/*                                                                                                                                                      
Copyright (c) 2006, Yahoo! Inc. All rights reserved.                                                                                                    
Code licensed under the BSD License:                                                                                                                    
http://developer.yahoo.net/yui/license.txt                                                                                                              
version: 0.10.0                                                                                                                                         
*/ 

/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
/*EVENT.JS*/
/*                                                                                                                                                      
Copyright (c) 2006, Yahoo! Inc. All rights reserved.                                                                                                    
Code licensed under the BSD License:                                                                                                                    
http://developer.yahoo.net/yui/license.txt                                                                                                              
version: 0.10.0                                                                                                                                         
*/ 

/**
 * The CustomEvent class lets you define events for your application
 * that can be subscribed to by one or more independent component.
 *
 * @param {String} type The type of event, which is passed to the callback
 *                 when the event fires
 * @param {Object} oScope The context the event will fire from.  "this" will
 *                 refer to this object in the callback.  Default value: 
 *                 the window object.  The listener can override this.
 * @constructor
 */
YAHOO.util.CustomEvent = function(type, oScope) {
    /**
     * The type of event, returned to subscribers when the event fires
     * @type string
     */
    this.type = type;

    /**
     * The scope the the event will fire from by default.  Defaults to the window 
     * obj
     * @type object
     */
    this.scope = oScope || window;

    /**
     * The subscribers to this event
     * @type Subscriber[]
     */
    this.subscribers = [];

    // Register with the event utility for automatic cleanup.  Made optional
    // so that CustomEvent can be used independently of pe.event
    if (YAHOO.util.Event) { 
        YAHOO.util.Event.regCE(this);
    }
};

YAHOO.util.CustomEvent.prototype = {
    /**
     * Subscribes the caller to this event
     * @param {Function} fn       The function to execute
     * @param {Object}   obj      An object to be passed along when the event fires
     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
     *                            scope of the listener
     */
    subscribe: function(fn, obj, bOverride) {
        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
    },

    /**
     * Unsubscribes the caller from this event
     * @param {Function} fn  The function to execute
     * @param {Object}   obj An object to be passed along when the event fires
     * @return {boolean} True if the subscriber was found and detached.
     */
    unsubscribe: function(fn, obj) {
        var found = false;
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
            var s = this.subscribers[i];
            if (s && s.contains(fn, obj)) {
                this._delete(i);
                found = true;
            }
        }

        return found;
    },

    /**
     * Notifies the subscribers.  The callback functions will be executed
     * from the scope specified when the event was created, and with the following
     * parameters:
     *   <pre>
     *   - The type of event
     *   - All of the arguments fire() was executed with as an array
     *   - The custom object (if any) that was passed into the subscribe() method
     *   </pre>
     *   
     * @param {Array} an arbitrary set of parameters to pass to the handler
     */
    fire: function() {
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
            var s = this.subscribers[i];
            if (s) {
                var scope = (s.override) ? s.obj : this.scope;
                s.fn.call(scope, this.type, arguments, s.obj);
            }
        }
    },

    /**
     * Removes all listeners
     */
    unsubscribeAll: function() {
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
            this._delete(i);
        }
    },

    /**
     * @private
     */
    _delete: function(index) {
        var s = this.subscribers[index];
        if (s) {
            delete s.fn;
            delete s.obj;
        }

        delete this.subscribers[index];
    }
};

/////////////////////////////////////////////////////////////////////

/**
 * @class Stores the subscriber information to be used when the event fires.
 * @param {Function} fn       The function to execute
 * @param {Object}   obj      An object to be passed along when the event fires
 * @param {boolean}  bOverride If true, the obj passed in becomes the execution
 *                            scope of the listener
 * @constructor
 */
YAHOO.util.Subscriber = function(fn, obj, bOverride) {
    /**
     * The callback that will be execute when the event fires
     * @type function
     */
    this.fn = fn;

    /**
     * An optional custom object that will passed to the callback when
     * the event fires
     * @type object
     */
    this.obj = obj || null;

    /**
     * The default execution scope for the event listener is defined when the
     * event is created (usually the object which contains the event).
     * By setting override to true, the execution scope becomes the custom
     * object passed in by the subscriber
     * @type boolean
     */
    this.override = (bOverride);
};

/**
 * Returns true if the fn and obj match this objects properties.
 * Used by the unsubscribe method to match the right subscriber.
 *
 * @param {Function} fn the function to execute
 * @param {Object} obj an object to be passed along when the event fires
 * @return {boolean} true if the supplied arguments match this 
 *                   subscriber's signature.
 */
YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
    return (this.fn == fn && this.obj == obj);
};

/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */

