ark.namespace('widget.Collapsable');

(function() {
    var Dom = YAHOO.util.Dom,
        Anim = YAHOO.util.Anim,
        Motion = YAHOO.util.Motion,
        Easing = YAHOO.util.Easing
        Event = YAHOO.util.Event
        CustomEvent = YAHOO.util.CustomEvent;
        
ark.widget.Collapsable = function(id) {
    this.id = id;
    this.elt = Dom.get(this.id);
    this.collapsed = false;
    this.animated = false;

    this.collapse_on_click = false;
    this.menu = false;
    this.no_constraint = false;
    this.right_justify = false;
    this.up = false;

    this.content_url = null;
    this.content_key = null;

    this._content_loaded = false;
    this._content_replaced = false;
    this._content_cache = null;
    this._content = null;
    this._content_dirty = true;

    this._menu_init = false;

    this._overflow_hack = false;

    this._verbose = false;
    this._log = function(msg) {
        if( "console" in window ) {
            if( this._verbose ) {
                console.log(msg);
            }
        }
    }

    this.expand = function(target) {
        if(!this.animated && this.collapsed) {
            this._log(this.id+' expand called');
            this._init_menu();
            this._init_lazy();
            this._load_lazy();
            this.animated = true;
            this.collapsed = false;
            Dom.setStyle(this.elt,'height','0px');
            Dom.setStyle(this.elt,'display','block');

            if( target && this.menu ) {
                var x = Dom.getX(target);
                if( this.right_justify ) {
                    x = x - this.elt.scrollWidth + target.scrollWidth;
                }
                var y = Dom.getY(target) + target.scrollHeight;
                if( this.up ) {
                    y -= target.scrollHeight;
                }
                Dom.setX(this.elt,x);
                Dom.setY(this.elt,y);
            }
            
            if( this.menu && this.up ) {
                var hAttributes = { points: { to: [x,y-this.elt.scrollHeight] }, height: { from: 0, to: this.elt.scrollHeight } };
                var oAnim = new Motion(this.elt,hAttributes,0.5,Easing.backOut);
            } else {
                var hAttributes = { height: { from: 0, to: this.elt.scrollHeight } };
                var oAnim = new Anim(this.elt,hAttributes,0.5,Easing.backOut);
            }
            this.ExpandingEvent.fire();
            this._log(this.id+' ExpandingEvent fired');
            oAnim.onComplete.subscribe(this._doneExpandAnim,this,true);
            oAnim.animate();
        }
    }

    this._doneExpandAnim = function(e,f,obj) {
        obj._log(this.id+' done with animation');
        obj._log(' * loaded   = '+obj._content_loaded);
        obj._log(' * replaced = '+obj._content_replaced);
        if( obj.content_url && obj._content_loaded && !obj._content_replaced ) {
            obj._content_replaced = true;
            obj.set_content(obj._content._html);
        } else {
            if( obj._overflow_hack ) {
                Dom.setStyle(obj.elt,'overflow','visible');
            }
            obj.ExpandedEvent.fire();
            this._log(this.id+' ExpandedEvent fired');
            obj.animated = false;
        }
    }
 
    this.collapse = function(target) {
        if(!this.animated && !this.collapsed) {
            this._log(this.id+' collapse called');
            this._init_menu();
            this.animated = true;
            this.collapsed = true;
            Dom.setStyle(this.elt,'overflow','hidden');

            if( target && this.menu && this.up ) {
                var x = Dom.getX(target);
                if( this.right_justify ) {
                    x = x - this.elt.scrollWidth + target.scrollWidth;
                }
                var y = Dom.getY(target);
 
                var hAttributes = { points: { to: [x,y] },height: { from: this.elt.scrollHeight, to: 0 } };
                var oAnim = new Motion(this.elt,hAttributes,0.5);
            } else {
                var hAttributes = { height: { from: this.elt.scrollHeight, to: 0 } };
                var oAnim = new Anim(this.elt,hAttributes,0.5,Easing.backOut);
            }
            var doneAnim = function(e,f,obj) {
                Dom.setStyle(obj.elt,'display','none');
                obj.CollapsedEvent.fire();
                obj._log(obj.id+' CollapsedEvent fired');
                obj.animated = false;
            };
            this.CollapsingEvent.fire();
            this._log(this.id+' CollapsingEvent fired');
            oAnim.onComplete.subscribe(doneAnim,this);
            oAnim.animate();
        }
    }

    this.toggle = function(target) {
        if( this.collapsed ) {
            this.expand(target);
        } else {
            this.collapse(target);
        }
    }

    this.show = function() {
        Dom.setStyle(this.elt,'display','block');
        if( this._overflow_hack ) {
            Dom.setStyle(this.elt,'overflow','visible');
        }
        this.collapsed = false;
        this.ExpandedEvent.fire();
        this._log(this.id+' ExpandedEvent fired');
    }

    this.hide = function() {
        Dom.setStyle(this.elt,'display','none');
        this.collapsed = true;
        this.CollapsedEvent.fire();
        this._log(this.id+' CollapsedEvent fired');
    }

    this._inside_click = function(oTarget) {
        if( oTarget && oTarget.id != this.id ) {
            return this._inside_click(oTarget.parentNode);
        } else if( oTarget && oTarget.id == this.id ) {
            return true;
        } else {
            return false;
        }
    }

    this._click = function(e,obj) {
        if( obj.collapse_on_click ) {
            var oTarget = Event.getTarget(e);
            var bInside = obj._inside_click(oTarget);
            if( !bInside ) {
                obj.collapse();
            }
        }
    }

    this._init_menu = function() {
        if(this.menu && !this._menu_init) {
            this._menu_init = true;
            Dom.setStyle(this.elt,'position','absolute');
            Dom.setStyle(this.elt,'zIndex','100');

            if( this.no_constraint ) {
                // NEED TO MOVE THE NODE AT THE ROOT JUST IN CASE
                this.elt.parentNode.removeChild(this.elt);
                document.body.appendChild(this.elt);
            }
        }
    }

    this._init_lazy = function() {
        if( this.content_url ) {
           if( !this.content_key ) {
                this.content_key = this.id;
           }
       }
    }

    this._load_lazy = function() {
        if( this._content_cache && this.content_url && !this._content_loaded ) {
            this._content_cache.load(this.content_key,this.content_url);
        }
    }

    this._content_loaded_cb = function(type,args) {
        this._log(this.id+' content loaded');
        var oContent = args[0];
        this._content = oContent;
        this._content_loaded = true;
        if( !this.animated && oContent._html ) {
            this._content_replaced = true;
            this.set_content(oContent._html);
        }
    }

    this._content_failed_cb = function(type,args) {
        this._log(this.id+' content failed');
        this.NoContentEvent.fire();
        this._log(this.id+' NoContentEvent fired');
    }

    this.refresh_content = function(bForce) {
        this._init_lazy();
        this._content_loaded = false;
        this._content_replaced = false;
        this._content_dirty = true;
        if( bForce && this._content_cache ) {
            this._content_cache.clearCache(this.content_key);
        }
        this._load_lazy();
    }

    this.refreshContent = function(bForce) {
        this.refresh_content(bForce);
    }

    this._log_dimensions = function(elt) {
        var msg = elt.tagName+' '+elt.id;
        msg += ' (scroll:'+elt.scrollWidth+'x'+elt.scrollHeight+')';
        msg += ' (offset:'+elt.offsetWidth+'x'+elt.offsetHeight+')';
        this._log(msg);
    }

    this._check_rendered = function(node,tracker) {
        var i = tracker['counter'];
        this._log_dimensions(node);
        this._log_dimensions(node.childNodes[0]);
        if( node.childNodes[0].tagName != 'DIV' ) {
            var tmp = node;
        } else {
            var tmp = node.childNodes[0];
        }
        tracker['size'][i] = {  height: tmp.scrollHeight, 
                                width: tmp.scrollWidth };
        tracker['other'][i] = { height: tmp.offsetHeight,
                                width: tmp.offsetWidth };
        tracker['counter'] = tracker['counter'] + 1;
        if( i > 1 ) {
            var w1 = tracker['size'][i-2]['width'];
            var h1 = tracker['size'][i-2]['height'];

            var w2 = tracker['size'][i-1]['width'];
            var h2 = tracker['size'][i-1]['height'];

            var w3 = tracker['size'][i]['width'];
            var h3 = tracker['size'][i]['height'];

            /*
            this._log(i+' 1: '+w1+'x'+h1+' 2:'+w2+'x'+h2+' 3: '+w3+'x'+h3);

            var w21 = tracker['other'][i-2]['width'];
            var h21 = tracker['other'][i-2]['height'];

            var w22 = tracker['other'][i-1]['width'];
            var h22 = tracker['other'][i-1]['height'];

            var w23 = tracker['other'][i]['width'];
            var h23 = tracker['other'][i]['height'];

            this._log(i+' 1: '+w21+'x'+h21+' 2:'+w22+'x'+h22+' 3: '+w23+'x'+h23+' < offset');
            */


            if( h1 != h2 && h2 != h3) {
                // try again then
                var obj = this;
                var fn = function() {
                    obj._check_rendered(node,tracker);
                }
                setTimeout(fn,100);
            } else {
                var end = tmp.scrollHeight;
                var hAttributes = { height: { to: end } };
                var oAnim = new Anim(this.elt,hAttributes,0.5,Easing.backOut);

                if(!tracker['no_event'] && !this.animated) {
                    this.ExpandingEvent.fire();
                    this._log(this.id+' ExpandingEvent fired');
                }

                this.animated = true;
                this._content_dirty = false;

                oAnim.onComplete.subscribe(this._doneExpandAnim,this,true);
                oAnim.animate();
            }
        } else {
            var obj = this;
            var fn = function() {
                obj._check_rendered(node,tracker);
            }
            setTimeout(fn,100);
        }
    }

    this._set_inner_html = function(element,html) {
        var newElement = element.cloneNode(false);
        newElement.innerHTML = html;
        element.parentNode.replaceChild(newElement, element);
        this.elt = newElement;
    }

    this.set_content = function(html) {
        this._log(this.id+' set_content');
        Dom.setStyle(this.elt,'overflow','hidden');
        this._set_inner_html(this.elt,html);
        var obj = this;
        var tracker = {counter: 0, size:[], other:[]};
        var tmp = this.elt;
        var fn = function() {
            obj._check_rendered(tmp,tracker);
        }
        setTimeout(fn,100);
    }

    this.setContent = function(html) {
        this.set_content(html);
    }

    this.resize = function() {
        this._log(this.id+' forced resize');
        Dom.setStyle(this.elt,'overflow','hidden');
        if( false ) {
            Dom.setStyle(this.elt,'height','auto');
            var tmp = this.elt;
            var obj = this;
            var tracker = {counter: 0, size:[], no_event: true};
            var fn = function() {
                obj._check_rendered(tmp,tracker);
            }
            setTimeout(fn,100);
        } else {
            var hAttributes = { height: { to: this.elt.scrollHeight } };
            var oAnim = new Anim(this.elt,hAttributes,0.5,Easing.backOut);
            var fn = function(e,f,obj) {
                if( obj._overflow_hack ) {
                    Dom.setStyle(obj.elt,'overflow','visible');
                }
            }
            oAnim.onComplete.subscribe(fn,this,true);
            oAnim.animate();
        } 
    }

    this.ExpandedEvent   = new CustomEvent('ExpandedEvent',this);
    this.ExpandingEvent  = new CustomEvent('ExpandingEvent',this);
    this.CollapsedEvent  = new CustomEvent('CollapsedEvent',this);
    this.CollapsingEvent = new CustomEvent('CollapsingEvent',this);
    this.NoContentEvent  = new CustomEvent('NoContentEvent',this);

    var sDisplay = Dom.getStyle(this.id,'display');
    if( sDisplay == 'none' ) {
        this.collapsed = true;
        Dom.setStyle(this.elt,'overflow','hidden');
        Dom.setStyle(this.elt,'height','0px');
   } 

   Event.on(window.document,'click',this._click,this);
   if( !this._content_cache ) {
        if (ark.util && ark.util.LazyContent) {
            this._content_cache = new ark.util.LazyContent();
            this._content_cache.LoadedEvent.subscribe(this._content_loaded_cb,this,true);
            this._content_cache.FailedEvent.subscribe(this._content_failed_cb,this,true);
            this._content_cache.TimedOutEvent.subscribe(this._content_failed_cb,this,true);
        }
   }
 
}

})();
