/*****************************************************************
 DynamicTopicTree is a class to support dynamic rendering of
 topic trees, with drag-n-drop reparenting.
******************************************************************/

/**
   Flag indicating that the user might be dragging a node.
*/
var DttMayBeDragging = 0;
var DttObject        = 0;

/** Constructor
    @param hierDivId (String) : (required) container DIV for the topic tree
*/
DynamicTopicTree = function (viewPath, webName, hierDivId) {
    /** Save the dynamic topic tree object. This global is used by the
	topic mouseover/out handlers.
	@global
    */
    DttObject = this;
    
    /** CGI Path of topic view URL (i.e. %SCRIPTURL%/view%SCRIPTSUFFIX%)
	@privileged
    */
    this._dttViewPath = viewPath;
    this._dttWeb      = webName;

    /** Name of the DIV that will contain the topic tree.
	@privileged
    */
    this._hierDivId = hierDivId;
    
    /**
       Store for topic information (indexed by topic name).
       @example var ref = __request()._storage["hamlet"];
       @privileged
    */
    this._dttNodes = { };

    /**
       Tree node id counter.
       @privileged
    */
    this._dttNodeId = 10000;
   
    /**
       Add handlers to detect mouse down/up events. This helps us
       determine whether the user might be dragging an object.
    */
    document.onmousedown = function() { DttMayBeDragging = 1; DttObject._dttMouseOutTopic(); };
    document.onmouseup   = function() { DttMayBeDragging = 0; };

    /**
       Create the popup window that is used for displaying additional
       information about topics.
    */
    this._initializePopup ();
}

