
if(document.getElementById && document.createTextNode){

    var COLLAPSIBLE_LIST_LOADED = true;

    /**ListManager
     *
     * Class which controls the functions of the collapsible lists
     * strScope - String id of parent element, all child lists of which wil be collapsed
     */
    function ListManager(strScope){

        if (typeof ListManager._init === "undefined"){

            ListManager.LISTS = new Array();

            /**_construct
             * creates the ListManager object
             * strScope String the scope. see above.
             */
            ListManager.prototype._construct = function(strScope){
                //alert("_construct");

                if(!strScope){
                    this._rootNode = document.body;
                }else{
                    this._rootNode = document.getElementById(strScope);
                }

                this._findLists(this._rootNode);

                //this._addControls();
            };

            /**_findLists
             * Finds all lists in the given scope, and creates a colapsible list objects for it. #
             * calls toggle to hide the list
             *
             * objRoot - parent node from which to start the search (optional - document scope if ommited)
             */
            ListManager.prototype._findLists = function(objRoot){
                //alert("begin call no: " + ++this._called + " on " + objRoot.id);
                //alert("find lists " + objRoot + " " + (objRoot == this._rootNode));

                var nodes = objRoot.childNodes;

                for(var i = nodes.length-1; i>=0; i--){

                    var currentNode = nodes[i];

                   if (currentNode.tagName == "UL" || currentNode.tagName == "OL"){

                       //alert("found list on call " + this._called);
                       var newList = new CollapsibleList(currentNode);
                       //this shouldn't be nescesary see comment at end of collasible list class
                       var id = newList._id;

                       ListManager.TOGGLE(id);

                       this._findLists(currentNode);

                       //Array push() in longhand for the benefit of ie 5.
                       var x = ListManager.LISTS.length;
                       ListManager.LISTS.length + 1;
                       
                       ListManager.LISTS[x] = currentNode;

                   }else if (currentNode.nodeType == 1){

                       this._findLists(currentNode); 
                   }
                }
            };

            /**TOGGLE
             * Controls the display state of collapsible states. Receives the id of the list.
             * Retrieves the class from the list and uses this to determine state. sets classname to reflect changes 
             * 
             * intId int Id of the list to be affected
             * return - new state of the list 0= closed 1=open
             */
            ListManager.TOGGLE = function(intId){

                var intReturn;

                var list = document.getElementById(intId);

                if(list.className == ""){
                    //alert("noClass");
                    list.className = "open";
                }else{
                    //alert("id passed to listManager.TOGGLE: " + intId);
                }

                //alert(list.className);

                if(list.className == "open"){
                    intReturn = this._HIDE(list);
                    list.className = "closed";
                    //alert("intReturn value set closed: " + intReturn);
                }else{
                    intReturn = this._SHOW(list);
                    list.className = "open";
                    //alert("intReturn value set open: " + intReturn);
                }

                //alert("return value to be sen from ListManager.TOGGLE: " + intReturn);
                return intReturn;

            };

            /**_HIDE
             * Hides all elements in the given list, 
             *
             * objList Object - the list to be affected
             * returns int - 0
             */
            ListManager._HIDE = function(objList){

                var children = objList.childNodes;

                for(var i = children.length -1; i >= 0 ; i--){

                    if(children[i].nodeType == 1){
                        DomUtilities.setStyle(children[i], "display", "none");
                    }
                }
                return 0;
            };

            /**_SHOW
             * Shows all elements in the given list
             *
             * objList Object - the list to be affected
             * returns int - 1
             */
            ListManager._SHOW = function(objList){

                var children = objList.childNodes;

                for(var i = children.length - 1; i >= 0 ; i--){
                    if(children[i].nodeType == 1){
                        DomUtilities.setStyle(children[i], "display", "block");
                    }
                }
                return 1;
            };

            /**SHOW_ALL
             * Expands all collapsible lists in the manager
             * 
             */
            ListManager.SHOW_ALL = function(){

                for(var i = ListManager.LISTS.length-1; i>=0; i--){

                    //show list contents
                    var currentNode = ListManager.LISTS[i];
                    ListManager._SHOW(currentNode);

                    //toggle widgets
                    var id = currentNode.getAttribute('id');
                    var widget = document.getElementById(id + "Widget");
                    ControlWidget.TOGGLE(widget, 1);

                }
            }

            /**HIDE_ALL
             * collapses all collapsible lists in the manager
             * 
             */
            ListManager.HIDE_ALL = function(){

                for(var i = ListManager.LISTS.length-1; i>=0; i--){

                    //show list contents
                    var currentNode = ListManager.LISTS[i];
                    ListManager._HIDE(currentNode);

                    //toggle widgets
                    var id = currentNode.getAttribute('id');
                    var widget = document.getElementById(id + "Widget");
                    ControlWidget.TOGGLE(widget, 0);
                }
            }

            /**addControls
             * Adds the show all and hide all controls to the top of the master list
             */
            ListManager.prototype._addControls = function(){

                var controls = document.createElement('div');
                controls.setAttribute('id', 'listControls');

                var showButton = document.createElement('a');
                showButton.setAttribute('class', 'controlButton');
                showButton.setAttribute('href', '#');
                showButton.onclick = function(){
                    ListManager.SHOW_ALL();
                }

                var hideButton = document.createElement('a');
                hideButton.setAttribute('class', 'controlButton');
                hideButton.setAttribute('href', '#');
                hideButton.onclick = function(){
                    ListManager.HIDE_ALL();
                }

                var showText = document.createTextNode("Expand all");

                var hideText = document.createTextNode("Collapse all");

                showButton.appendChild(showText);
                hideButton.appendChild(hideText);

                controls.appendChild(showButton);
                controls.appendChild(hideButton);

                var firstList = this._rootNode.firstChild;

                while(firstList.nodeType != 1){
                    firstList = firstList.nextSibling;
                }

                this._rootNode.insertBefore(controls, firstList);

            }

            ListManager._init = true;   
        }

        this._construct(strScope);
    }

    /**CollapsibleList
     * Creates a collapsible list objects and assigns classes and ids to relevant document nodes
     * so that the ListManager can control the lists
     *
     * objNode Object - Node the list rlates to
     * returns - id of the created list
     */
    function CollapsibleList(objNode){

        this._id;
        this._titleNode;

        if(typeof CollapsibleList._init === "undefined"){

            CollapsibleList._COUNTER = 0;

            /**_construct
             * Creates the collapsibleList object. calls setId method. calls findTitle method
             * Sets the rootNode property to point to the document node of the list
             *
             * objNode Object - Node the list relates to
             */
            CollapsibleList.prototype._construct = function(objNode){
                objNode.setAttribute('id', this._generateId());
                this._findTitle(objNode);
                this._addWidget();
            };

            /**_generateId
             * sets the id of the list to the current counter then incements the counter. sets _id property;
             * returns id
             */
            CollapsibleList.prototype._generateId = function(){
                this._id = CollapsibleList._COUNTER++;
                return this._id;
            };

            /**_findTitle
             * Locates the nearest preceding html element to the list and stores a reference to this node
             * in the _titleNode property
             *
             * objNode Object - Node the list rlates to
             */
            CollapsibleList.prototype._findTitle = function(objNode){

                var node = objNode;

                do{
                    node = node.previousSibling;
                    //alert("node: " + node + " " + node.nodeType);
                    }
                while(node.nodeType != 1);

                this._titleNode = node;


            };

            /**_addWidget
             * creates a new widget object and assigns it a class corresponding to the list id. 
             * Inserts it as a docuent node adjacent to the tile node. 
             */
            CollapsibleList.prototype._addWidget = function(){
                //alert("calling new widget for list no " + this._id);
                var widget = new ControlWidget(this._id);

                //alert(widget);

                this._titleNode.parentNode.insertBefore(widget, this._titleNode);

            };

            CollapsibleList._init = true;
        }

        this._construct(objNode);
        //alert(this._id);

        //this seems to return the whole object not the id, not sure why
        return this._id;
    }

    /**ControlWidget
     * Creates acontrol widget to collapse/expand colapsible lists. Assigns the correct class and 
     * stores references to the correct images for each state
     *
     * intId int - the id of the list which the widget will control
     */
    function ControlWidget(intId){

        if(typeof ControlWidget._init === "undefined"){

            ControlWidget._OPEN_IMAGE = "images/minus.gif";
            ControlWidget._CLOSED_IMAGE = "images/plus.gif";

            /**_construct
             *Creates the node, assigns class, sets default state, assigns onClick handler
             *
             * intId int - the id of the list which the widget will control
             * //returns objNode - the created node ready for document insertion
             */
            ControlWidget.prototype._construct = function(intId){
                //alert("widget created for list no " + intId);
                var imgNode = document.createElement('img');
                imgNode.setAttribute('src', ControlWidget._CLOSED_IMAGE);
                imgNode.setAttribute('title', "Click to expand");
                imgNode.setAttribute('alt', "Plus symbol");

                var aNode = document.createElement('a');
                aNode.setAttribute('class', intId);
                aNode.setAttribute('id', intId + "Widget");
                aNode.setAttribute('href', '#' + intId);

                aNode.onclick = function(){

                    var intClass = this.getAttribute('class');

                    ControlWidget.TOGGLE(this, ListManager.TOGGLE(intClass));
                };

                aNode.appendChild(imgNode);
                //alert(node);
                return aNode;
            };

            /**TOGGLE
             * Changes the image state of the widget 
             *
             * objNode Object - widget node
             * intMode int - state to change to 0 = closed, 1= open
             */
            ControlWidget.TOGGLE = function(objNode, intMode){
                if(intMode){
                    objNode.firstChild.setAttribute('src', ControlWidget._OPEN_IMAGE);
                    objNode.firstChild.setAttribute('title', "Click to collapse");
                    objNode.firstChild.setAttribute('alt', "minus symbol");
                }else{
                    objNode.firstChild.setAttribute('src', ControlWidget._CLOSED_IMAGE);
                    objNode.firstChild.setAttribute('title', "Click to expand");
                    objNode.firstChild.setAttribute('alt', "plus symbol");
                }
            };

             ControlWidget._init = true;
        }

        this._node = this._construct(intId);
        //alert(this._node);
        return(this._node);
    }
}