// Only load this library once.  If it is loaded a second time, existing
// events cannot be detached.
if (!YAHOO.util.Event) {

    YAHOO.util.Event = function() {

        var loadComplete =  false;

        var listeners = [];

        var delayedListeners = [];

        var unloadListeners = [];

        var customEvents = [];

        var legacyEvents = [];

        var legacyHandlers = [];

        var retryCount = 0;

        /**
         * onAvailable listeners
         * @private
         */
        var onAvailStack = [];

        /**
         * Lookup table for legacy events
         * @private
         */
        var legacyMap = [];

        /**
         * Counter for auto id generation
         * @private
         */
        var counter = 0;

        return { // PREPROCESS

            POLL_RETRYS: 200,

            /**
             * The poll interval in milliseconds
             * @type int
             */
            POLL_INTERVAL: 50,

            /**
             * Element to bind, int constant
             * @type int
             */
            EL: 0,

            /**
             * Type of event, int constant
             * @type int
             */
            TYPE: 1,

            /**
             * Function to execute, int constant
             * @type int
             */
            FN: 2,

            WFN: 3,

            SCOPE: 3,

            ADJ_SCOPE: 4,

            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),

            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) && 
                    navigator.userAgent.match(/msie/gi)),

            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
                delayedListeners[delayedListeners.length] =
                    [el, sType, fn, oScope, bOverride];

                if (loadComplete) {
                    retryCount = this.POLL_RETRYS;
                    this.startTimeout(0);
                    // this._tryPreloadAttach();
                }
            },

            /**
             * @private
             */
            startTimeout: function(interval) {
                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
                var self = this;
                var callback = function() { self._tryPreloadAttach(); };
                this.timeout = setTimeout(callback, i);
            },

            onAvailable: function(p_id, p_fn, p_obj, p_override) {
                onAvailStack.push( { id:       p_id, 
                                     fn:       p_fn, 
                                     obj:      p_obj, 
                                     override: p_override } );

                retryCount = this.POLL_RETRYS;
                this.startTimeout(0);
                // this._tryPreloadAttach();
            },
            addListener: function(el, sType, fn, oScope, bOverride) {

                if (!fn || !fn.call) {
                    return false;
                }

                // The el argument can be an array of elements or element ids.
                if ( this._isValidCollection(el)) {
                    var ok = true;
                    for (var i=0,len=el.length; i<len; ++i) {
                        ok = ( this.on(el[i], 
                                       sType, 
                                       fn, 
                                       oScope, 
                                       bOverride) && ok );
                    }
                    return ok;

                } else if (typeof el == "string") {
                    var oEl = this.getEl(el);
                    if (loadComplete && oEl) {
                        el = oEl;
                    } else {
                        // defer adding the event until onload fires
                        this.addDelayedListener(el, 
                                                sType, 
                                                fn, 
                                                oScope, 
                                                bOverride);

                        return true;
                    }
                }

                // Element should be an html element or an array if we get 
                // here.
                if (!el) {
                    return false;
                }

                if ("unload" == sType && oScope !== this) {
                    unloadListeners[unloadListeners.length] =
                            [el, sType, fn, oScope, bOverride];
                    return true;
                }


                var scope = (bOverride) ? oScope : el;
                var wrappedFn = function(e) {
                        return fn.call(scope, YAHOO.util.Event.getEvent(e), 
                                oScope);
                    };

                var li = [el, sType, fn, wrappedFn, scope];
                var index = listeners.length;
                // cache the listener so we can try to automatically unload
                listeners[index] = li;

                if (this.useLegacyEvent(el, sType)) {
                    var legacyIndex = this.getLegacyIndex(el, sType);
                    if (legacyIndex == -1) {

                        legacyIndex = legacyEvents.length;
                        legacyMap[el.id + sType] = legacyIndex;

                        // cache the signature for the DOM0 event, and 
                        // include the existing handler for the event, if any
                        legacyEvents[legacyIndex] = 
                            [el, sType, el["on" + sType]];
                        legacyHandlers[legacyIndex] = [];

                        el["on" + sType] = 
                            function(e) {
                                YAHOO.util.Event.fireLegacyEvent(
                                    YAHOO.util.Event.getEvent(e), legacyIndex);
                            };
                    }

                    // add a reference to the wrapped listener to our custom
                    // stack of events
                    legacyHandlers[legacyIndex].push(index);

                // DOM2 Event model
                } else if (el.addEventListener) {
                    el.addEventListener(sType, wrappedFn, false);
                // Internet Explorer abstraction
                } else if (el.attachEvent) {
                    el.attachEvent("on" + sType, wrappedFn);
                }

                return true;
                
            },

            fireLegacyEvent: function(e, legacyIndex) {
                var ok = true;

                var le = legacyHandlers[legacyIndex];
                for (var i=0,len=le.length; i<len; ++i) {
                    var index = le[i];
                    if (index) {
                        var li = listeners[index];
                        if ( li && li[this.WFN] ) {
                            var scope = li[this.ADJ_SCOPE];
                            var ret = li[this.WFN].call(scope, e);
                            ok = (ok && ret);
                        } else {
                            delete le[i];
                        }
                    }
                }

                return ok;
            },
            getLegacyIndex: function(el, sType) {

                var key = this.generateId(el) + sType;
                if (typeof legacyMap[key] == "undefined") { 
                    return -1;
                } else {
                    return legacyMap[key];
                }

            },

            useLegacyEvent: function(el, sType) {

                if (!el.addEventListener && !el.attachEvent) {
                    return true;
                } else if (this.isSafari) {
                    if ("click" == sType || "dblclick" == sType) {
                        return true;
                    }
                }

                return false;
            },
                    
            removeListener: function(el, sType, fn, index) {

                if (!fn || !fn.call) {
                    return false;
                }

                // The el argument can be a string
                if (typeof el == "string") {
                    el = this.getEl(el);
                // The el argument can be an array of elements or element ids.
                } else if ( this._isValidCollection(el)) {
                    var ok = true;
                    for (var i=0,len=el.length; i<len; ++i) {
                        ok = ( this.removeListener(el[i], sType, fn) && ok );
                    }
                    return ok;
                }

                if ("unload" == sType) {

                    for (i=0, len=unloadListeners.length; i<len; i++) {
                        var li = unloadListeners[i];
                        if (li && 
                            li[0] == el && 
                            li[1] == sType && 
                            li[2] == fn) {
                                delete unloadListeners[i];
                                return true;
                        }
                    }

                    return false;
                }

                var cacheItem = null;
  
                if ("undefined" == typeof index) {
                    index = this._getCacheIndex(el, sType, fn);
                }

                if (index >= 0) {
                    cacheItem = listeners[index];
                }

                if (!el || !cacheItem) {
                    return false;
                }


                if (el.removeEventListener) {
                    el.removeEventListener(sType, cacheItem[this.WFN], false);
                } else if (el.detachEvent) {
                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
                }

                // removed the wrapped handler
                delete listeners[index][this.WFN];
                delete listeners[index][this.FN];
                delete listeners[index];

                return true;

            },

            getTarget: function(ev, resolveTextNode) {
                var t = ev.target || ev.srcElement;

                if (resolveTextNode && t && "#text" == t.nodeName) {
                    return t.parentNode;
                } else {
                    return t;
                }
            },

            getPageX: function(ev) {
                var x = ev.pageX;
                if (!x && 0 !== x) {
                    x = ev.clientX || 0;

                    if ( this.isIE ) {
                        x += this._getScrollLeft();
                    }
                }

                return x;
            },

            getPageY: function(ev) {
                var y = ev.pageY;
                if (!y && 0 !== y) {
                    y = ev.clientY || 0;

                    if ( this.isIE ) {
                        y += this._getScrollTop();
                    }
                }

                return y;
            },
            getXY: function(ev) {
                return [this.getPageX(ev), this.getPageY(ev)];
            },
            getRelatedTarget: function(ev) {
                var t = ev.relatedTarget;
                if (!t) {
                    if (ev.type == "mouseout") {
                        t = ev.toElement;
                    } else if (ev.type == "mouseover") {
                        t = ev.fromElement;
                    }
                }

                return t;
            },
            getTime: function(ev) {
                if (!ev.time) {
                    var t = new Date().getTime();
                    try {
                        ev.time = t;
                    } catch(e) { 
                        // can't set the time property  
                        return t;
                    }
                }

                return ev.time;
            },
            stopEvent: function(ev) {
                this.stopPropagation(ev);
                this.preventDefault(ev);
            },
            stopPropagation: function(ev) {
                if (ev.stopPropagation) {
                    ev.stopPropagation();
                } else {
                    ev.cancelBubble = true;
                }
            },
            preventDefault: function(ev) {
                if (ev.preventDefault) {
                    ev.preventDefault();
                } else {
                    ev.returnValue = false;
                }
            },
            getEvent: function(e) {
                var ev = e || window.event;

                if (!ev) {
                    var c = this.getEvent.caller;
                    while (c) {
                        ev = c.arguments[0];
                        if (ev && Event == ev.constructor) {
                            break;
                        }
                        c = c.caller;
                    }
                }

                return ev;
            },
            getCharCode: function(ev) {
                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
            },
            _getCacheIndex: function(el, sType, fn) {
                for (var i=0,len=listeners.length; i<len; ++i) {
                    var li = listeners[i];
                    if ( li                 && 
                         li[this.FN] == fn  && 
                         li[this.EL] == el  && 
                         li[this.TYPE] == sType ) {
                        return i;
                    }
                }

                return -1;
            },
            generateId: function(el) {
                var id = el.id;

                if (!id) {
                    id = "yuievtautoid-" + (counter++);
                    el.id = id;
                }

                return id;
            },
            _isValidCollection: function(o) {

                return ( o                    && // o is something
                         o.length             && // o is indexed
                         typeof o != "string" && // o is not a string
                         !o.tagName           && // o is not an HTML element
                         !o.alert             && // o is not a window
                         typeof o[0] != "undefined" );

            },
            elCache: {},

            getEl: function(id) {
                return document.getElementById(id);
            },
            clearCache: function() { },
            regCE: function(ce) {
                customEvents.push(ce);
            },
            _load: function(e) {
                loadComplete = true;
            },
            _tryPreloadAttach: function() {

                if (this.locked) {
                    return false;
                }

                this.locked = true;
                var tryAgain = !loadComplete;
                if (!tryAgain) {
                    tryAgain = (retryCount > 0);
                }
                var stillDelayed = [];

                for (var i=0,len=delayedListeners.length; i<len; ++i) {
                    var d = delayedListeners[i];
                    if (d) {
                        var el = this.getEl(d[this.EL]);

                        if (el) {
                            this.on(el, d[this.TYPE], d[this.FN], 
                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
                            delete delayedListeners[i];
                        } else {
                            stillDelayed.push(d);
                        }
                    }
                }

                delayedListeners = stillDelayed;

                // onAvailable
                notAvail = [];
                for (i=0,len=onAvailStack.length; i<len ; ++i) {
                    var item = onAvailStack[i];
                    if (item) {
                        el = this.getEl(item.id);

                        if (el) {
                            var scope = (item.override) ? item.obj : el;
                            item.fn.call(scope, item.obj);
                            delete onAvailStack[i];
                        } else {
                            notAvail.push(item);
                        }
                    }
                }

                retryCount = (stillDelayed.length === 0 && 
                                    notAvail.length === 0) ? 0 : retryCount - 1;

                if (tryAgain) {
                    this.startTimeout();
                }

                this.locked = false;

            },

            _unload: function(e, me) {
                for (var i=0,len=unloadListeners.length; i<len; ++i) {
                    var l = unloadListeners[i];
                    if (l) {
                        var scope = (l[this.ADJ_SCOPE]) ? l[this.SCOPE]: window;
                        l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );
                    }
                }

                if (listeners && listeners.length > 0) {
                    for (i=0,len=listeners.length; i<len ; ++i) {
                        l = listeners[i];
                        if (l) {
                            this.removeListener(l[this.EL], l[this.TYPE], 
                                    l[this.FN], i);
                        }
                    }

                    this.clearCache();
                }

                for (i=0,len=customEvents.length; i<len; ++i) {
                    customEvents[i].unsubscribeAll();
                    delete customEvents[i];
                }

                for (i=0,len=legacyEvents.length; i<len; ++i) {
                    // dereference the element
                    delete legacyEvents[i][0];
                    // delete the array item
                    delete legacyEvents[i];
                }
            },
            _getScrollLeft: function() {
                return this._getScroll()[1];
            },

            _getScrollTop: function() {
                return this._getScroll()[0];
            },

            _getScroll: function() {
                var dd = document.documentElement; db = document.body;
                if (dd && dd.scrollTop) {
                    return [dd.scrollTop, dd.scrollLeft];
                } else if (db) {
                    return [db.scrollTop, db.scrollLeft];
                } else {
                    return [0, 0];
                }
            }
        };
    } ();

    /**
     * @private
     */
    YAHOO.util.Event.on = YAHOO.util.Event.addListener;

    if (document && document.body) {
        YAHOO.util.Event._load();
    } else {
        YAHOO.util.Event.on(window, "load", YAHOO.util.Event._load, 
                YAHOO.util.Event, true);
    }

    YAHOO.util.Event.on(window, "unload", YAHOO.util.Event._unload, 
                YAHOO.util.Event, true);

    YAHOO.util.Event._tryPreloadAttach();

}

