/*
 * Content-seperated javascript tree widget
 * Copyright (C) 2005 SilverStripe Limited
 * Feel free to use this on your websites, but please leave this message in the fies
 * http://www.silverstripe.com/blog
*/

/*
 * Initialise all trees identified by <ul class="tree">
 */
function autoInit_trees() {
    var candidates = document.getElementsByTagName('ul');
    for(var i=0;i<candidates.length;i++) {
        if(candidates[i].className && candidates[i].className.indexOf('tree') != -1) {
            initTree(candidates[i]);
            candidates[i].className = candidates[i].className.replace(/ ?unformatted ?/, ' ');
        }
    }
}

/*
 * Initialise a tree node, converting all its LIs appropriately
 */
function initTree(el) {
    var i,j;
    var spanA, spanB, spanC;
    var startingPoint, stoppingPoint, childUL;

    // Find all LIs to process
    for(i=0;i<el.childNodes.length;i++) {
        if(el.childNodes[i].tagName && el.childNodes[i].tagName.toLowerCase() == 'li') {
            var li = el.childNodes[i];

            // Create our extra spans
            spanA = document.createElement('span');
            spanB = document.createElement('span');
            spanC = document.createElement('span');
            spanA.appendChild(spanB);
            spanB.appendChild(spanC);
            spanA.className = 'a ' + li.className.replace('closed','spanClosed');
            spanA.onMouseOver = function() {}
            spanB.className = 'b';
            spanB.onclick = treeToggle;
            spanC.className = 'c';


            // Find the UL within the LI, if it exists
            stoppingPoint = li.childNodes.length;
            startingPoint = 0;
            childUL = null;
            for(j=0;j<li.childNodes.length;j++) {
                if(li.childNodes[j].tagName && li.childNodes[j].tagName.toLowerCase() == 'div') {
                    startingPoint = j + 1;
                    continue;
                }

                if(li.childNodes[j].tagName && li.childNodes[j].tagName.toLowerCase() == 'ul') {
                    childUL = li.childNodes[j];
                    stoppingPoint = j;
                    break;
                }
            }

            // Move all the nodes up until that point into spanC
            for(j=startingPoint;j<stoppingPoint;j++) {
                spanC.appendChild(li.childNodes[startingPoint]);
            }

            // Insert the outermost extra span into the tree
            if(li.childNodes.length > startingPoint) li.insertBefore(spanA, li.childNodes[startingPoint]);
            else li.appendChild(spanA);

            // Process the children
            if(childUL != null) {
                if(initTree(childUL)) {
                    addClass(li, 'children', 'closed');
                    addClass(spanA, 'children', 'spanClosed');
                }
            }
        }
    }

    if(li) {
        // li and spanA will still be set to the last item

        addClass(li, 'last', 'closed');
        addClass(spanA, 'last', 'spanClosed');
        return true;
    } else {
        return false;
    }

}


/*
 * +/- toggle the tree, where el is the <span class="b"> node
 * force, will force it to "open" or "close"
 */
function treeToggle(el, force) {
    el = this;

    while(el != null && (!el.tagName || el.tagName.toLowerCase() != "li")) el = el.parentNode;

    // Get UL within the LI
    var childSet = findChildWithTag(el, 'ul');
    var topSpan = findChildWithTag(el, 'span');

    if( force != null ){

        if( force == "open"){
            treeOpen( topSpan, el )
        }
        else if( force == "close" ){
            treeClose( topSpan, el )
        }

    }

    else if( childSet != null) {
        // Is open, close it
        if(!el.className.match(/(^| )closed($| )/)) {
            treeClose( topSpan, el )
        // Is closed, open it
        } else {
            treeOpen( topSpan, el )
        }
    }
}


function treeOpen( a, b ){
    removeClass(a,'spanClosed');
    removeClass(b,'closed');
    //alert("tree open" + a + " :: " + b);
}


function treeClose( a, b ){
    addClass(a,'spanClosed');
    addClass(b,'closed');
    //alert("tree closed" + a + " :: " + b);
}

/*
 * Find the a child of el of type tag
 */
function findChildWithTag(el, tag) {
    for(var i=0;i<el.childNodes.length;i++) {
        if(el.childNodes[i].tagName != null && el.childNodes[i].tagName.toLowerCase() == tag) return el.childNodes[i];
    }
    return null;
}

/*
 * Functions to add and remove class names
 * Mac IE hates unnecessary spaces
 */
function addClass(el, cls, forceBefore) {
    if(forceBefore != null && el.className.match(new RegExp('(^| )' + forceBefore))) {
        el.className = el.className.replace(new RegExp("( |^)" + forceBefore), '$1' + cls + ' ' + forceBefore);

    } else if(!el.className.match(new RegExp('(^| )' + cls + '($| )'))) {
        el.className += ' ' + cls;
        el.className = el.className.replace(/(^ +)|( +$)/g, '');
    }
}
function removeClass(el, cls) {
    var old = el.className;
    var newCls = ' ' + el.className + ' ';
    newCls = newCls.replace(new RegExp(' (' + cls + ' +)+','g'), ' ');
    el.className = newCls.replace(/(^ +)|( +$)/g, '');
}

/*
 * Handlers for automated loading
 */
 /*_LOADERS = Array();

function callAllLoaders() {
    var i, loaderFunc;
    for(i=0;i<_LOADERS.length;i++) {
        loaderFunc = _LOADERS[i];
        if(loaderFunc != callAllLoaders) loaderFunc();
    }
}

function appendLoader(loaderFunc) {
    if(window.onload && window.onload != callAllLoaders)
        _LOADERS[_LOADERS.length] = window.onload;

    window.onload = callAllLoaders;

    _LOADERS[_LOADERS.length] = loaderFunc;
}

appendLoader(autoInit_trees);
*/
