/*--------------------------------------------------------------------------
 *  DOM DropDown Navigation v 0.1 
 *  (c) 2008 Patrick Le Hégarat - Planète Interactive
 *  Based on Prototype.js v 1.5.0+
 *--------------------------------------------------------------------------*/

TreeItem = {
    _depth : null,
    _parentItem : null,

    bindthis : function(){return function(){return this;}.bind(this)} ,
    handlekey: 'domhandle' ,
    setDomHandle : function(){
        if(!this.element) return;
        this.element[this.handlekey] = this.bindthis();
    },

	depth: function() {
 	    return (this._depth = this._depth || ( this._parentItem ? this._parentItem.depth()+1 : 1 ));
    }
}


Nav = Class.create();
Object.extend(Nav.prototype, TreeItem);
Object.extend(Nav.prototype, {

    initialize: function(o) {
        if(!o||!(this.element = $(o.element))) return;
        this.config = o.config||{};
        try {
            this.config.navItemSelector = new Selector(this.config.navItemSelector);
            this.config.navSubItemSelector = new Selector(this.config.navSubItemSelector);       
        } catch(e){ return; }
        this.config.zindex = this.config.zindex || 0;
        this.element.setStyle({zindex:this.config.zindex+this.depth()});
        
        if(this.config.setNavItem)
        this.config.navItemSelector.findElements(this.element).each(
            function(element,index) {
                new NavItem({ element:element,ref:this,index:index,config:this.config });
            }.bind(this)
        );

        this.config.navSubItemSelector.findElements(this.element).each(
            function(element,index) {
                new NavSubItem({ element:element,ref:this,index:index,config:this.config });
            }.bind(this)
        );
    },
    
    setOn: function(o) {
        this._on = this._on || {};
        var depth = o.depth();
        var inrefresh = (this._on[depth] && this._on[depth]!=o);
        if( inrefresh ) this._on[depth].setVisible();
        this._on[depth] = o;
        if( !inrefresh ) return;
        depth++;
        var item = null;
        while(item = this._on[depth])
        {
            item.visible = false;
            item.setVisible();
            if(item==this._on[depth])
                this._on[depth] = null;
            else
                return;
            depth++;
        }
    }
});

NavItem = Class.create();
Object.extend(NavItem.prototype, TreeItem);
Object.extend(NavItem.prototype, {

    manifest: 'NavItem',
    initialize: function(o) {
        if(!o||!(this.element = $(o.element))) return;
        if(!(this.ref = o.ref)) return;
        this.config = o.config||{};
        this.index = o.index;
        if(this.config.domHandle)
        {
            this.setDomHandle();
        }
        else
        {
            this.id = this.manifest+'.'+this.index;
            with(this.element){ this.id=id=(id||this.id); }
            (this.ref.navItems = this.ref.navItems || {})[this.id] = this;
        }
        this.lookup(this.ref);
		
		//alert(this.element.parentNode.tagName); 
		//alert( this.element.parentNode.offsetWidth );
		if(this.depth()>1)
			this.element.style.width =  this.element.parentNode.offsetWidth+'px';		
    },

	lookup: function(o) {
	    if(!this.element) return;
        var c,d,pe = this.element.parentNode;
        while(!this._parentItem && pe && pe!=o.element)
        {
            var id,dh;
            if(this.config.domHandle && (dh=pe[this.handlekey])!=undefined && typeof(dh)=='function')
            {
                var handle = dh.apply();
                if(handle instanceof NavItem )
                    this._parentItem = handle;
                //if(handle instanceof NavSubItem )
                //    this._parentItem = handle;
            }
            else if((id=pe.id)!=undefined)
            {
                if((c=c||o.navItems) && c[id] && c[id].element === pe)
                    this._parentItem = c[id];
                //if((d=d||o.subNavItems) && d[id] && d[id].element === pe)
                //    this._parentItem = d[id];
            }
            pe = pe.parentNode;
        }
	}
});