/** TREE VIEW.JS*/
YAHOO.widget.TreeView = function(id) {
	if (id) { this.init(id); }
};

YAHOO.widget.TreeView.nodeCount = 0;

YAHOO.widget.TreeView.prototype = {

    id: null,

    _nodes: null,

    locked: false,

    _expandAnim: null,

    _collapseAnim: null,

    _animCount: 0,

    maxAnim: 2,

    setExpandAnim: function(type) {
        if (YAHOO.widget.TVAnim.isValid(type)) {
            this._expandAnim = type;
        }
    },

    setCollapseAnim: function(type) {
        if (YAHOO.widget.TVAnim.isValid(type)) {
            this._collapseAnim = type;
        }
    },

    animateExpand: function(el) {

        if (this._expandAnim && this._animCount < this.maxAnim) {
            // this.locked = true;
            var tree = this;
            var a = YAHOO.widget.TVAnim.getAnim(this._expandAnim, el, 
                            function() { tree.expandComplete(); });
            if (a) { 
                ++this._animCount;
                a.animate();
            }

            return true;
        }

        return false;
    },

    animateCollapse: function(el) {

        if (this._collapseAnim && this._animCount < this.maxAnim) {
            // this.locked = true;
            var tree = this;
            var a = YAHOO.widget.TVAnim.getAnim(this._collapseAnim, el, 
                            function() { tree.collapseComplete(); });
            if (a) { 
                ++this._animCount;
                a.animate();
            }

            return true;
        }

        return false;
    },

    expandComplete: function() {
        --this._animCount;
        // this.locked = false;
    },

    collapseComplete: function() {
        --this._animCount;
        // this.locked = false;
    },

    init: function(id) {

        this.id = id;
        this._nodes = [];

        // store a global reference
        YAHOO.widget.TreeView.trees[id] = this;

        // Set up the root node
        this.root = new YAHOO.widget.RootNode(this);


    },

    draw: function() {
        var html = this.root.getHtml();
        document.getElementById(this.id).innerHTML = html;
        this.firstDraw = false;
    },

    regNode: function(node) {
        this._nodes[node.index] = node;
    },

    getRoot: function() {
        return this.root;
    },

    setDynamicLoad: function(fnDataLoader, iconMode) { 
        this.root.setDynamicLoad(fnDataLoader, iconMode);
    },

    expandAll: function() { 
        if (!this.locked) {
            this.root.expandAll(); 
        }
    },

    collapseAll: function() { 
        if (!this.locked) {
            this.root.collapseAll(); 
        }
    },

    getNodeByIndex: function(nodeIndex) {
        var n = this._nodes[nodeIndex];
        return (n) ? n : null;
    },

    getNodeByProperty: function(property, value) {
        for (var i in this._nodes) {
            var n = this._nodes[i];
            if (n.data && value == n.data[property]) {
                return n;
            }
        }

        return null;
    },

    removeNode: function(node, autoRefresh) { 

        // Don't delete the root node
        if (node.isRoot()) {
            return false;
        }

        // Get the branch that we may need to refresh
        var p = node.parent;
        if (p.parent) {
            p = p.parent;
        }

        // Delete the node and its children
        this._deleteNode(node);

        // Refresh the parent of the parent
        if (autoRefresh && p && p.childrenRendered) {
            p.refresh();
        }

        return true;
    },

    removeChildren: function(node) { 
        for (var i=0, len=node.children.length;i<len;++i) {
            this._deleteNode(node.children[i]);
        }

        node.childrenRendered = false;
        node.dynamicLoadComplete = false;
        node.collapse();
    },

    _deleteNode: function(node) { 
        var p = node.parent;

        // Remove all the child nodes first
        this.removeChildren(node);

        // Update the parent's collection of children
        var a = [];

        for (i=0, len=p.children.length;i<len;++i) {
            if (p.children[i] != node) {
                a[a.length] = p.children[i];
            }
        }

        p.children = a;

        // reset the childrenRendered flag for the parent
        p.childrenRendered = false;

         // Update the sibling relationship                                                                                                                       
        if (node.previousSibling) {                                                                                                                              
            node.previousSibling.nextSibling = node.nextSibling;                                                                                                   
        }                                                                                                                                                        

        if (node.nextSibling) {                                                                                                                                  
            node.nextSibling.previousSibling = node.previousSibling;                                                                                               
        }

        // Update the tree's node collection 
        delete this._nodes[node.index];
    },

    onExpand: function(node) { },

    onCollapse: function(node) { }

};

