/*
 * JX 0.31
 * Copyright(c) 2008, Santosh Rajan
 * Author - Santosh Rajan
 * Email - santrajan@gmail.com
 * License - MIT, GPL
 */

var JX = {

    extend: function(bc, sc, o) {
        var f = function() {};
        f.prototype = sc.prototype;
        bc.prototype = new f();
        bc.prototype.constructor = bc;
        bc.superclass = sc.prototype;
        for (var m in o)
            bc.prototype[m] = o[m];
    },

    setScope: function(callback, scope) {
        return function() {
            return callback.apply(scope, arguments);
        };
    },

    namespace: function() {
        var ns, d;
        for (var i = 0; i < arguments.length; i++) {
            ns = window;
            d = arguments[i].split(".");
            for (var j in d)
                ns = ns[d[j]] = ns[d[j]] ? ns[d[j]] : {};
        };
    },
    
    isObject: function(obj) {
        return (obj && obj.constructor && obj.constructor == Object.prototype.constructor && !obj.nodeName)
            ? true : false;
    },

    isArray: function(arr) {
        return  /array/gi.test(arr.constructor) ? true : false;
    },
    
    jxTypes: {
        component: 'JX.Component',
        container: 'JX.Container',
        columncontainer: 'JX.ColumnContainer',
        panel: 'JX.Panel',
        frame: 'JX.Frame',
        roundcornerbox: 'JX.RoundCornerBox'
    }
};

JX.Component = function() {
    if (JX.isObject(arguments[0])) {
        var config = arguments[0];
        config.jxtype = config.jxtype ? config.jxtype : 'div'; // default type is div
        config.jxtype = JX.jxTypes[config.jxtype] ? 'div' : config.jxtype;
        JX.Component.superclass.init.call(this, document.createElement(config.jxtype));
        this.applyConfig(config);
    } else {
        if (arguments.length > 0)
            JX.Component.superclass.init.apply(this, arguments);
        else
            JX.Component.superclass.init.call(this, document.createElement('div'));
    }
};

JX.extend(JX.Component, jQuery, {
    applyConfig: function(config) {
        this.css({overflow: 'hidden'});
        for (var key in config) {
            var a = JX.isArray(config[key]) ? config[key] : [config[key]];
            for (var i = 0; i < a.length; i++)
                if (config.scopeThis)
                    a[i] = (typeof a[i] == 'function') ? JX.setScope(a[i], this) : a[i];
            eval('this.' + key + '.apply(this, a)');
        };
    },
    jxtype: function(jxtype) { 
        this._jxtype = jxtype;
    },
    fitWidth: function(fit) {
        this._fitWidth = fit;
        return this;
    },
    fitHeight: function(fit) {
        this._fitHeight = fit;
        return this;
    },
    scopeThis: function(s) {
        this._scope = s;
    },
    setLoadIndicator: function(url, w, h) {
        this.children().each(function() {$(this).remove()});
        this.append(new JX.Component({
            jxtype: 'image',
            attr: {src: url},
            css: {
                position: 'relative',
                top: parseInt(this.height()/2 - h/2) + 'px',
                left: parseInt(this.width()/2 - w/2) + 'px'
            }
        }));
    },
    removeLoadIndicator: function() {
        this.children().each(function() {$(this).remove()});
    },
    spacingHeight: function() {
        var ret = 0, s;
        ret += isNaN(s = parseInt(this.css('borderTopHeight'))) ? 0 : s;
        ret += isNaN(s = parseInt(this.css('borderBottomHeight'))) ? 0 : s;
        ret += isNaN(s = parseInt(this.css('paddingTop'))) ? 0 : s;
        ret += isNaN(s = parseInt(this.css('paddingBottom'))) ? 0 : s;
        return ret;
    },    
    spacingWidth: function() {
        var ret = 0, s;
        ret += isNaN(s = parseInt(this.css('borderLeftWidth'))) ? 0 : s;
        ret += isNaN(s = parseInt(this.css('borderRightWidth'))) ? 0 : s;
        ret += isNaN(s = parseInt(this.css('paddingLeft'))) ? 0 : s;
        ret += isNaN(s = parseInt(this.css('paddingRight'))) ? 0 : s;
        return ret;
    }
});


