/**
 * @class YAHOO.ext.tree.TreeNode
 * @extends YAHOO.ext.data.Node
 * @cfg {Boolean} leaf true if this node is a leaf and does not have or cannot have children
 * @cfg {Boolean} expanded true to start the node expanded
 * @cfg {Boolean} draggable false to make this node undraggable if DD is on (default to true)
 * @cfg {Boolean} isTarget false if this node cannot be drop on
 * @cfg {Boolean} disabled true to start the node disabled
 * @constructor
 * @param {Object} attributes The attributes/config for the node 
 */
YAHOO.ext.tree.TreeNode = function(attributes){
    attributes = attributes || {};
    if(typeof attributes == 'string'){
        attributes = {text: attributes};
    }
    this.el = null;
    this.childrenRendered = false;
    this.rendered = false;
    YAHOO.ext.tree.TreeNode.superclass.constructor.call(this, attributes);
    this.expanded = attributes.expanded === true;
    this.isTarget = attributes.isTarget !== false;
    this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
    this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
    this.text = attributes.text;
    this.disabled = attributes.disabled === true;
    
    YAHOO.ext.util.Config.apply(this.events, {
        'textchange' : true,
        'beforeexpand' : true,
        'beforecollapse' : true,
        'expand' : true,
        'disabledchange' : true,
        'collapse' : true,
        'beforeclick':true,
        'click':true,
        'dblclick':true,
        'contentmenu':true,
        'beforechildrenrendered':true
    });
    
    var uiClass = this.attributes.uiProvider || YAHOO.ext.tree.TreeNodeUI;
    this.ui = new uiClass(this);
};
YAHOO.extendX(YAHOO.ext.tree.TreeNode, YAHOO.ext.data.Node, {
    isExpanded : function(){
        return this.expanded;
    },
    
    getUI : function(){
        return this.ui;    
    },
    
    setFirstChild : function(node){
        var of = this.firstChild;
        YAHOO.ext.tree.TreeNode.superclass.setFirstChild.call(this, node);
        if(this.childrenRendered && of && node != of){
            of.renderIndent(true, true);  
        }
        if(this.rendered){
            this.renderIndent(true, true);
        }
    },
    
    setLastChild : function(node){
        var ol = this.lastChild;
        YAHOO.ext.tree.TreeNode.superclass.setLastChild.call(this, node);
        if(this.childrenRendered && ol && node != ol){
            ol.renderIndent(true, true);    
        }
        if(this.rendered){
            this.renderIndent(true, true);
        }
    },
    
    // these methods are overridden to provide lazy rendering support
    appendChild : function(){
        var node = YAHOO.ext.tree.TreeNode.superclass.appendChild.apply(this, arguments);
        if(node && this.childrenRendered){
            node.render();
        }
        this.ui.updateExpandIcon();
        return node;
    },
    
    removeChild : function(node){
        this.ownerTree.getSelectionModel().unselect(node);
        YAHOO.ext.tree.TreeNode.superclass.removeChild.apply(this, arguments);
        // if it's been rendered remove dom node
        if(this.childrenRendered){
            node.ui.remove();
        }
        if(this.childNodes.length < 1){
            this.collapse(false, false);
        }else{
            this.ui.updateExpandIcon();
        }
        return node;
    },
    
    insertBefore : function(node, refNode){
        var newNode = YAHOO.ext.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
        if(newNode && refNode && this.childrenRendered){
            node.render();
        }
        this.ui.updateExpandIcon();
        return newNode;
    },
    
    setText : function(text){
        var oldText = this.text;
        this.text = text;
        this.attributes.text = text;
        if(this.rendered){ // event without subscribing
            this.ui.onTextChange(this, text, oldText);
        }
        this.fireEvent('textchange', this, text, oldText);
    },
    
    select : function(){
        this.getOwnerTree().getSelectionModel().select(this);
    },
    
    unselect : function(){
        this.getOwnerTree().getSelectionModel().unselect(this);
    },
    
    isSelected : function(){
        return this.getOwnerTree().getSelectionModel().isSelected(node);  
    },
    
    expand : function(deep, anim, callback){
        if(!this.expanded){
            if(this.fireEvent('beforeexpand', this, deep, anim) === false){
                return;
            }
            if(!this.childrenRendered){
                this.renderChildren();
            }
            this.expanded = true;
            if((this.getOwnerTree().animate && anim !== false) || anim){
                this.ui.animExpand(function(){
                    this.fireEvent('expand', this);
                    if(typeof callback == 'function'){
                        callback(this);
                    }
                    if(deep === true){
                        this.expandChildNodes(true);
                    }
                }.createDelegate(this));
                return;
            }else{
                this.ui.expand();
                this.fireEvent('expand', this);
                if(typeof callback == 'function'){
                    callback(this);
                }
            }
        }else{
           if(typeof callback == 'function'){
               callback(this);
           } 
        }
        if(deep === true){
            this.expandChildNodes(true);
        }
    },
    
    collapse : function(deep, anim){
        if(this.expanded && (!this.isRoot || (this.isRoot && this.getOwnerTree().rootVisible))){
            if(this.fireEvent('beforecollapse', this, deep, anim) === false){
                return;
            }
            this.expanded = false;
            if((this.getOwnerTree().animate && anim !== false) || anim){
                this.ui.animCollapse(function(){
                    this.fireEvent('collapse', this);
                    if(deep === true){
                        this.collapseChildNodes(true);
                    }
                }.createDelegate(this));
                return;
            }else{
                this.ui.collapse();
                this.fireEvent('collapse', this);
            }
        }
        if(deep === true){
            var cs = this.childNodes;
            for(var i = 0, len = cs.length; i < len; i++) {
            	cs[i].collapse(true)
            }
        }
    },
    
    delayedExpand : function(delay){
        if(!this.expandProcId){
            this.expandProcId = this.expand.defer(delay, this);
        } 
    },
    
    cancelExpand : function(){
        if(this.expandProcId){
            clearTimeout(this.expandProcId);
        }
        this.expandProcId = false; 
    },
    
    toggle : function(){
        if(this.expanded){
            this.collapse();
        }else{
            this.expand();
        }
    },
    
    ensureVisible : function(){
        if(this.parentNode){
            this.parentNode.bubble(function(){
                this.expand(false, false);
            });
        }  
    },
    
    expandChildNodes : function(deep){
        var cs = this.childNodes;
        for(var i = 0, len = cs.length; i < len; i++) {
        	cs[i].expand(deep);
        }
    },
    
    collapseChildNodes : function(deep){
        var cs = this.childNodes;
        for(var i = 0, len = cs.length; i < len; i++) {
        	cs[i].expand(deep);
        }
    },
    
    disable : function(){
        this.disabled = true;
        this.unselect();
        if(this.rendered && this.ui.onDisableChange){ // event without subscribing
            this.ui.onDisableChange(this, true);
        }
        this.fireEvent('disabledchange', this, true);
    },
    
    enable : function(){
        this.disabled = false;
        if(this.rendered && this.ui.onDisableChange){ // event without subscribing
            this.ui.onDisableChange(this, false);
        }
        this.fireEvent('disabledchange', this, false); 
    },
    
    renderChildren : function(suppressEvent){
        if(suppressEvent !== false){
            this.fireEvent('beforechildrenrendered', this);
        }
        var cs = this.childNodes;
        for(var i = 0, len = cs.length; i < len; i++){
            cs[i].render(true);
        }
        this.childrenRendered = true;
    },
    
    sort : function(fn, scope){
        YAHOO.ext.tree.TreeNode.superclass.sort.apply(this, arguments);
        if(this.childrenRendered){
            var cs = this.childNodes;
            for(var i = 0, len = cs.length; i < len; i++){
                cs[i].render(true);
            }
        }  
    },
    
    render : function(bulkRender){
        this.ui.render(bulkRender);
        if(!this.rendered){
            this.rendered = true;
            if(this.expanded){
                this.expanded = false;
                this.expand(false, false);
            }
        }
    },
    
    renderIndent : function(deep, refresh){
        if(refresh){
            this.ui.childIndent = null;
        }
        this.ui.renderIndent();
        if(deep === true && this.childrenRendered){
            var cs = this.childNodes;
            for(var i = 0, len = cs.length; i < len; i++){
                cs[i].renderIndent(true, refresh);
            }
        }
    }
});