YAHOO.widget.TreeView.trees = [];

YAHOO.widget.TreeView.getTree = function(treeId) {
	var t = YAHOO.widget.TreeView.trees[treeId];
	return (t) ? t : null;
};

YAHOO.widget.TreeView.getNode = function(treeId, nodeIndex) {
	var t = YAHOO.widget.TreeView.getTree(treeId);
	return (t) ? t.getNodeByIndex(nodeIndex) : null;
};

YAHOO.widget.TreeView.addHandler = function (el, sType, fn, capture) {
	capture = (capture) ? true : false;
	if (el.addEventListener) {
		el.addEventListener(sType, fn, capture);
	} else if (el.attachEvent) {
		el.attachEvent("on" + sType, fn);
	} else {
		el["on" + sType] = fn;
	}
};

YAHOO.widget.TreeView.preload = function() {

	var styles = [
		"ygtvtn",	
		"ygtvtm",	
		"ygtvtmh",	
		"ygtvtp",	
		"ygtvtph",	
		"ygtvln",	
		"ygtvlm",	
		"ygtvlmh",	
		"ygtvlp",	
		"ygtvlph",	
		"ygtvloading"
		];

	var sb = [];
	
	for (var i = 0; i < styles.length; ++i) { 
		sb[sb.length] = '<span class="' + styles[i] + '">&nbsp;</span>';
	}

	var f = document.createElement("div");
	var s = f.style;
	s.position = "absolute";
	s.top = "-1000px";
	s.left = "-1000px";
	f.innerHTML = sb.join("");

	document.body.appendChild(f);
};