JX.Container = function() {
    this._items = [];
    JX.Container.superclass.constructor.apply(this, arguments);
};
JX.extend(JX.Container, JX.Component, {
    applyConfig: function(config) {
        JX.Container.superclass.applyConfig.apply(this, arguments);
        var c = this.citems ? this.citems : [], item, obj;
        for (var i = 0; i < c.length; i++) {
            item = c[i];
            if (JX.isObject(item)) {
                item.jxtype = item.jxtype ? item.jxtype : 'div';
                if (JX.jxTypes[item.jxtype])
                    eval('obj = new ' + JX.jxTypes[item.jxtype] + '(item)');
                else
                    obj = new JX.Component(item);
            } else
                obj = item;
            this.append(obj);
        };
    },
    append: function(comp) {
        JX.Container.superclass.append.apply(this, arguments);
        if (comp instanceof JX.Component)
            this._items.push(comp);
        return this;
    },
    items: function() {
        this.citems = Array.prototype.slice.call(arguments);
    },
    doLayout: function() {
        var h = this.height(), fitter, el;
        for (var i = 0; i < this._items.length; i++) {
            el = this._items[i];
            if (el._fitWidth)
                el.width(this.width() - el.spacingWidth());
            if (el._fitHeight) {
                fitter = el;
                h -= el.spacingHeight();
            } else {
                h -= el.outerHeight();
            }
        };
        if (fitter)
            fitter.height(h);
        for (var i in this._items) {
            el = this._items[i];
            if (el.doLayout)
                JX.setScope(el.doLayout, el)();
        };
        return this;
    },
    getItems: function() {
        return this._items;
    },
    trigger: function() {
        JX.Container.superclass.trigger.apply(this, arguments);
        if (this._items)
            for (var i = 0; i < this._items.length; i++)
                this._items[i].trigger.apply(this._items[i], arguments);
    }
});

JX.Viewport = function() {
    JX.Viewport.superclass.constructor.call(this, document.body);
    this.children().each(function() {$(this).hide()});
    this.css({padding: '0px', margin: '0px'});
    this.setSize();
    $(window).resize(JX.setScope(this.setSize, this));
    if (JX.isObject(arguments[0])) {
        this.applyConfig(arguments[0]);
        this.setSize();
    };
};
JX.extend(JX.Viewport, JX.Container, {
    setSize: function() {
        this.height($(window).height());
        this.width($(window).width())
        this.doLayout();
    }
});

JX.ColumnContainer = function() {
    if (arguments.length > 0)
        JX.ColumnContainer.superclass.constructor.apply(this, arguments);
    else
        JX.ColumnContainer.superclass.constructor.call(this, {});
};
JX.extend(JX.ColumnContainer, JX.Container, {
    applyConfig: function(config) {
        $('<table border="0px" cellspacing="0px" cellpadding="0px"><tr></tr></table>').appendTo(this);
        JX.ColumnContainer.superclass.applyConfig.apply(this, arguments);
    },
    append: function(comp) {
        $('tr:first', this).append($(document.createElement('td')).append(comp));
        if (comp instanceof JX.Component)
            this._items.push(comp);
        return this;
    },
    doLayout: function() {
        var height = this.height(), fitter, el;
        var width = this.width();
        for (var i = 0; i < this._items.length; i++) {
            el = this._items[i];
            if (el._fitHeight)
                el.height(height - el.spacingHeight());
            if (el._fitWidth) {
                fitter = el;
                width -= el.spacingWidth();
            } else
                width -= el.outerWidth();
        };
        if (fitter)
            fitter.width(width);
        for (var i = 0; i < this._items.length; i++) {
            el = this._items[i];
            if (el.doLayout)
                JX.setScope(el.doLayout, el)();
        };
        return this;
    }
});


