
/*
    Creates a tree
    portletid: the portlet id
    componentname: the name of the global attribute that contains the component
    containerelementId: the html id of the element that will contain the tree
    javascriptVarName: the name of the javacript var that this instance has (used for generated even callbacks)
    removeCall:(optional string) function name for a remove function in the page (used for legacy), if not present it uses the internal remove mechanism,
                                if value is 'noremove' remove link is not rendered

  javascript events:
  - selection changed: throws an object event.name='selectionChanged' event.nodeid='new node selected'
  


  the produced tree has this style info:
  .expand .collapse .leaf class for a element containing expand-collapse button

  .selected class for an li node selected
  .label class for a element containing node label
  .remove class for a elemnt containing the remove button
  .lastsibling  class for last sibling of a set of siblings

  .expand .collapse .leaf alternative classes for a li node
  
  locale key used:

  tree_expand,tree_collapse,tree_remove
  
*/
function PE_Tree(portletid,attributename,containerElementId,javascriptVarName,removeCall) {
    this.portletid=portletid;
    this.attributename=attributename;
    this.containerElementId=containerElementId;
    this.containerElement=$(containerElementId);
    this.globalVarName=javascriptVarName;
    this.selectedID='';
    if (!this.containerElement)
        alert("Container element for tree:"+attributename+" not present");

    if (removeCall)
        this.removeCall=removeCall;
    
/*
  public: the selected node id
 */
this.selectedNodeId='';

/*
    resets the tree reloading all the nodes
*/
this.reset= function() {
   
   var obj=this;
   var params=new Object();
   params.cascade='true';
   PEAjaxUtils.scheduleSessionRefresh();
   RemoteProxy.call(this.portletid,this.attributename,'refresh',params,
                        {callback:function(data) 
                                    {obj._drawTree(data);
                                     
                                    }
                        }
                    );
}

/*
  refreshes the tree reloading one node and all his descendants, the passed node can be empty (for root)
*/
this.refresh= function(nodeid) {
   var obj=this;
   var params=new Object();
   if (nodeid) params.nodeid=nodeid;
   params.cascade='true';
   PEAjaxUtils.scheduleSessionRefresh();
   RemoteProxy.call(this.portletid,this.attributename,'refresh',params,
                        {callback:function(data) 
                                    { 
                                            obj._drawTree(data);
                                    }   
                        }
                    );
}

/*
Selects a node in the tree
*/
this.select= function(nodeid) {
   var obj=this;
   var params=new Object();
   params.nodeid=nodeid;
   PEAjaxUtils.scheduleSessionRefresh();
   RemoteProxy.call(this.portletid,this.attributename,'select',params,
                        {callback:function(data) 
                                    { 
                                        //gets the selected node and changes it
                                        obj._switchSelection(nodeid);
                                        
                                    }   
                        }
                    );
}



/*
expands a node in the tree
*/
this.expand= function(nodeid) {
   var obj=this;
   var params=new Object();
   params.nodeid=nodeid;
   PEAjaxUtils.scheduleSessionRefresh();
   RemoteProxy.call(this.portletid,this.attributename,'expand',params,
                        {callback:function(data) 
                                    { 
                                        
                                        //gets the selected node and changes it
                                        obj._drawTree(data);
                                        
                                    }   
                        }
                    );
}

/*
collapses a node in the tree
*/
this.collapse= function(nodeid) {
   var obj=this;
   var params=new Object();
   params.nodeid=nodeid;
   PEAjaxUtils.scheduleSessionRefresh();
   RemoteProxy.call(this.portletid,this.attributename,'collapse',params,
                        {callback:function(data) 
                                    { 
                                        obj._drawTree(data);
                                    }   
                        }
                    );
}


/*
removes a node in the tree
*/
this.remove= function(nodeid,message) {
    
    if (message) {
        var agree=confirm(message);
        if (!agree) {
            return;
        }
   }
    
   var obj=this;
   var params=new Object();
   params.nodeid=nodeid;
   PEAjaxUtils.scheduleSessionRefresh();
   RemoteProxy.call(this.portletid,this.attributename,'remove',params,
                        {callback:function(data) 
                                    { 
                                        obj._drawTree(data);  
                                    }   
                        }
                    );
}


/*
----------------
Private functions
*/

/*
finds a node given id
*/
this._findNode=function(id) {
    
    var allnodes=this.containerElement.descendants();
    for (var idx=0;idx<allnodes.length;idx++) {
        
        if (allnodes[idx].getAttribute)
            if (allnodes[idx].getAttribute("prv_id")==id) {
                
                return allnodes[idx];
            }
    }
}

/*
removes all li children from a li node
*/
this._removeChildren=function(li) {
    
    
    var allnodes=li.immediateDescendants();
    
    for (var idx=0;idx<allnodes.length;idx++) {
        
        if (allnodes[idx].tagName=='UL')
                li.removeChild(allnodes[idx]);
                
            
    }
}

/*
private function
*/
this._drawTree= function(data) {

    var node=data.node;

    var substitutenode=this._findNode(node.ID);
    
    var parentNode;
    var sibling;
    
    var wasselected=false;
    
    if (substitutenode) {
        wasselected=substitutenode.hasClassName("selected");
        parentNode=substitutenode.parentNode;
        
        sibling=substitutenode.next('li');
        
        parentNode.removeChild(substitutenode);
        
    } else {
        
        //removes all content
        this.containerElement.update();
        parentNode=$(document.createElement("ul"));
        this.containerElement.appendChild(parentNode);
    }

    
    if (sibling)
        this._drawSubTree(parentNode,node,false,wasselected,sibling);
    else
        this._drawSubTree(parentNode,node,true,wasselected);

    this._switchSelection(data.selectedid);
}

this._drawSubTree=function(ulnode,treenode,islast,wasselected,sibling) {
  
    
    //creates the item
    var li=$(document.createElement("li"));
    li.setAttribute("prv_id",treenode.ID);
    if (islast==true)
        li.addClassName("lastsibling");

    if (wasselected)
        li.addClassName("selected");
    
    

    if (sibling) 
        ulnode.insertBefore(li,sibling);
    else
        ulnode.appendChild(li);

    //adds text and elements
    var collapser=$(document.createElement("a"));
    //alert(treenode.ID+" leaf"+treenode.leaf);
    if (treenode.expanded==true && treenode.leaf==false) {
        li.addClassName("collapse");
        collapser.addClassName("collapse");
        collapser.href="javascript:"+this.globalVarName+".collapse('"+treenode.ID+"')";
    } else if (treenode.expanded==false && treenode.leaf==false) {
        li.addClassName("expand");
        collapser.addClassName("expand");
        collapser.href="javascript:"+this.globalVarName+".expand('"+treenode.ID+"')";
    } else {
        li.addClassName("leaf");
        collapser.addClassName("leaf");
    }
    //expand icon
    collapser.update("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
    li.appendChild(collapser);
    
    var label=$(document.createElement("a"));
    label.href="javascript:"+this.globalVarName+".select('"+treenode.ID+"')";
    label.addClassName("label");
    label.update(treenode.value);
    li.appendChild(label);
    
    if (treenode.removeable==true) {
        var remover=$(document.createElement("a"));
        
        if (this.removeCall) {
            remover.href="javascript:"+this.removeCall+'("'+treenode.ID+'")';
        } else {
            if (treenode.message)
                remover.href="javascript:"+this.globalVarName+'.remove("'+treenode.ID+'","'+treenode.message+'")';
            else
                remover.href="javascript:"+this.globalVarName+'.remove("'+treenode.ID+'")';
        }
        remover.addClassName("remove");
        // remove icon
        remover.update("&nbsp;&nbsp;&nbsp;&nbsp;");
        
        if (this.removeCall && this.removeCall!='noremove')
            li.appendChild(remover);
    }
    

    var ul=$(document.createElement("ul"));
    li.appendChild(ul);
    
    //adds all children to the ul
    var children=treenode.children;
    
    for (var i=0;i<children.length;i++)
        this._drawSubTree(ul,children[i],i==(children.length-1),false);
    
   
}


/*
 private function
*/
this._switchSelection= function(id) {
  
    this.selectedNodeId=id;
    var allnodes=this.containerElement.descendants();
    for (var idx=0;idx<allnodes.length;idx++) {
        
        if (allnodes[idx].getAttribute)
            if (allnodes[idx].getAttribute("prv_id")==id){

                
                var wasselected=(allnodes[idx].hasClassName('selected'));
                
                if (!wasselected) {
                    allnodes[idx].addClassName("selected");
                    var eventObject=new Object();
                    eventObject.name='selectionChanged';
                    eventObject.nodeid=id;
                    PEEventManager.fireEvent(this.portletid,this.attributename,eventObject);
                }
                
            } else {
                
                if (allnodes[idx].hasClassName('selected'))
                    allnodes[idx].removeClassName("selected");
            }

    }

}





    if (!PEAjaxUtils.windowLoaded) {
        Event.observe(window, 'load', function() {
          this.reset();
        }.bind(this));
    } else
        this.reset();
    
                                                         
}