YAHOO.widget.TreeView.addHandler(window, 
                "load", YAHOO.widget.TreeView.preload);

/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */

/**
 * The base class for all tree nodes.  The node's presentation and behavior in
 * response to mouse events is handled in Node subclasses.
 *
 * @param oData {object} a string or object containing the data that will
 * be used to render this node
 * @param oParent {Node} this node's parent node
 * @param expanded {boolean} the initial expanded/collapsed state
 * @constructor
 */
YAHOO.widget.Node = function(oData, oParent, expanded) {
	if (oParent) { this.init(oData, oParent, expanded); }
};

YAHOO.widget.Node.prototype = {


    index: 0,


    children: null,


    tree: null,

    data: null,

    parent: null,

    depth: -1,

    href: null,

    target: "_self",

    expanded: false,

    multiExpand: true,

    renderHidden: false,

    childrenRendered: false,

    dynamicLoadComplete: false,

    previousSibling: null,

    nextSibling: null,

    _dynLoad: false,

    dataLoader: null,

    isLoading: false,

    hasIcon: true,

    iconMode: 0,

    _type: "Node",

    init: function(oData, oParent, expanded) {
        this.data		= oData;
        this.children	= [];
        this.index		= YAHOO.widget.TreeView.nodeCount;
        ++YAHOO.widget.TreeView.nodeCount;
        this.expanded	= expanded;

        // oParent should never be null except when we create the root node.
        if (oParent) {
            this.tree			= oParent.tree;
            this.parent			= oParent;
            this.href			= "javascript:" + this.getToggleLink();
            this.depth			= oParent.depth + 1;
            this.multiExpand	= oParent.multiExpand;

            oParent.appendChild(this);
        }
    },

    appendChild: function(node) {
        if (this.hasChildren()) {
            var sib = this.children[this.children.length - 1];
            sib.nextSibling = node;
            node.previousSibling = sib;
        }

        this.tree.regNode(node);
        this.children[this.children.length] = node;
        this.childrenRendered = false;
        return node;

    },

    getSiblings: function() {
        return this.parent.children;
    },

    showChildren: function() {
        if (!this.tree.animateExpand(this.getChildrenEl())) {
            if (this.hasChildren()) {
                this.getChildrenEl().style.display = "";
            }
        }
    },

    /**
     * Hides this node's children
     */
    hideChildren: function() {

        if (!this.tree.animateCollapse(this.getChildrenEl())) {
            this.getChildrenEl().style.display = "none";
        }
    },

    getElId: function() {
        return "ygtv" + this.index;
    },

    getChildrenElId: function() {
        return "ygtvc" + this.index;
    },

    getToggleElId: function() {
        return "ygtvt" + this.index;
    },

    getEl: function() {
        return document.getElementById(this.getElId());
    },

    getChildrenEl: function() {
        return document.getElementById(this.getChildrenElId());
    },

    getToggleEl: function() {
        return document.getElementById(this.getToggleElId());
    },

    getToggleLink: function() {
        return "YAHOO.widget.TreeView.getNode(\'" + this.tree.id + "\'," + 
            this.index + ").toggle()";
    },
    collapse: function() {
        // Only collapse if currently expanded
        if (!this.expanded) { return; }

        // fire the collapse event handler
        var ret = this.tree.onCollapse(this);

        if ("undefined" != typeof ret && !ret) {
            return;
        }

        if (!this.getEl()) {
            this.expanded = false;
            return;
        }

        // hide the child div
        this.hideChildren();
        this.expanded = false;

        if (this.hasIcon) {
            this.getToggleEl().className = this.getStyle();
        }

        // this.getSpacer().title = this.getStateText();

    },

    expand: function() {
        // Only expand if currently collapsed.
        if (this.expanded) { return; }

        // fire the expand event handler
        var ret = this.tree.onExpand(this);

        if ("undefined" != typeof ret && !ret) {
            return;
        }

        if (!this.getEl()) {
            this.expanded = true;
            return;
        }

        if (! this.childrenRendered) {
            this.getChildrenEl().innerHTML = this.renderChildren();
        } else {
        }

        this.expanded = true;
        if (this.hasIcon) {
            this.getToggleEl().className = this.getStyle();
        }

        if (this.isLoading) {
            this.expanded = false;
            return;
        }

        if (! this.multiExpand) {
            var sibs = this.getSiblings();
            for (var i=0; i<sibs.length; ++i) {
                if (sibs[i] != this && sibs[i].expanded) { 
                    sibs[i].collapse(); 
                }
            }
        }

        this.showChildren();
    },

    getStyle: function() {
        if (this.isLoading) {
            return "ygtvloading";
        } else {
            // location top or bottom, middle nodes also get the top style
            var loc = (this.nextSibling) ? "t" : "l";

            // type p=plus(expand), m=minus(collapase), n=none(no children)
            var type = "n";
            if (this.hasChildren(true) || (this.isDynamic() && !this.getIconMode())) {
            // if (this.hasChildren(true)) {
                type = (this.expanded) ? "m" : "p";
            }

            return "ygtv" + loc + type;
        }
    },

    /**
     * Returns the hover style for the icon
     * @return {string} the css class hover state
     */
    getHoverStyle: function() { 
        var s = this.getStyle();
        if (this.hasChildren(true) && !this.isLoading) { 
            s += "h"; 
        }
        return s;
    },

    /**
     * Recursively expands all of this node's children.
     */
    expandAll: function() { 
        for (var i=0;i<this.children.length;++i) {
            var c = this.children[i];
            if (c.isDynamic()) {
                alert("Not supported (lazy load + expand all)");
                break;
            } else if (! c.multiExpand) {
                alert("Not supported (no multi-expand + expand all)");
                break;
            } else {
                c.expand();
                c.expandAll();
            }
        }
    },

    /**
     * Recursively collapses all of this node's children.
     */
    collapseAll: function() { 
        for (var i=0;i<this.children.length;++i) {
            this.children[i].collapse();
            this.children[i].collapseAll();
        }
    },

    setDynamicLoad: function(fnDataLoader, iconMode) { 
        if (fnDataLoader) {
            this.dataLoader = fnDataLoader;
            this._dynLoad = true;
        } else {
            this.dataLoader = null;
            this._dynLoad = false;
        }

        if (iconMode) {
            this.iconMode = iconMode;
        }
    },

    isRoot: function() { 
        return (this == this.tree.root);
    },

    isDynamic: function() { 
        var lazy = (!this.isRoot() && (this._dynLoad || this.tree.root._dynLoad));
        return lazy;
    },

    getIconMode: function() {
        return (this.iconMode || this.tree.root.iconMode);
    },

    hasChildren: function(checkForLazyLoad) { 
        return ( this.children.length > 0 || 
                (checkForLazyLoad && this.isDynamic() && !this.dynamicLoadComplete) );
    },

    toggle: function() {
        if (!this.tree.locked && ( this.hasChildren(true) || this.isDynamic()) ) {
            if (this.expanded) { this.collapse(); } else { this.expand(); }
        }
    },

    getHtml: function() {
        var sb = [];
        sb[sb.length] = '<div class="ygtvitem" id="' + this.getElId() + '">';
        sb[sb.length] = this.getNodeHtml();
        sb[sb.length] = this.getChildrenHtml();
        sb[sb.length] = '</div>';
        return sb.join("");
    },

    getChildrenHtml: function() {

        var sb = [];
        sb[sb.length] = '<div class="ygtvchildren"';
        sb[sb.length] = ' id="' + this.getChildrenElId() + '"';
        if (!this.expanded) {
            sb[sb.length] = ' style="display:none;"';
        }
        sb[sb.length] = '>';

        // Don't render the actual child node HTML unless this node is expanded.
        if ( (this.hasChildren(true) && this.expanded) ||
                (this.renderHidden && !this.isDynamic()) ) {
            sb[sb.length] = this.renderChildren();
        }

        sb[sb.length] = '</div>';

        return sb.join("");
    },

    renderChildren: function() {


        var node = this;

        if (this.isDynamic() && !this.dynamicLoadComplete) {
            this.isLoading = true;
            this.tree.locked = true;

            if (this.dataLoader) {

                setTimeout( 
                    function() {
                        node.dataLoader(node, 
                            function() { 
                                node.loadComplete(); 
                            });
                    }, 10);
                
            } else if (this.tree.root.dataLoader) {

                setTimeout( 
                    function() {
                        node.tree.root.dataLoader(node, 
                            function() { 
                                node.loadComplete(); 
                            });
                    }, 10);

            } else {
                return "Error: data loader not found or not specified.";
            }

            return "";

        } else {
            return this.completeRender();
        }
    },

    completeRender: function() {
        var sb = [];

        for (var i=0; i < this.children.length; ++i) {
            this.children[i].childrenRendered = false;
            sb[sb.length] = this.children[i].getHtml();
        }
        
        this.childrenRendered = true;

        return sb.join("");
    },

    loadComplete: function() {
        this.getChildrenEl().innerHTML = this.completeRender();
        this.dynamicLoadComplete = true;
        this.isLoading = false;
        this.expand();
        this.tree.locked = false;
    },

    getAncestor: function(depth) {
        if (depth >= this.depth || depth < 0)  {
            return null;
        }

        var p = this.parent;
        
        while (p.depth > depth) {
            p = p.parent;
        }

        return p;
    },

    getDepthStyle: function(depth) {
        return (this.getAncestor(depth).nextSibling) ? 
            "ygtvdepthcell" : "ygtvblankdepthcell";
    },

    getNodeHtml: function() { 
        return ""; 
    },

    refresh: function() {
        // this.loadComplete();
        this.getChildrenEl().innerHTML = this.completeRender();

        if (this.hasIcon) {
            var el = this.getToggleEl();
            if (el) {
                el.className = this.getStyle();
            }
        }
    }

};