JX.Panel = function(config) {
    JX.Panel.superclass.constructor.apply(this, arguments);
    if (this._title)
        JX.Panel.superclass.append.call(this, this._title);
    if (this._body)
        JX.Panel.superclass.append.call(this, this._body);
};
JX.extend(JX.Panel, JX.Container, {
    append: function(comp) {
        this._body.append(comp);
        return this;
    },
    title: function(title) {
        this._title = new JX.Component(title);
    },
    body: function(body) {
        this._body = new JX.Container(body);
    },
    getItems: function() {
        return this._body._items;
    },
    text: function(text) {
        this._body.text(text);
        return this;
    },
    html: function(html) {
        this._body.html(html);
        return this;
    }
});


JX.Frame = function(config) {
    this._body = new JX.Container({});
    JX.Frame.superclass.constructor.apply(this, arguments);
    var factory = function(l, c, r) {
        return new JX.ColumnContainer()
            .append(l)
            .append(c)
            .append(r);
    };
    JX.Frame.superclass.append.call(this, factory(this._topLeft, this._topCenter, this._topRight));
    JX.Frame.superclass.append.call(this, factory(this._middleLeft, this._body, this._middleRight));
    JX.Frame.superclass.append.call(this, factory(this._bottomLeft, this._bottomCenter, this._bottomRight));
    this._items[1].fitHeight(true).fitWidth(true);
};
JX.extend(JX.Frame, JX.Container, {
    topLeft: function(c) {
        this._topLeft = new JX.Component(c);
    },
    topCenter: function(c) {
        this._topCenter = new JX.Component(c);
    },
    topRight: function(c) {
        this._topRight = new JX.Component(c);
    },
    middleLeft: function(c) {
        this._middleLeft = new JX.Component(c);
    },
    body: function(c) {
        this._body.applyConfig(c);
    },
    middleRight: function(c) {
        this._middleRight = new JX.Component(c);
    },
    bottomLeft: function(c) {
        this._bottomLeft = new JX.Component(c);
    },
    bottomCenter: function(c) {
        this._bottomCenter = new JX.Component(c);
    },
    bottomRight: function(c) {
        this._bottomRight = new JX.Component(c);
    },
    append: function(comp) {
        this._body.append(comp);
        return this;
    },
    getItems: function() {
        return this._body._items;
    },
    text: function(text) {
        this._body.text(text);
        return this;
    },
    html: function(html) {
        this._body.html(html);
        return this;
    }
});

JX.RoundCornerBox = function(config) {
    var imagepath = config.imagepath;
    delete config.imagepath;
    var radius = config.radius;
    delete config.radius;
    var color = config.backgroundColor;
    delete config.backgroundColor;
    var boxConfig = jQuery.extend({
        topLeft: {
            width: radius,
            height: radius,
            css: {background: 'url(' + imagepath + ') no-repeat top left'}
        },
        topCenter: {
            height: radius,
            fitWidth: true,
            css: {background: color}
        },
        topRight: {
            width: radius,
            height: radius,
            css: {background: 'url(' + imagepath + ') no-repeat top right'}
        },
        middleLeft: {
            width: radius,
            fitHeight: true,
            css: {background: color}
        },
        middleRight: {
            width: radius,
            fitHeight: true,
            css: {background: color}
        },
        bottomLeft: {
            width: radius,
            height: radius,
            css: {background: 'url(' + imagepath + ') no-repeat bottom left'}
        },
        bottomCenter: {
            height: radius,
            fitWidth: true,
            css: {background: color}
        },
        bottomRight: {
            width: radius,
            height: radius,
            css: {background: 'url(' + imagepath + ') no-repeat bottom right'}
        }
   }, config);
   JX.RoundCornerBox.superclass.constructor.call(this, boxConfig);
};
JX.extend(JX.RoundCornerBox, JX.Frame);