/* DynamicTopicTree class */
DynamicTopicTree.prototype = {
    /**
       Create a complete topic tree.
       @param hierArray   (Datastructure)  : (required) array containing all topic information
    */
    createTopicTree : function (hierArray) {
	/* create the WebHome node */
	this._createNode("WebHome", 1, 1, 0, 1);

	for (var i = 0; i < hierArray.length; i += 1) {
          if (!hierArray[i]) { continue; }

	    /* retrieve name/parent of i'th topic */
	    var c = hierArray[i].child;
	    var p = hierArray[i].parent;

	    /* "NO_PARENT is the default node for topics with undefined parents */
	    /* Also, for topics with themselves as parent! 
	       (yes, it can happen ... found out the hard way :-( */
	    if (!p || p == c) { p = "NO_PARENT"; this._createNode(p, 1, 1, 1, 0); }

	    /* if necessary, create parent and current topic nodes */
	    if (!this._dttNodes[p]) { this._createNode(p, 1); }
	    if (!this._dttNodes[c]) { this._createNode(c, 0); }

	    var pNode = this._dttNodes[p][0];
	    var pUl   = this._dttNodes[p][1];

	    /* The parent's UL can be missing, if 'p' was previously 
	       added to the tree as a child of another node */
	    if (!pUl) {
		pUl = document.createElement("ul");
		pNode.appendChild(pUl);
		this._dttNodes[p][1] = pUl;
	    }
	    var cNode = this._dttNodes[c][0];
	    /* add current topic's LI to parent's UL */
	    pUl.appendChild(cNode);

	    /* add the rest of the topic information as an
	       attribute to the topic node's A element */
	    /* FIXME: Don't understand why this kludge is required. */
	    hierArray[i].summary = hierArray[i].summary.replace(/&#060;nop&#062;/gi,"");
	    var aNode            = cNode.getElementsByTagName("a")[0];
	    aNode.info           = hierArray[i];

	    /* add mouseover and mouseout handlers */
	    aNode.onmouseover = this._dttMouseOverTopic;
	    aNode.onmouseout  = this._dttMouseOutTopic;

	    /* if parent is in another web, then add it as a child of
	       another special node: "OTHER_WEB" */
	    if (p.indexOf('.') != -1) {
		this._createNode("OTHER_WEB", 1, 1, 1, 0);
		ul = this._dttNodes["OTHER_WEB"][1];
		ul.appendChild(pNode);
		pNode.noDrag     = "true";
		pNode.noChildren = "true";
	    }
	    /* alert ('NODE: ' + c + ' PARENT: ' + p); */
	}

	/* finally, add the top level nodes of the tree to the specified DIV */
	var hierDiv = document.getElementById(this._hierDivId);
	hierDiv.appendChild(this._dttNodes["WebHome"][0]);
	if (this._dttNodes["NO_PARENT"]) {
	    hierDiv.appendChild(this._dttNodes["NO_PARENT"][0]);
	}
	if (this._dttNodes["OTHER_WEB"]) {
	    hierDiv.appendChild(this._dttNodes["OTHER_WEB"][0]);
	}
    } 
    ,
    /**
       Create a new topic tree node.
       @param topicName   (String)  : (required) topic name
       @param hasChildren (Boolean) : (optional) topic has children 
       @param noDrag      (Boolean) : (optional) tree node cannot be dragged
       @param noChildren  (Boolean) : (optional) tree node cannot have children
       @param noSiblings  (Boolean) : (optional) tree node cannot have siblings
       @privileged

       HTML generated: 
         - The attributes on the LI element are optional.
         - The inner UL is generated only if hasChildren is defined.

         <li id="node10001" noDrag="true" noChildren="true" noSiblings="true">
           <a href="VIEWPATH/WEB/TOPIC">TOPIC</a>
           <ul></ul>
         </li>
    */
    _createNode : function (topicName, hasChildren, noDrag, noChildren, noSiblings) {
	if (this._dttNodes[topicName])
	    return;

	this._dttNodeId ++;
	var n       = document.createElement("li");	/* LI element */
	n.id        = 'node' + this._dttNodeId;
	var a       = document.createElement("a");	/* A element */
	if (topicName.indexOf('.') == -1) {
	    a.href  = this._dttViewPath + "/" + this._dttWeb + "/" + topicName;
	}
	else {
	    a.href  = this._dttViewPath + "/" + topicName;
	} 
	a.innerHTML = topicName;
	n.appendChild(a);

	/* optional attributes for the LI element */
	if (noDrag)     { n.noDrag     = "true"; }
	if (noChildren) { n.noChildren = "true"; }
	if (noSiblings) { n.noSiblings = "true"; }

	/* add inner UL if required */
	if (hasChildren)   {
	    var ul = document.createElement("ul");
	    n.appendChild(ul);
	    this._dttNodes[topicName] = [ n, ul ];
	}
	else {
	    this._dttNodes[topicName] = [ n ];
	}
    }
    ,
    /**
       Event handler for when a mouse is over a topic node.
       NOTE: 'this' refers to the ELEMENT that triggered the action.
       @param e (Event) : (required) event information
       @privileged
    */
    _dttMouseOverTopic : function (e) {
	var event = e || window.event;
	var obj   = this;

	if (this.info.rev) { /* check for additional topic information */
	    /* Add 12 pixels to the current mouse location in both
	     * directions. This ensures that the popup does not cover
	     * the mouse which leads to flickering.
	     * Handle Mozilla / IE differences */
	    if (event.pageX || event.pageY) {
		popX = event.pageX + 12;
		popY = event.pageY + 12;
	    }
	    else if (event.clientX || event.clientY)    {
		popX = event.clientX + document.body.scrollLeft +
		    document.documentElement.scrollLeft         +
		    12;
		popY = event.clientY + document.body.scrollTop  +
		    document.documentElement.scrollTop          +
		    12;
	    }
	    /* Add an additional offset for topics that we pass over
	     * while dragging another topic. */
	    if (DttMayBeDragging) popY += 15;

	    /* Show the popup only if the user hovers over a topic for a while.
	     * Increase the delay, if the a topic is being dragged. */
	    obj.mouseOver = 1;
	    var delay     = (DttMayBeDragging) ? 2000 : 1000;
	    window.setTimeout (
		function() { if (obj.mouseOver == 1) DttObject._showTopicInfo(obj,popX,popY); },
		delay );
	}
	return true;
    }
    ,
    /**
       Event handler for when a mouse moves out of a topic node.
       NOTE: 'this' refers to the ELEMENT that triggered the action.
       @param e (Event) : (required) event information
       @privileged
    */
    _dttMouseOutTopic : function (e) {
	this.mouseOver = 0;
	var popup = document.getElementById('DttTopicInfoPopup');
	popup.style.display = 'none';
	return true;
    }
    ,
    /**
       Create the topic info popup window.
    */
    _initializePopup : function () {
	var popup   = document.createElement("div");
	popup.id    = 'DttTopicInfoPopup';
	//var parent  = document.body;
      var parent  = document.getElementById(this._hierDivId);
	parent.appendChild(popup);
    }
    ,
    /**
       Display the popup that contains additional information about a topic.
       @param obj (Object)   : (required) should have a member called
                                          'info' that defines various attributes
       @param X   (Position) : (required) X position
       @param Y   (Position) : (required) Y position
       @privileged
    */
    _showTopicInfo : function (obj, X, Y) {
	var popup = document.getElementById('DttTopicInfoPopup');
	/* Format the information to show in the topic info popup */
	popup.innerHTML = 
          '<div class=\"topicName\">' + obj.info.child + '</div>'             +
          '<div class=\"topicSummary\">'                                      + 
            '<span class=\"topicField\">Summary</span>'                       +
            obj.info.summary                                                  + 
          '</div>'                                                            +
          '<div class=\"topicInfo\">'                                         + 
            '<span class=\"topicField\">Revision</span>'                      + 
            obj.info.rev                                                      +
          '</div>'                                                            + 
          '<div class=\"topicInfo left\">'                                    +
            '<span class=\"topicField\">Changed</span>'                       +
            '<br/>' + obj.info.date + '<br/>' + obj.info.wikiname             +
          '</div>'                                                            + 
          '<div class=\"topicInfo right\">'                                   +
            '<span class=\"topicField\">Created</span>'                       +
            '<br/>' + obj.info.createdate + '<br/>' + obj.info.createwikiname +
          '</div>'                                                            +
          '<br clear=\"both\"/>';

	popup.style.left    = X + 'px';
	popup.style.top     = Y + 'px';
	popup.style.display = 'block';
	return true;
    }
} 

/* =================================================== */