NavSubItem = Class.create();
Object.extend(NavSubItem.prototype, TreeItem);
Object.extend(NavSubItem.prototype, {

    manifest: 'NavSubItem',
    initialize: function(o) {
        if(!o||!(this.element = $(o.element))) return;
        if(!(this.ref = o.ref)) return;
        this.config = o.config||{};
        this.index = o.index;
        if(this.config.domHandle)
        {
            this.setDomHandle();
        }
        else
        {
            this.id = this.manifest +'.'+this.index;
            with(this.element){ this.id=id=(id||this.id); }
            (this.ref.subNavItems = this.ref.subNavItems || {})[this.id] = this;
        }
        this.visible = false;
        this.setVisible();
        this.lookup(this.ref);
        if( this._navItem )
        {
            Event.observe( this._navItem.element, 'mousemove', this._swap.bindAsEventListener(this,true) );
            Event.observe( this._navItem.element, 'mouseout', this._swap.bindAsEventListener(this,false) );
        }
    },

    lookup: function(o) {
	    if(!this.element) return;
        if(!o) return;
        this._navItem = null;
        this._parentItem = null;
        var c,d,pe = this.element.parentNode;
        while(!this._parentItem && pe && pe!=o.element)
        {
            var id,dh;
            if(!(d=d||o.navItems) && this.config.navItemSelector.match(pe))
                this._navItem = new NavItem({ element:pe });
            
            if( this.config.domHandle && (dh=pe[this.handlekey])!=undefined && typeof(dh)=='function')
            {
                var handle=dh.apply();
                if(!this._navItem && handle instanceof NavItem )
                    this._navItem = handle;
                if(handle instanceof NavSubItem)
                    this._parentItem = handle;
            }
            else if((id=pe.id)!=undefined)
            {
                if((d=d||o.navItems) && !this._navItem && d[id] && d[id].element==pe )
                    this._navItem = d[id];
                if((c=c||o.subNavItems) && c[id] && c[id].element==pe)
                    this._parentItem = c[id];
            }
            pe = pe.parentNode;
        }
	},

	_swap: function (e,v) {
	    if(this.visible==v) return;
        this.visible = v;
        this.isInitiated = this.isInitiated || this.setPosition();
    
	    if(this.visible)
	    {
            if( this.timeout ){ clearTimeout( this.timeout ); this.timeout = null; };
            this.ref.setOn(this);
    	    this.setVisible();
        }
        else
        {
            var time = ( this.config.timeClose||50 ) - ((this.config.timeCloseLevel||1)*(this.depth()-1));
            this.timeout = setTimeout( this.setVisible.bind(this), time );
        }
    },

	_style: {0:{key:'display',0:'none',1:'block'},1:{key:'visibility',0:'hidden',1:'visible'}},

	visibleStyle : function () {
	    this._visiblestyle = this._visiblestyle || this._style[Number(this.config.visibleMode||false)];
        return this._visiblestyle;
	},
	setVisible: function () {
	    var o = this.visibleStyle();
	    if(!this.element) return;
        if( this.visible == this.getVisible()) return;
        var style = {}; style[o.key]=o[Number(this.visible)];
        this.element.setStyle( style );
    },
    
	getVisible: function () {
	    if(!this.element) return;
	    var o = this.visibleStyle();
	    return (this.element.style[o.key]!=o[0]);
	},

	setPosition: function () {
        var opener = (this._navItem ? this._navItem.element : null );
	    if(!this.element||!opener) return;
        var p = { top:null, left:null, classname:null };
        [this.config[this.depth()],this.config]
        .each( function (o,c){for(var k in o ) if(o[k]==null && c && c[k]!=undefined) o[k]=c[k];}.bind(this,p));
        if(p.classname) this.element.addClassName(p.classname.replace('{depth}',this.depth()));
        var _top = ((!this.config.relative?opener.offsetTop:0)+(p.top?(opener.offsetHeight||0):0));
        var _left = ((!this.config.relative?opener.offsetLeft:0)+(p.left?(opener.offsetWidth||0):0));
	    this.element.setStyle({
	        left:_left+'px'
	        ,top:_top+'px'
	        ,zindex:(this.config.zindex||0)+this.depth()}
	        );
	    return true;
    }
});