/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */

/**
 * A custom YAHOO.widget.Node that handles the unique nature of 
 * the virtual, presentationless root node.
 *
 * @extends YAHOO.widget.Node
 * @constructor
 */
YAHOO.widget.RootNode = function(oTree) {
	this.init(null, null, true);
	this.tree = oTree;
};
YAHOO.widget.RootNode.prototype = new YAHOO.widget.Node();

// overrides YAHOO.widget.Node
YAHOO.widget.RootNode.prototype.getNodeHtml = function() { 
	return ""; 
};

/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */

YAHOO.widget.TextNode = function(oData, oParent, expanded) {
    this.type = "TextNode";

	if (oParent) { 
		this.init(oData, oParent, expanded);
		this.setUpLabel(oData);
	}
};

YAHOO.widget.TextNode.prototype = new YAHOO.widget.Node();

YAHOO.widget.TextNode.prototype.labelStyle = "ygtvlabel";

YAHOO.widget.TextNode.prototype.labelElId = null;

YAHOO.widget.TextNode.prototype.label = null;

YAHOO.widget.TextNode.prototype.setUpLabel = function(oData) { 
	if (typeof oData == "string") {
		oData = { label: oData };
	}
	this.label = oData.label;
	
	// update the link
	if (oData.href) {
		this.href = oData.href;
	}

	// set the target
	if (oData.target) {
		this.target = oData.target;
	}

    if (oData.style) {
        this.labelStyle = oData.style;
    }

	this.labelElId = "ygtvlabelel" + this.index;
};

