/**
 * The check box marks a task complete.  It is a simulated form field 
 * with three states ...
 * 0=unchecked, 1=some children checked, 2=all children checked
 * When a task is clicked, the state of the nodes and parent and children
 * are updated, and this behavior cascades.
 *
 * @extends YAHOO.widget.TextNode
 * @constructor
 * @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
 * @param checked  {boolean} The initial checked/unchecked state
 */
 
function extendTaskNode() {
YAHOO.widget.TaskNode = function(oData, oParent, expanded, checked, leaf) {

    if (YAHOO.widget.LogWriter) {
        this.logger = new YAHOO.widget.LogWriter(this.toString());
    } else {
        this.logger = YAHOO;
    }

    if (oData) { 
    	if (leaf) this.isLeaf = true;
        this.init(oData, oParent, expanded);
        this.setUpLabel(oData);
        this.setUpCheck(checked);
    }

};

YAHOO.extend(YAHOO.widget.TaskNode, YAHOO.widget.TextNode, {

    /**
     * True if checkstate is 1 (some children checked) or 2 (all children checked),
     * false if 0.
     * @type boolean
     */
    checked: false,

    /**
     * checkState
     * 0=unchecked, 1=some children checked, 2=all children checked
     * @type int
     */
    checkState: 0,
    
    /**
     *
     */
    isLoading: false,
    
    imageUrl: null,
    
    setImage: function(url) {
    	this.imageUrl = url;
    	this.updateImgHtml();
    },
    
    startLoading: function() {
    	this.isLoading = true;
    	this.updateCheckHtml();
    },
    
    stopLoading: function() {
    	this.isLoading = false;
    	this.updateCheckHtml();
    },
    
    taskNodeParentChange: function() {
        //this.updateParent();
    },

    setUpCheck: function(checked) {
        // if this node is checked by default, run the check code to update
        // the parent's display state
        if (checked && checked === true) {
            this.check();
        // otherwise the parent needs to be updated only if its checkstate 
        // needs to change from fully selected to partially selected
        } else if (this.parent && 2 == this.parent.checkState) {
             this.updateParent();
        }

        // set up the custom event on the tree for checkClick
        /**
         * Custom event that is fired when the check box is clicked.  The
         * custom event is defined on the tree instance, so there is a single
         * event that handles all nodes in the tree.  The node clicked is 
         * provided as an argument.  Note, your custom node implentation can
         * implement its own node specific events this way.
         *
         * @event checkClick
         * @for YAHOO.widget.TreeView
         * @param {YAHOO.widget.Node} node the node clicked
         */
        if (this.tree && !this.tree.hasEvent("checkClick")) {
            this.tree.createEvent("checkClick", this.tree);
        }

        this.subscribe("parentChange", this.taskNodeParentChange);

    },

    /**
     * The id of the check element
     * @for YAHOO.widget.TaskNode
     * @type string
     */
    getCheckElId: function() { 
        return "ygtvcheck" + this.index; 
    },

    /**
     * The id of the check element
     * @for YAHOO.widget.TaskNode
     * @type string
     */
    getLoadElId: function() { 
        return "ygtvload" + this.index; 
    },
    
    /**
     * The id of the check element
     * @for YAHOO.widget.TaskNode
     * @type string
     */
    getImgElId: function() { 
        return "ygtvimg" + this.index; 
    },

    /**
     * Returns the check box element
     * @return the check html element (img)
     */
    getCheckEl: function() { 
        return document.getElementById(this.getCheckElId()); 
    },
    
    /**
     * Returns the check box element
     * @return the check html element (img)
     */
    getLoadEl: function() { 
        return document.getElementById(this.getLoadElId()); 
    },

    /**
     * Returns the check box element
     * @return the check html element (img)
     */
    getImgEl: function() { 
        return document.getElementById(this.getImgElId()); 
    },

    /**
     * The style of the check element, derived from its current state
     * @return {string} the css style for the current check state
     */
    getCheckStyle: function() { 
    	if (this.isLoading) {
    		return "ygtvloading";
    	} else {
        	return "ygtvcheck" + this.checkState;
        }
    },
    
    /**
     * The style of the check element, derived from its current state
     * @return {string} the css style for the current check state
     */
    getLoadStyle: function() { 
    	if (this.isLoading) {
    		return "ygtvloading";
    	} else {
    		return "ygtvspacer";
    	}
    },

    /**
     * Returns the link that will invoke this node's check toggle
     * @return {string} returns the link required to adjust the checkbox state
     */
    getCheckLink: function() { 
        return "YAHOO.widget.TreeView.getNode(\'" + this.tree.id + "\'," + 
            this.index + ").checkClick()";
    },

    /**
     * Invoked when the user clicks the check box
     */
    checkClick: function() { 
        this.logger.log("previous checkstate: " + this.checkState);
        if (this.checkState === 0) {
            this.check();
        } else {
            this.uncheck();
        }

        this.onCheckClick(this);
        this.tree.fireEvent("checkClick", this);
    },

    /**
     * Override to get the check click event
     */
    onCheckClick: function() { 
        this.logger.log("onCheckClick: " + this);
    },

    /**
     * Refresh the state of this node's parent, and cascade up.
     */
    updateParent: function() { 
        var p = this.parent;

        if (!p || !p.updateParent) {
            this.logger.log("Abort udpate parent: " + this.index);
            return;
        }

        var somethingChecked = false;
        var somethingNotChecked = false;

        for (var i=0;i< p.children.length;++i) {
            if (p.children[i].checked) {
                somethingChecked = true;
                // checkState will be 1 if the child node has unchecked children
                if (p.children[i].checkState == 1) {
                    somethingNotChecked = true;
                }
            } else {
                somethingNotChecked = true;
            }
        }

        if (somethingChecked) {
            p.setCheckState( (somethingNotChecked) ? 1 : 2 );
        } else {
            p.setCheckState(0);
        }

        p.updateCheckHtml();
        p.updateParent();
    },

    /**
     * If the node has been rendered, update the html to reflect the current
     * state of the node.
     */
    updateCheckHtml: function() { 
        if (this.parent && this.parent.childrenRendered) {
            this.getCheckEl().className = this.getCheckStyle();
        }
    },
    
    /**
     * If the node has been rendered, update the html to reflect the current
     * state of the node.
     */
    updateLoadHtml: function() { 
        if (this.parent && this.parent.childrenRendered) {
            this.getLoadEl().className = this.getLoadStyle();
        }
    },

    /**
     * If the node has been rendered, update the html to reflect the current
     * state of the node.
     */
    updateImgHtml: function() { 
        if (this.parent && this.parent.childrenRendered) {
        	var img = this.getImgEl();
        	if (this.imageUrl) {
            	img.style.display = 'block';
            	img.src = this.imageUrl;
            } else {
            	img.style.display = 'none';
            }
        }
    },

    /**
     * Updates the state.  The checked property is true if the state is 1 or 2
     * 
     * @param the new check state
     */
    setCheckState: function(state) { 
        this.checkState = state;
        this.checked = (state > 0);
    },

    /**
     * Check this node
     */
    check: function() { 
    	if (!this.isLeaf) return;
        this.logger.log("check");
        this.setCheckState(2);
        for (var i=0; i<this.children.length; ++i) {
            this.children[i].check();
        }
        this.updateCheckHtml();
        this.updateParent();
    },

    /**
     * Uncheck this node
     */
    uncheck: function() { 
    	if (!this.isLeaf) return;
        this.setCheckState(0);
        for (var i=0; i<this.children.length; ++i) {
            this.children[i].uncheck();
        }
        this.updateCheckHtml();
        this.updateParent();
    },

    // Overrides YAHOO.widget.TextNode
    getNodeHtml: function() { 
        this.logger.log("Generating html");
        var sb = [];

        var getNode = 'YAHOO.widget.TreeView.getNode(\'' +
                        this.tree.id + '\',' + this.index + ')';


        sb[sb.length] = '<table border="0" cellpadding="0" cellspacing="0">';
        sb[sb.length] = '<tr>';
        
        for (var i=0;i<this.depth;++i) {
            //sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '"> </td>';
            sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '"><div class="ygtvspacer"></div></td>';
        }
        
        sb[sb.length] = '<td';
        sb[sb.length] = ' id="' + this.getToggleElId() + '"';
        if (!this.isLoading) { // only show toggle-button if node is not loading ...
        	sb[sb.length] = ' class="' + this.getStyle() + '"';
        } else {
        	sb[sb.length] = ' class="ygtvspacer"';
        }
        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] = ' onclick="javascript:' + this.getToggleLink() + '"> ';
        sb[sb.length] = '</td>';

        // check box
        sb[sb.length] = '<td';
        sb[sb.length] = ' id="' + this.getCheckElId() + '"';
        sb[sb.length] = ' class="' + this.getCheckStyle() + '"';
        sb[sb.length] = ' onclick="javascript:' + this.getCheckLink() + '">';
        sb[sb.length] = ' </td>';

		// img ...
		sb[sb.length] = '<td valign="top">';
		sb[sb.length] = ' <img';
        sb[sb.length] = ' id="' + this.getImgElId() + '"';
        sb[sb.length] = ' src="' + this.imageUrl + '" width="15" height="15"';
        if (!this.imageUrl) {
        	sb[sb.length] = ' style="vertical-align:middle;border:none;padding:1px;padding-top:3px;padding-right:3px;display:none;" >';
        } else {
        	sb[sb.length] = ' style="vertical-align:middle;border:none;padding:1px;padding-top:3px;padding-right:3px;" >';
        }
        sb[sb.length] = ' </img>';
        sb[sb.length] = '</td>';

        sb[sb.length] = '<td style="padding-left:3px;" >';
        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] = 'YAHOO.widget.TreeView.getNode(\'';
            sb[sb.length] = this.tree.id + '\',' + this.index +  ').getHoverStyle()"';
            sb[sb.length] = ' onmouseout="document.getElementById(\'';
            sb[sb.length] = this.getToggleElId() + '\').className=';
            sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
            sb[sb.length] = this.tree.id + '\',' + this.index +  ').getStyle()"';
        }
        sb[sb.length] = (this.nowrap) ? ' nowrap="nowrap" ' : '';
        sb[sb.length] = ' >';
        
        sb[sb.length] = this.label;
        sb[sb.length] = '</a>';
        sb[sb.length] = '</td>';
        
        /* is attached to the check symbol now ...
        // loading symbol ...
        sb[sb.length] = '<td';
        sb[sb.length] = ' id="' + this.getLoadElId() + '"';
        sb[sb.length] = ' class="' + this.getLoadStyle() + '" >';
        sb[sb.length] = '</td>';
        */

        sb[sb.length] = '</tr>';
        sb[sb.length] = '</table>';

        return sb.join("");

    },

    toString: function() {
        return "TaskNode (" + this.index + ") " + this.label;
    }

});
}