Ext.ns('Ext.ux');

Ext.ux.FluidLayout = function(target, config) {
    var tCalc   = false;
    var xTarget = Ext.get(target);

    if (!xTarget) {
        throw 'Invalid target';
    }

    var xPublic = Ext.extend(Ext.util.Observable, {
        constructor: function(config) {
            config = config || {};
            Ext.apply(this, config);

            Ext.ux.Menu.superclass.constructor.call(this, config);

            this.addEvents(
                'beforeResize'
              , 'afterResize'
            );

            Ext.fly(window).on('resize', prepCalculate);
        }

      , animate:        true
      , checkLayout:    function() { calculate(); }
      , constraint:     false
      , duration:       0.5
      , easing:         'easeOut'
      , getWindowSize:  function() {
            var myWidth = 0, myHeight = 0;
            if( typeof( window.innerWidth ) == 'number' ) {
                //Non-IE
                myWidth = window.innerWidth;
                myHeight = window.innerHeight;
            } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
                //IE 6+ in 'standards compliant mode'
                myWidth = document.documentElement.clientWidth;
                myHeight = document.documentElement.clientHeight;
            } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
                //IE 4 compatible
                myWidth = document.body.clientWidth;
                myHeight = document.body.clientHeight;
            }
    
            return [myWidth, myHeight];
        }
    });

    var triggerResize = function() {
        api.fireEvent('afterResize', xTarget, api);
    }

    var prepCalculate = function() {
        if (false != tCalc) {
            clearTimeout(tCalc);
        }
        tCalc = setTimeout(calculate, 350);
    }

    var calculate = function(config) {
        tCalc = false;

        config = config || {};
        Ext.applyIf(config, api);
        config.callback = triggerResize;

        var iFloor   = Ext.getBody().getHeight() - xTarget.getBottom();
        var iMax     = api.getWindowSize()[1] - xTarget.getTop() - iFloor;
        var iCompare = false;

        if (api.constraint) {
            if (api.constraint.isComposite) {
                for (var i = 0, len = api.constraint.getCount(); i < len; i++) {
                    var xCompare = api.constraint.item(i);

                    var iCheck = xCompare.getOffsetsTo(xTarget)[1] + xCompare.getHeight();
                    if (iCompare == false || iCheck > iCompare) {
                        iCompare = iCheck;
                    }
                }
            } else {
                iCompare = api.constraint.getHeight();
            }
        }

        if (iCompare < iMax) {
            iMax = iCompare;
        }

        api.fireEvent('beforeResize', xTarget, api);
        if (api.animate) {
            xTarget.scale(null, iMax, config);
        } else {
            xTarget.setHeight(iMax);
            triggerResize();
        }
    }

    var api = new xPublic(config);
    return api;
};