/**
 * Returns the label element
 *
 * @return {object} the element
 */
YAHOO.widget.TextNode.prototype.getLabelEl = function() { 
	return document.getElementById(this.labelElId);
};

// overrides YAHOO.widget.Node
YAHOO.widget.TextNode.prototype.getNodeHtml = function() { 
	var sb = [];

	sb[sb.length] = '<table border="0" cellpadding="0" cellspacing="0">';
	sb[sb.length] = '<tr>';
	
	for (i=0;i<this.depth;++i) {
		// sb[sb.length] = '<td class="ygtvdepthcell">&nbsp;</td>';
		sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '">&nbsp;</td>';
	}

	var getNode = 'YAHOO.widget.TreeView.getNode(\'' +
					this.tree.id + '\',' + this.index + ')';

	sb[sb.length] = '<td';
	// sb[sb.length] = ' onselectstart="return false"';
	sb[sb.length] = ' id="' + this.getToggleElId() + '"';
	sb[sb.length] = ' class="' + this.getStyle() + '"';
	if (this.hasChildren(true)) {
		sb[sb.length] = ' onmouseover="this.className=';
		sb[sb.length] = getNode + '.getHoverStyle()"';
		sb[sb.length] = ' onmouseout="this.className=';
		sb[sb.length] = getNode + '.getStyle()"';
	}
	sb[sb.length] = ' onclick="javascript:' + this.getToggleLink() + '">';

	sb[sb.length] = '&nbsp;';

	sb[sb.length] = '</td>';
	sb[sb.length] = '<td>';
	sb[sb.length] = '<a';
	sb[sb.length] = ' id="' + this.labelElId + '"';
	sb[sb.length] = ' class="' + this.labelStyle + '"';
	sb[sb.length] = ' href="' + this.href + '"';
	sb[sb.length] = ' target="' + this.target + '"';
	sb[sb.length] = ' onclick="return ' + getNode + '.onLabelClick(' + getNode +')"';
	if (this.hasChildren(true)) {
		sb[sb.length] = ' onmouseover="document.getElementById(\'';
		sb[sb.length] = this.getToggleElId() + '\').className=';
		sb[sb.length] = getNode + '.getHoverStyle()"';
		sb[sb.length] = ' onmouseout="document.getElementById(\'';
		sb[sb.length] = this.getToggleElId() + '\').className=';
		sb[sb.length] = getNode + '.getStyle()"';
	}
	sb[sb.length] = ' >';
	sb[sb.length] = this.label;
	sb[sb.length] = '</a>';
	sb[sb.length] = '</td>';
	sb[sb.length] = '</tr>';
	sb[sb.length] = '</table>';

	return sb.join("");
};

YAHOO.widget.TextNode.prototype.onLabelClick = function(me) { 
    //return true;
};

YAHOO.widget.MenuNode = function(oData, oParent, expanded) {
	if (oParent) { 
		this.init(oData, oParent, expanded);
		this.setUpLabel(oData);
	}

	this.multiExpand = false;

};

YAHOO.widget.MenuNode.prototype = new YAHOO.widget.TextNode();

/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */

YAHOO.widget.HTMLNode = function(oData, oParent, expanded, hasIcon) {
    if (oParent) { 
        this.init(oData, oParent, expanded);
        this.initContent(oData, hasIcon);
    }
};

YAHOO.widget.HTMLNode.prototype = new YAHOO.widget.Node();

YAHOO.widget.HTMLNode.prototype.contentStyle = "ygtvhtml";

YAHOO.widget.HTMLNode.prototype.contentElId = null;

YAHOO.widget.HTMLNode.prototype.content = null;

YAHOO.widget.HTMLNode.prototype.initContent = function(oData, hasIcon) { 
    if (typeof oData == "string") {
        oData = { html: oData };
    }

    this.html = oData.html;
    this.contentElId = "ygtvcontentel" + this.index;
    this.hasIcon = hasIcon;
};

/**
 * Returns the outer html element for this node's content
 *
 * @return {HTMLElement} the element
 */
YAHOO.widget.HTMLNode.prototype.getContentEl = function() { 
    return document.getElementById(this.contentElId);
};

// overrides YAHOO.widget.Node
YAHOO.widget.HTMLNode.prototype.getNodeHtml = function() { 
    var sb = [];

    sb[sb.length] = '<table border="0" cellpadding="0" cellspacing="0">';
    sb[sb.length] = '<tr>';
    
    for (i=0;i<this.depth;++i) {
        sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '">&nbsp;</td>';
    }

    if (this.hasIcon) {
        sb[sb.length] = '<td';
        sb[sb.length] = ' id="' + this.getToggleElId() + '"';
        sb[sb.length] = ' class="' + this.getStyle() + '"';
        sb[sb.length] = ' onclick="javascript:' + this.getToggleLink() + '"';
        if (this.hasChildren(true)) {
            sb[sb.length] = ' onmouseover="this.className=';
            sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
            sb[sb.length] = this.tree.id + '\',' + this.index +  ').getHoverStyle()"';
            sb[sb.length] = ' onmouseout="this.className=';
            sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
            sb[sb.length] = this.tree.id + '\',' + this.index +  ').getStyle()"';
        }
        sb[sb.length] = '>&nbsp;</td>';
    }

    sb[sb.length] = '<td';
    sb[sb.length] = ' id="' + this.contentElId + '"';
    sb[sb.length] = ' class="' + this.contentStyle + '"';
    sb[sb.length] = ' >';
    sb[sb.length] = this.html;
    sb[sb.length] = '</td>';
    sb[sb.length] = '</tr>';
    sb[sb.length] = '</table>';

    return sb.join("");
};

/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */

YAHOO.widget.TVAnim = function() {
    return {
        FADE_IN: "TVFadeIn",
        FADE_OUT: "TVFadeOut",
        getAnim: function(type, el, callback) {
            if (YAHOO.widget[type]) {
                return new YAHOO.widget[type](el, callback);
            } else {
                return null;
            }
        },
        isValid: function(type) {
            return (YAHOO.widget[type]);
        }
    };
} ();

/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */

YAHOO.widget.TVFadeIn = function(el, callback) {
	this.el = el;
	this.callback = callback;
};

YAHOO.widget.TVFadeIn.prototype = {
    animate: function() {
        var tvanim = this;

        var s = this.el.style;
        s.opacity = 0.1;
        s.filter = "alpha(opacity=10)";
        s.display = "";

        // var dur = ( navigator.userAgent.match(/msie/gi) ) ? 0.05 : 0.4;
        var dur = 0.4; 
        var a = new YAHOO.util.Anim(this.el, {opacity: {from: 0.1, to: 1, unit:""}}, dur);
        a.onComplete.subscribe( function() { tvanim.onComplete(); } );
        a.animate();
    },

    onComplete: function() {
        this.callback();
    }
};

/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */

YAHOO.widget.TVFadeOut = function(el, callback) {
	this.el = el;
	this.callback = callback;

};

YAHOO.widget.TVFadeOut.prototype = {
    animate: function() {
        var tvanim = this;
        // var dur = ( navigator.userAgent.match(/msie/gi) ) ? 0.05 : 0.4;
        var dur = 0.4;
        var a = new YAHOO.util.Anim(this.el, {opacity: {from: 1, to: 0.1, unit:""}}, dur);
        a.onComplete.subscribe( function() { tvanim.onComplete(); } );
        a.animate();
    },

    onComplete: function() {
        var s = this.el.style;
        s.display = "none";
        // s.opacity = 1;
        s.filter = "alpha(opacity=100)";
        this.callback();
    }
};

