/********
 * This file is part of the Coolite Toolkit.
 * 
 * The Coolite Toolkit is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * The Coolite Toolkit is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with the Coolite Toolkit.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * @version: 0.7.0 - Community Edition (GPL 3.0 License)
 * @author: Coolite Inc. http://www.coolite.com/
 * @date: 2008-12-22
 * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
 * @license: See license.txt and http://www.coolite.com/license/. 
 * @website: http://www.coolite.com/
 ********/

Ext.namespace("Coolite", "Coolite.Ext");

Coolite.Ext.Version = "0.7.0";

Ext.isEmptyObj = function(o) {
    if (!(!Ext.isEmpty(o) && typeof o == "object")) { return false; }
    for (var p in o) { return false; }
    return true;
};

Coolite.Ext.Viewport = Ext.extend(Ext.Container, {
    initComponent: function() {
        Coolite.Ext.Viewport.superclass.initComponent.call(this);
        var html = document.getElementsByTagName("html")[0];
        html.className += " x-viewport";
        html.style.height = "100%";
        this.el = Ext.get(document.forms[0]);
        this.el.setHeight = this.el.setWidth = this.el.setSize = Ext.emptyFn;
        this.el.dom.scroll = "no";
        this.allowDomMove = false;
        this.autoWidth = this.autoHeight = true;
        Ext.EventManager.onWindowResize(this.fireResize, this);
        this.renderTo = this.el;
        Ext.getBody().applyStyles({
            overflow: "hidden",
            margin: "0",
            padding: "0",
            border: "0px none",
            height: "100%"
        });
        this.el.applyStyles({ height: "100%", width: "100%" });
    },

    fireResize: function(w, h) {
        this.fireEvent("resize", this, w, h, w, h);
    }
});

Ext.reg("cooliteviewport", Coolite.Ext.Viewport);

Coolite.Ext.AnchorLayout = Ext.extend(Ext.layout.AnchorLayout, {
    monitorResize: true,
    getAnchorViewSize: function(ct, target) {
    return ((target.dom == Ext.getBody().dom) || (target.dom == document.forms[0])) ?
                   target.getViewSize() : target.getStyleSize();
    }
});

Ext.reg("cooliteanchor", Coolite.Ext.AnchorLayout);

Ext.Container.LAYOUTS.cooliteanchor = Coolite.Ext.AnchorLayout;

Coolite.Ext.FitLayout = Ext.extend(Ext.layout.FitLayout, {
    onLayout: function(ct, target) {
        Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target);
        if (!this.container.collapsed) {
            if (target.dom == Ext.getBody().dom || target.dom == document.forms[0]) {
                this.setItemSize(this.activeItem || ct.items.itemAt(0), Ext.getBody().getViewSize());
            } else {
                this.setItemSize(this.activeItem || ct.items.itemAt(0), target.getStyleSize());
            }
        }
    }
});

Ext.reg("coolitefit", Coolite.Ext.FitLayout);

Ext.Container.LAYOUTS.coolitefit = Coolite.Ext.FitLayout;

Coolite.Ext.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
    monitorResize: true,
    extraCls: "x-column",
    scrollOffset: 0,
    margin: 0,
    split: false,
    fitHeight: false,

    // private
    isValidParent: function(c, target) {
        return c.getEl().dom.parentNode == this.innerCt.dom;
    },

    renderAll: function(ct, target) {
        if (this.split && !this.splitBars) {
            this.splitBars = [];
            this.margin = 5;
        }

        Coolite.Ext.ColumnLayout.superclass.renderAll.apply(this, arguments);
    },

    // private
    onLayout: function(ct, target) {
        var cs = ct.items.items, len = cs.length, c, cel, i;

        if (!this.innerCt) {
            target.addClass("x-column-layout-ct");
            this.innerCt = target.createChild({ cls: "x-column-inner" });
            this.innerCt.createChild({ cls: "x-clear" });
        }
        this.renderAll(ct, this.innerCt);

        var size = Ext.isIE && ((target.dom != Ext.getBody().dom) && (target.dom != document.forms[0])) ? target.getStyleSize() : target.getViewSize();

        if (size.width < 1 && size.height < 1) { // display none?
            return;
        }

        var w = size.width - target.getPadding("lr") - this.scrollOffset,
            h = size.height - target.getPadding("tb");
        this.availableWidth = w;
        var pw = this.availableWidth;

        if (this.split) {
            this.minWidth = Math.min(pw / len, 100);
            this.maxWidth = pw - ((this.minWidth + 5) * (len ? (len - 1) : 1));
        }

        if (this.fitHeight) {
            this.innerCt.setSize(w, h);
        }
        else {
            this.innerCt.setWidth(w);
        }

        var lastProportionedColumn;
        for (i = 0; i < len; i++) {
            c = cs[i];
            cel = c.getEl();

            if (this.margin && (i < (len - 1))) {
                cel.setStyle("margin-right", this.margin + "px");
            }
            if (c.columnWidth) {
                lastProportionedColumn = i;
            } else {
                pw -= (c.getSize().width + cel.getMargins("lr"));
            }
        }

        var remaining = (pw = pw < 0 ? 0 : pw);

        var splitterPos = 0, cw;
        for (i = 0; i < len; i++) {
            c = cs[i];
            cel = c.getEl();
            if (c.columnWidth) {
                cw = (i == lastProportionedColumn) ? remaining : Math.floor(c.columnWidth * pw);
                if (this.fitHeight) {
                    c.setSize(cw - cel.getMargins("lr"), h);
                }
                else {
                    c.setSize(cw - cel.getMargins("lr"));
                }
                //c.setSize(cw - cel.getMargins("lr"), this.fitHeight ? h : null);
                remaining -= cw;
            } else if (this.fitHeight) {
                c.setHeight(h);
            }

            if (this.split) {
                cw = cel.getWidth();

                if (i < (len - 1)) {
                    splitterPos += cw;
                    if (this.splitBars[i]) {
                        this.splitBars[i].el.setHeight(h);
                    } else {
                        this.splitBars[i] = new Ext.SplitBar(this.innerCt.createChild({
                            cls: "x-layout-split x-layout-split-west",
                            style: {
                                top: "0px",
                                left: splitterPos + "px",
                                height: h + "px"
                            }
                        }), cel);
                        this.splitBars[i].index = i;
                        this.splitBars[i].leftComponent = c;
                        this.splitBars[i].addListener("resize", this.onColumnResize, this);
                        this.splitBars[i].minSize = this.minWidth;
                    }

                    splitterPos += this.splitBars[i].el.getWidth();
                }

                delete c.columnWidth;
            }
        }

        if (this.split) {
            this.setMaxWidths();
        }
    },

    //  On column resize, explicitly size the Components to the left and right of the SplitBar
    onColumnResize: function(sb, newWidth) {
        if (sb.dragSpecs.startSize) {
            sb.leftComponent.setWidth(newWidth);
            var items = this.container.items.items;
            var expansion = newWidth - sb.dragSpecs.startSize;
            for (var i = sb.index + 1, len = items.length; expansion && i < len; i++) {
                var c = items[i];
                var w = c.el.getWidth();
                newWidth = w - expansion;
                if (newWidth < this.minWidth) {
                    c.setWidth(this.minWidth);
                } else if (newWidth > this.maxWidth) {
                    expansion -= (newWidth - this.maxWidth);
                    c.setWidth(this.maxWidth);
                } else {
                    c.setWidth(c.el.getWidth() - expansion);
                    break;
                }
            }
            this.setMaxWidths();
        }
    },

    setMaxWidths: function() {
        var items = this.container.items.items;

        var spare = items[items.length - 1].el.dom.offsetWidth - 100;

        for (var i = items.length - 2; i > -1; i--) {
            var sb = this.splitBars[i], sbel = sb.el, c = items[i], cel = c.el;
            var itemWidth = cel.dom.offsetWidth;
            sbel.setStyle("left", (cel.getX() - Ext.fly(cel.dom.parentNode).getX() + itemWidth) + "px");
            sb.maxSize = itemWidth + spare;
            spare = itemWidth - 100;
        }
    },

    onResize: function() {
        if (this.split) {
            var items = this.container.items.items;
            if (items[0].rendered) {
                var tw = 0, c;
                for (var i = 0; i < items.length; i++) {
                    c = items[i];
                    tw += c.el.getWidth() + c.el.getMargins("lr");
                }
                for (var j = 0; j < items.length; j++) {
                    c = items[j];
                    c.columnWidth = (c.el.getWidth() + c.el.getMargins("lr")) / tw;
                }
            }
        }
        Coolite.Ext.ColumnLayout.superclass.onResize.apply(this, arguments);
    }
});
Ext.reg("coolitecolumn", Coolite.Ext.ColumnLayout);
Ext.Container.LAYOUTS.coolitecolumn = Coolite.Ext.ColumnLayout;

Ext.apply(Ext.lib.Ajax, {
    serializeForm: function(form) {
        if (typeof form == "string") {
            form = (document.getElementById(form) || document.forms[form]);
        }

        var el, name, val, disabled, data = "", hasSubmit = false;
        hasSubmit = form.ignoreAllSubmitFields || false;
        for (var i = 0; i < form.elements.length; i++) {
            el = form.elements[i];
            disabled = form.elements[i].disabled;
            name = form.elements[i].name;
            val = form.elements[i].value;

            if (!disabled && name) {
                switch (el.type) {
                    case "select-one":
                    case "select-multiple":
                        for (var j = 0; j < el.options.length; j++) {
                            if (el.options[j].selected) {
                                if (Ext.isIE) {
                                    data += encodeURIComponent(name) + "=" + encodeURIComponent(el.options[j].attributes.value.specified ? el.options[j].value : el.options[j].text) + "&";
                                } else {
                                    data += encodeURIComponent(name) + "=" + encodeURIComponent(el.options[j].hasAttribute("value") ? el.options[j].value : el.options[j].text) + "&";
                                }
                            }
                        }
                        break;
                    case "radio":
                    case "checkbox":
                        if (el.checked) {
                            data += encodeURIComponent(name) + "=" + encodeURIComponent(val) + "&";
                        }
                        break;
                    case "file":
                    case undefined:
                    case "reset":
                    case "button":
                        break;
                    case "submit":
                        if (hasSubmit === false) {
                            data += encodeURIComponent(name) + "=" + encodeURIComponent(val) + "&";
                            hasSubmit = true;
                        }
                        break;
                    default:
                        data += encodeURIComponent(name) + "=" + encodeURIComponent(val) + "&";
                        break;
                }
            }
        }
        data = data.substr(0, data.length - 1);
        return data;
    }
});


Coolite.Ext.on = function(target, eventName, handler, scope, mode, cfg) {
    var el = target;
    if (typeof target == "string") {
        el = Ext.get(target);
    }

    if (!Ext.isEmpty(el)) {
        if (mode && mode == "client") {
            el.on(eventName, handler.fn, scope, handler);
        } else {
            el.on(eventName, handler, scope, cfg);
        }
    }
};


Ext.form.Hidden.override({
    setValue: function(v) {
        this.value = v;
        var temp = this.el.dom.value;
        if (this.rendered) {
            this.el.dom.value = (v === null || v === undefined ? "" : v);
            this.validate();
        }
        if (this.el.dom.value != temp) {
            this.fireEvent("change");
        }
    }
});

Ext.form.Label.override({
    onRender: function(ct, position) {
        if (!this.el) {
            this.el = document.createElement(this.forId ? "label" : "span");
            this.el.id = this.getId();
            this.el.innerHTML = this.text ? Ext.util.Format.htmlEncode(this.text) : (this.html || "");
            if (this.forId) {
                this.el.setAttribute("htmlFor", this.forId);
            }
        }
        Ext.form.Label.superclass.onRender.call(this, ct, position);
    },
    getText: function(encode) {
        return this.rendered ? encode === true ? Ext.util.Format.htmlEncode(this.el.dom.innerHTML) : this.el.dom.innerHTML : this.text;
    }
});

Ext.form.ComboBox.prototype.onRender = Ext.form.ComboBox.prototype.onRender.createSequence(function(el) {
    this.getEl().dom.setAttribute("name", this.uniqueName || this.id);
    this.on("focus", function(el) {
        this.oldValue = this.getValue();
        var t = this.getEl().dom.value.trim();
        this.oldText = (t === this.emptyText) ? "" : t;
    });
});

Ext.form.ComboBox.prototype.onBlur = Ext.form.ComboBox.prototype.onBlur.createInterceptor(function(el) {
    var t = this.getEl().dom.value.trim(), v = this.getValue();
    this.changed = false;
    if (this.oldValue !== v || (t !== this.oldText && t !== this.emptyText)) {
        if (!Ext.isEmpty(this.selValue) && this.selText != t && this.selValue == this.getValue()) {
            this.hiddenField.value = "";
        }

        var val = this.el.dom.value,
            r = this.findRecordByText(this.displayField, val);

        this.setValue(!Ext.isEmpty(r) ? r.data[this.valueField] : val);

        var hf = Ext.get(this.id + "_SelIndex");
        if (!Ext.isEmpty(hf)) {
            hf.dom.value = this.getSelectedIndex();
        }  
        this.changed = true;
    }
});

Ext.form.ComboBox.override({
    getText: function() {
        return this.el.getValue();
    },
    getSelectedItem: function() {
        return { text: this.getText(), value: this.getValue() };
    },
    initSelect: false,
    setValueAndFireSelect: function(v) {
        this.setValue(v);

        var r = this.findRecord(this.valueField, v);

        if (!Ext.isEmpty(r)) {
            var index = this.store.indexOf(r);
            this.initSelect = true;
            this.fireEvent("select", this, r, index);
            this.initSelect = false;
        }
    },
    findRecordByText: function(prop, text) {
        var record;
        if (this.store.getCount() > 0) {
            this.store.each(function(r) {
                if (r.data[prop] == text) {
                    record = r;
                    return false;
                }
            });
        }
        return record;
    },
    findRecordEx: function(prop, value) {
        if (this.store.snapshot && this.store.snapshot.getCount() > 0) {
            var record;
            if (this.store.snapshot.getCount() > 0) {
                this.store.snapshot.each(function(r) {
                    if (r.data[prop] == value) {
                        record = r;
                        return false;
                    }
                });
            }
            return record;
        }

        return this.findRecord(prop, value);
    },
    indexOfEx: function(record) {
        if (this.store.snapshot && this.store.snapshot.getCount() > 0) {
            return this.store.snapshot.indexOf(record);
        }

        return this.store.data.indexOf(record);
    },
    getSelectedIndex: function() {
        var r = this.findRecordEx(this.valueField, this.getValue());
        return (!Ext.isEmpty(r)) ? this.indexOfEx(r) : -1;
    },
    initEvents: function() {
        Ext.form.ComboBox.superclass.initEvents.call(this);

        this.keyNav = new Ext.KeyNav(this.el, {
            "up": function(e) {
                this.inKeyMode = true;
                this.selectPrev();
            },

            "down": function(e) {
                if (!this.isExpanded()) {
                    this.onTriggerClick();
                } else {
                    this.inKeyMode = true;
                    this.selectNext();
                }
            },

            "enter": function(e) {
                this.onViewClick();
                this.delayedCheck = true;
                this.unsetDelayCheck.defer(10, this);
            },

            "esc": function(e) {
                this.collapse();
            },

            "tab": function(e) {
                this.monitorTab = false;
                this.onViewClick(false);
                this.triggerBlur();
                return true;
            },

            scope: this,

            doRelay: function(foo, bar, hname) {
                if (hname == 'down' || this.scope.isExpanded()) {
                    return Ext.KeyNav.prototype.doRelay.apply(this, arguments);
                }
                return true;
            },

            forceKeyDown: true
        });
        this.queryDelay = Math.max(this.queryDelay || 10,
                    this.mode == 'local' ? 10 : 250);
        this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);
        if (this.typeAhead) {
            this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this);
        }
        if (this.editable !== false) {
            this.el.on("keyup", this.onKeyUp, this);
        }
        if (this.forceSelection) {
            this.on('blur', this.doForce, this);
        }
    },
    onSelect: function(record, index) {
        if (this.fireEvent('beforeselect', this, record, index) !== false) {
            this.setValue(record.data[this.valueField || this.displayField]);
            this.collapse();

            var hf = Ext.get(this.id + "_SelIndex");
            if (!Ext.isEmpty(hf)) {
                hf.dom.value = this.getSelectedIndex();
            }

            this.selValue = this.getValue();
            this.selText = this.el.dom.value;

            this.fireEvent('select', this, record, index);
        }
    }
});

Ext.ns("Ext.ux.layout");

Ext.ux.layout.CenterLayout = Ext.extend(Coolite.Ext.FitLayout, {
    // private
    setItemSize: function(item, size) {
        this.container.addClass("ux-layout-center");
        item.addClass("ux-layout-center-item");
        if (item && size.height > 0) {
            if (item.width) {
                size.width = item.width;
            }
            item.setSize(size);
        }
    }
});
Ext.Container.LAYOUTS["ux.center"] = Ext.ux.layout.CenterLayout;

Ext.ux.RowLayout = Ext.extend(Ext.layout.ContainerLayout, {
    monitorResize: true,
    //extraCls: "x-column",
    scrollOffset: 0,
    margin: 0,
    split: false,

    // private
    isValidParent: function(c, target) {
        return c.getEl().dom.parentNode == this.innerCt.dom;
    },

    renderAll: function(ct, target) {
        if (this.split && !this.splitBars) {
            this.splitBars = [];
            this.margin = 5;
        }

        Ext.ux.RowLayout.superclass.renderAll.apply(this, arguments);
    },

    // private
    onLayout: function(ct, target) {
        var cs = ct.items.items, len = cs.length, c, cel, i;

        if (!this.innerCt) {
            target.addClass("x-column-layout-ct");
            this.innerCt = target.createChild({ cls: "x-column-inner" });
            this.innerCt.createChild({ cls: "x-clear" });
        }
        this.renderAll(ct, this.innerCt);

        var size = Ext.isIE && ((target.dom != Ext.getBody().dom) && (target.dom != document.forms[0])) ? target.getStyleSize() : target.getViewSize();

        if (size.height < 1 && size.height < 1) { // display none?
            return;
        }

        var w = size.height - target.getPadding("tb");
        this.availableHeight = w;
        var pw = this.availableHeight;

        if (this.split) {
            this.minHeight = Math.min(pw / len, 100);
            this.maxHeight = pw - ((this.minHeight + 5) * (len ? (len - 1) : 1));
        }

        this.innerCt.setHeight(w);

        var lastProportionedColumn;
        for (i = 0; i < len; i++) {
            c = cs[i];
            cel = c.getEl();

            if (this.margin && (i < (len - 1))) {
                cel.setStyle("margin-bottom", this.margin + "px");
            }
            if (c.rowHeight) {
                lastProportionedColumn = i;
            } else {
                pw -= (c.getSize().height + cel.getMargins("tb"));
            }
        }

        var remaining = (pw = pw < 0 ? 0 : pw);

        var splitterPos = 0, cw;
        for (i = 0; i < len; i++) {
            c = cs[i];
            cel = c.getEl();
            if (c.rowHeight) {
                cw = (i == lastProportionedColumn) ? remaining : Math.floor(c.rowHeight * pw);
                c.setHeight(cw - cel.getMargins("tb"));
                //c.setSize(cw - cel.getMargins("tb"), this.fitHeight ? h : null);
                remaining -= cw;
            }

            if (this.split) {
                cw = cel.getHeight();

                if (i < (len - 1)) {
                    splitterPos += cw;
                    this.splitBars[i] = new Ext.SplitBar(this.innerCt.createChild({
                        cls: "x-layout-split x-layout-split-north",
                        style: {
                            left: "0px",
                            top: splitterPos + "px",
                            width: "100%",
                            height: this.margin+"px"
                        }
                    }), cel, Ext.SplitBar.VERTICAL, Ext.SplitBar.TOP);
                    this.splitBars[i].index = i;
                    this.splitBars[i].topComponent = c;
                    this.splitBars[i].addListener("resize", this.onColumnResize, this);
                    this.splitBars[i].minSize = this.minHeight;

                    splitterPos += this.splitBars[i].el.getHeight();
                }

                delete c.rowHeight;
            }
        }

        if (this.split) {
            this.setMaxHeights();
        }
    },

    //  On column resize, explicitly size the Components to the left and right of the SplitBar
    onColumnResize: function(sb, newHeight) {
        if (sb.dragSpecs.startSize) {
            sb.topComponent.el.setStyle('height', '');
            sb.topComponent.setHeight(newHeight);
            var items = this.container.items.items;
            var expansion = newHeight - sb.dragSpecs.startSize;
            for (var i = sb.index + 1, len = items.length; expansion && i < len; i++) {
                var c = items[i];
                var w = c.el.getHeight();
                newHeight = w - expansion;
                if (newHeight < this.minHeight) {
                    c.setHeight(this.minHeight);
                } else if (newHeight > this.maxHeight) {
                    expansion -= (newHeight - this.maxHeight);
                    c.setHeight(this.maxHeight);
                } else {
                    c.setHeight(c.el.getHeight() - expansion);
                    break;
                }
            }
            this.setMaxHeights();
        }
    },

    setMaxHeights: function() {
        var items = this.container.items.items;

        var spare = items[items.length - 1].el.dom.offsetHeight - 100;

        for (var i = items.length - 2; i > -1; i--) {
            var sb = this.splitBars[i], sbel = sb.el, c = items[i], cel = c.el;
            var itemHeight = cel.dom.offsetHeight;
            sbel.setStyle("top", (cel.getY() - Ext.fly(cel.dom.parentNode).getY() + itemHeight) + "px");
            sb.maxSize = itemHeight + spare;
            spare = itemHeight - 100;
        }
    },

    onResize: function() {
        if (this.split) {
            var items = this.container.items.items;
            if (items[0].rendered) {
                var tw = 0, c;
                for (var i = 0; i < items.length; i++) {
                    c = items[i];
                    tw += c.el.getHeight() + c.el.getMargins("tb");
                }
                for (var j = 0; j < items.length; j++) {
                    c = items[j];
                    c.rowHeight = (c.el.getHeight() + c.el.getMargins("tb")) / tw;
                }
            }
        }
        Ext.ux.RowLayout.superclass.onResize.apply(this, arguments);
    }
});

Ext.Container.LAYOUTS["ux.row"] = Ext.ux.RowLayout;

Ext.Toolbar.HtmlElement = function(config) {
    Ext.Toolbar.HtmlElement.superclass.constructor.call(this, config.target);
};

Ext.extend(Ext.Toolbar.HtmlElement, Ext.Toolbar.Item, {});

Ext.reg("coolitetbhtml", Ext.Toolbar.HtmlElement);

Ext.override(Ext.Component, {
    addPlugins: function(plugins) {
        if (Ext.isEmpty(this.plugins)) {
            this.plugins = [];
        } else if (!Ext.isArray(this.plugins)) {
            this.plugins = [this.plugins];
        }
        if (Ext.isArray(plugins)) {
            for (var i = 0; i < plugins.length; i++) {
                this.plugins.push(this.initPlugin(plugins[i]));
            }
        } else {
            this.plugins.push(this.initPlugin(plugins));
        }
    },
    getForm: function(id) {
        var form = Ext.isEmpty(id) ? this.el.up('form') : Ext.get(id);
        if (!Ext.isEmpty(form)) {
            Ext.apply(form, form.dom);
            form.submit = function() {
                form.dom.submit();
            };
        }
        return form;
    }
});

Coolite.Ext.DateItem = function(config) {
    Coolite.Ext.DateItem.superclass.constructor.call(this, new Ext.DatePicker(config.picker || {}), config);
    this.picker = this.component;    
    this.addEvents("select");

    this.picker.on("render", function(picker) {
        picker.getEl().swallowEvent("click");
        picker.container.addClass("x-menu-date-item");
    });

    this.picker.on("select", this.onSelect, this);
};

Ext.extend(Coolite.Ext.DateItem, Ext.menu.Adapter, {
    // private
    onSelect: function(picker, date) {
        this.fireEvent("select", this, date, picker);
        Coolite.Ext.DateItem.superclass.handleClick.call(this);
    }
});

Coolite.Ext.DateMenu = function(config) {
    Coolite.Ext.DateMenu.superclass.constructor.call(this, config);
    this.plain = true;

    var ae = config.ajaxEvents;
    var listeners = config.listeners;
    config.ajaxEvents = undefined;
    config.listeners = undefined;
    
    var di = new Coolite.Ext.DateItem(config);

    config.ajaxEvents = ae;
    config.listeners = listeners;
    
    this.add(di);
    this.picker = di.picker;
    this.relayEvents(di, ["select"]);

    this.on("beforeshow", function() {
        if (this.picker) {
            this.picker.hideMonthPicker(true);
        }
    }, this);
};
Ext.extend(Coolite.Ext.DateMenu, Ext.menu.Menu, {
    cls: "x-date-menu",

    // private
    beforeDestroy: function() {
        this.picker.destroy();
    }
});

Ext.override(Ext.ColorPalette, {
    silentSelect: function(color) {
        color = color.replace("#", "");
        if (color != this.value || this.allowReselect) {
            var el = this.el;
            if (this.value) {
                el.child("a.color-" + this.value).removeClass("x-color-palette-sel");
            }
            el.child("a.color-" + color).addClass("x-color-palette-sel");
            this.value = color;
        }
    }
});

Coolite.Ext.ColorItem = function(config) {
    Coolite.Ext.ColorItem.superclass.constructor.call(this, new Ext.ColorPalette(config.palette), config);
    this.palette = this.component;
    this.relayEvents(this.palette, ["select"]);
    if (this.selectHandler) {
        this.on("select", this.selectHandler, this.scope);
    }
};
Ext.extend(Coolite.Ext.ColorItem, Ext.menu.Adapter);

Coolite.Ext.ColorMenu = function(config) {
    Coolite.Ext.ColorMenu.superclass.constructor.call(this, config);
    this.plain = true;
    var ci = new Coolite.Ext.ColorItem(config);
    this.add(ci);
    this.palette = ci.palette;
    //this.relayEvents(ci, ["select"]);
};
Ext.extend(Coolite.Ext.ColorMenu, Ext.menu.Menu);

Ext.override(Ext.CycleButton, {
    initComponent: function() {
        this.addEvents("change");

        if (this.changeHandler) {
            this.on("change", this.changeHandler, this.scope || this);
            delete this.changeHandler;
        }

        this.itemCount = this.menu.items.length;

        this.menu.cls = "x-cycle-menu";
        var checked;
        for (var i = 0, len = this.itemCount; i < len; i++) {
            var item = this.menu.items.itemAt(i);

            item.group = item.group || this.id;

            item.itemIndex = i;
            item.on("checkchange", this.checkHandler, this);
            item.scope = this;
            item.setChecked(item.checked || false, true);

            if (item.checked) {
                checked = item;
            }
        }
        this.setActiveItem(checked, true);
        Ext.CycleButton.superclass.initComponent.call(this);

        this.on("click", this.toggleSelected, this);
    }
});

Ext.override(Ext.menu.Menu, {
    lastTargetIn: function(cmp) {
        var el = cmp.getEl ? cmp.getEl() : cmp;
        return Ext.fly(el).contains(this.trg);
    },

    createEl: function() {
        var frm = document.body;
        if (document.forms.length > 0) {
            frm = document.forms[0];
        }
        return new Ext.Layer({
            cls: "x-menu",
            shadow: this.shadow,
            shim: this.shim || true,
            constrain: false,
            parentEl: this.parentEl || frm,
            zindex: 15000
        });
    }
});

Coolite.Ext.ElementMenuItem = function(cfg) {
    this.target = cfg.target;
    Coolite.Ext.ElementMenuItem.superclass.constructor.call(this, cfg);
};

Ext.extend(Coolite.Ext.ElementMenuItem, Ext.menu.BaseItem, {
    hideOnClick: false,
    itemCls: "x-menu-item",
    shift: true,

    getComponent: function() {
        if (Ext.isEmpty(this.el.id)) {
            return null;
        }
        var cmp = Ext.getCmp(this.el.id);
        if (Ext.isEmpty(cmp)) {
            return null;
        }
        return cmp;
    },

    // private
    onRender: function(container) {

        if (this.target.getEl) {
            this.el = this.target.getEl();
        }
        else {
            this.el = Ext.get(this.target);
        }

        var cmp = Ext.getCmp(this.el.id);
        this.parentMenu.on("show", function() {
            if (!Ext.isEmpty(cmp)) {
                if (cmp.doLayout) {
                    cmp.doLayout();
                }

                if (cmp.syncSize) {
                    cmp.syncSize();
                }
            }
        });

        if (Ext.isIE) {
            this.parentMenu.shadow = false;
            this.parentMenu.el.shadow = false;

            if (!Ext.isEmpty(cmp)) {
                cmp.shadow = false;
                cmp.el.shadow = false;
            }
        }

        if (this.shift) {
            this.el.applyStyles({ "margin-left": "23px" });
        }

        this.el.swallowEvent(["keydown", "keypress"]);
        Ext.each(["keydown", "keypress"], function(eventName) {
            this.el.on(eventName, function(e) {
                if (e.isNavKeyPress()) {
                    e.stopPropagation();
                }
            }, this);
        }, this);

        if (Ext.isGecko) {
            container.removeClass("x-menu-list-item");
            container.setStyle({ width: "", height: "" });
            if (this.shift) {
                this.el.applyStyles({ "margin-left": "24px" });
            }
        }

        Coolite.Ext.ElementMenuItem.superclass.onRender.apply(this, arguments);
    },

    activate: function() {
        if (this.disabled) {
            return false;
        }

        var cmp = this.getComponent();
        if (Ext.isEmpty(cmp)) {
            return false;
        }

        this.cmp.focus();
        this.fireEvent("activate", this);
        return true;
    },

    // private
    deactivate: function() {
        this.fireEvent("deactivate", this);
    },

    // private
    disable: function() {
        var cmp = this.getComponent();
        if (Ext.isEmpty(cmp)) {
            return;
        }
        this.cmp.disable();
        Coolite.Ext.ElementMenuItem.superclass.disable.call(this);
    },

    // private
    enable: function() {
        var cmp = this.getComponent();
        if (Ext.isEmpty(cmp)) {
            return;
        }
        this.cmp.enable();
        Coolite.Ext.ElementMenuItem.superclass.enable.call(this);
    }
});

Coolite.Ext.ComboMenuItem = function(config) {
    Coolite.Ext.ComboMenuItem.superclass.constructor.call(this, new Ext.form.ComboBox(config.combobox), config);
    this.combo = this.component;
    this.addEvents("select");
    this.combo.on("render", function(combo) {
        combo.getEl().swallowEvent("click");
        combo.list.applyStyles("z-index:99999");
        combo.list.on("mousedown", function(e) {
            Ext.lib.Event.stopPropagation(e);
        });
    });
};

Ext.extend(Coolite.Ext.ComboMenuItem, Ext.menu.Adapter, {
    hideOnClick: false,
    onSelect: function(combo, record) {
        this.fireEvent("select", this, record);
        Coolite.Ext.ComboMenuItem.superclass.handleClick.call(this);
    },
    onRender: function(container) {
        Coolite.Ext.ComboMenuItem.superclass.onRender.call(this, container);

        if (Ext.isIE) {
            this.combo.list.shadow = false;
        }

        this.el.swallowEvent(["keydown", "keypress"]);
        Ext.each(["keydown", "keypress"], function(eventName) {
            this.el.on(eventName, function(e) {
                if (e.isNavKeyPress()) {
                    e.stopPropagation();
                }
            }, this);
        }, this);

        if (Ext.isGecko) {
            container.setOverflow("auto");
            var containerSize = container.getSize();
            this.combo.wrap.setStyle("position", "fixed");
            container.setSize(containerSize);
        }
    }
});

Coolite.Ext.DateFieldMenuItem = function(config) {
    Coolite.Ext.DateFieldMenuItem.superclass.constructor.call(this, new Ext.form.DateField(config.dateField), config);
    this.dateField = this.component;
    this.dateField.menu = new Ext.menu.DateMenu({
        allowOtherMenus: true
    });

    this.dateField.on("render", function(dateField) {
        dateField.getEl().swallowEvent("click");
    });
};

Ext.extend(Coolite.Ext.DateFieldMenuItem, Ext.menu.Adapter, {
    hideOnClick: false,
    canActivate: false,
    onRender: function(container) {
        Coolite.Ext.DateFieldMenuItem.superclass.onRender.call(this, container);

        this.el.swallowEvent(["keydown", "keypress"]);
        Ext.each(["keydown", "keypress"], function(eventName) {
            this.el.on(eventName, function(e) {
                if (e.isNavKeyPress()) {
                    e.stopPropagation();
                }
            }, this);
        }, this);

        if (Ext.isGecko) {
            container.setOverflow("auto");
            var containerSize = container.getSize();
            this.dateField.wrap.setStyle("position", "fixed");
            container.setSize(containerSize);
        }
    }
});

Coolite.Ext.EditMenuItem = function(config) {
    Coolite.Ext.EditMenuItem.superclass.constructor.call(this, new Ext.form.TextField(config.textbox), config);
    this.textbox = this.component;
    this.addEvents("select");
    this.textbox.on("render", function(textbox) {
        textbox.getEl().swallowEvent("click");
    });
};

Ext.extend(Coolite.Ext.EditMenuItem, Ext.menu.Adapter, {
    onRender: function(container) {
        Coolite.Ext.EditMenuItem.superclass.onRender.call(this, container);

        this.el.swallowEvent(["keydown", "keypress"]);
        Ext.each(["keydown", "keypress"], function(eventName) {
            this.el.on(eventName, function(e) {
                if (e.isNavKeyPress()) {
                    e.stopPropagation();
                }
            }, this);
        }, this);

        if (Ext.isGecko) {
            this.el.setOverflow("auto");
            var containerSize = container.getSize();
            this.textbox.getEl().setStyle("position", "fixed");
            container.setSize(containerSize);
        }
    }
});

Coolite.Ext.MenuPanel = function(config) {
    Coolite.Ext.MenuPanel.superclass.constructor.call(this, config);
    this.menu.on("itemclick", this.setSelection, this);
};

Ext.extend(Coolite.Ext.MenuPanel, Ext.Panel, {
    saveSelection: true,
    selectedIndex: -1,

    initComponent: function() {
        Coolite.Ext.MenuPanel.superclass.initComponent.call(this);

        if (this.selectedIndex > -1) {
            this.menu.items.get(this.selectedIndex).cls = "x-menu-item-active";
        }
    },

    setSelectedIndex: function(index) {
        this.setSelection(this.menu.items.get(index));
    },

    setSelection: function(item, e) {
        if (this.saveSelection) {
            this.menu.items.each(function(item) {
                item.removeClass("x-menu-item-active");
            }, this.menu);

            item.addClass("x-menu-item-active");
        }

        var f = Ext.get(this.id + "_SelIndex");

        if (!Ext.isEmpty(f)) {
            f.dom.value = this.menu.items.indexOf(item);
        }
    },

    afterRender: function() {
        Coolite.Ext.MenuPanel.superclass.afterRender.call(this);
        var layer = this.menu.getEl();
        if (Ext.isIE) {
            layer.shadow = false;
        }

        this.body.appendChild(layer);
        layer.clearPositioning("auto");
        layer.setWidth("auto");
        layer.setHeight("100%");
        layer.applyStyles({ border: "0px" });
        layer.show();
    }
});

Ext.reg("coolitemenupanel", Coolite.Ext.MenuPanel);

// HACK: monkey-patch Toolbar.Item .getEl() to return a typeof Element
Ext.Toolbar.Item.prototype.getEl = function() {
    return Ext.get(this.el);
};

Ext.Toolbar.TextItem.override({
    setText: function(text) {
        this.el.innerHTML = text;
    }
});

Ext.override(Ext.form.TextField, {
    truncate: true,
    afterRender: function() {
        Ext.form.TextField.superclass.afterRender.call(this);
        if (this.maxLength !== Number.MAX_VALUE && this.truncate) {
            this.el.dom.setAttribute("maxlength", this.maxLength);
        }
    }
});

Coolite.Ext.TreePanel = function(config) {
    Coolite.Ext.TreePanel.superclass.constructor.call(this, config);
};

Ext.extend(Coolite.Ext.TreePanel, Ext.tree.TreePanel, {
    initComponent: function() {
        Coolite.Ext.TreePanel.superclass.initComponent.call(this);
        this.initChildren(this.nodes);
    },

    initChildren: function(nodes) {
        if (!Ext.isEmpty(nodes) && nodes.length > 0) {
            var root = nodes[0];
            var rootNode = this.createNode(root);
            this.setRootNode(rootNode);

            if (root.children) {
                this.setChildren(root, rootNode);
            }
        }
    },

    setChildren: function(parent, node) {
        for (var i = 0; i < parent.children.length; i++) {
            var child = parent.children[i];
            var childNode = this.createNode(child);
            node.appendChild(childNode);
            if (child.children) {
                this.setChildren(child, childNode);
            }
        }
    },

    createNode: function(config) {
        var type = config.nodeType || "node";
        if (type == "node") {
            return new Ext.tree.TreeNode(config);
        }

        return new Ext.tree.AsyncTreeNode(config);
    }
});

Ext.reg("coolitetreepanel", Coolite.Ext.TreePanel);

Ext.override(Ext.util.Observable, {
    init_ev: function() {
        if (!(this.isPostBackInit || false)) {
            this.isPostBackInit = true;

            if (this.postBacks) {
                this.on(this.postBacks);
            }
        }

        if (!(this.isAjaxInit || false)) {
            this.isAjaxInit = true;

            if (this.ajaxEvents) {
                this.on(this.ajaxEvents);
            }
        }
    }
});

Coolite.AjaxEvent = new Ext.data.Connection({
    autoAbort: false,
    serializeForm: function(form) {
        return Ext.lib.Ajax.serializeForm(form);
    },
    setValue: function(form, name, value) {
        var input = null;
        if (form[name]) {
            input = form[name];
        } else {
            input = document.createElement("input");
            input.setAttribute("name", name);
            input.setAttribute("type", "hidden");
        }
        input.setAttribute("value", value);
        var parentElement = input.parentElement ? input.parentElement : input.parentNode;
        if (Ext.isEmpty(parentElement)) {
            form.appendChild(input);
            form[name] = input;
        }
    },
    delayedF: function(el, remove) {
        if (!Ext.isEmpty(el)) {
            el.unmask();
            if (remove === true) {
                el.remove();
            }
        }
    },
    showFailure: function(response, errorMsg) {
        var bodySize = Ext.getBody().getViewSize();
        var width = (bodySize.width < 500) ? bodySize.width - 50 : 500;
        var height = (bodySize.height < 300) ? bodySize.height - 50 : 300;

        if (Ext.isEmpty(errorMsg)) {
            errorMsg = response.responseText;
        }

        var win = new Ext.Window({ modal: true, width: width, height: height, title: "Request Failure", layout: "fit", maximizable: true,
            listeners: {
                "maximize": {
                    fn: function(el) {
                        var v = Ext.getBody().getViewSize();
                        el.setSize(v.width, v.height);
                    },
                    scope: this
                },

                "resize": {
                    fn: function(wnd) {
                        var editor = Ext.getCmp('__ErrorMessageEditor');
                        var sz = wnd.body.getViewSize();
                        editor.setSize(sz.width, sz.height - 42);
                    }
                }
            },
            items: new Ext.form.FormPanel({
                baseCls: "x-plain",
                layout: "absolute",
                defaultType: "label",
                items: [
                {
                    x: 5,
                    y: 5,
                    html: '<div class="x-window-dlg"><div class="ext-mb-error" style="width:32px;height:32px"></div></div>'
                }, {
                    x: 42,
                    y: 6,
                    html: "<b>Status code: </b>"
                }, {
                    x: 125,
                    y: 6,
                    text: response.status
                }, {
                    x: 42,
                    y: 25,
                    html: "<b>Status text: </b>"
                }, {
                    x: 125,
                    y: 25,
                    text: response.statusText
                }, {
                    x: 0,
                    y: 42,
                    id: '__ErrorMessageEditor',
                    xtype: "htmleditor",
                    enableAlignments: false,
                    enableColors: false,
                    enableFont: false,
                    enableFontSize: false,
                    enableFormat: false,
                    enableLinks: false,
                    enableLists: false,
                    enableSourceEdit: false,
                    readOnly: true,
                    value: errorMsg
}]
                })
            });
            win.show();
        },
        parseResponse: function(response) {
            var text = response.responseText,
            xmlTpl = "<?xml",
            result = {},
            exception = false;

            result.success = true;

            try {
                if (response.responseText.match(/^<\?xml/) == xmlTpl) {
                    //xml parsing      
                    var xmlData = response.responseXML;
                    var root = xmlData.documentElement || xmlData;
                    var q = Ext.DomQuery;

                    if (root.nodeName == "AjaxResponse") {
                        //root = q.select("AjaxResponse", root);
                        //success
                        var sv = q.selectValue("Success", root, true);
                        var pSuccess = sv !== false && sv !== "false",
                            pErrorMessage = q.selectValue("ErrorMessage", root, ""),
                            pScript = q.selectValue("Script", root, ""),
                            pViewState = q.selectValue("ViewState", root, ""),
                            pViewStateEncrypted = q.selectValue("ViewStateEncrypted", root, ""),
                            pEventValidation = q.selectValue("EventValidation", root, ""),
                            pServiceResponse = q.selectValue("ServiceResponse", root, ""),
                            pUserParamsResponse = q.selectValue("ExtraParamsResponse", root, ""),
                            pResult = q.selectValue("Result", root, "");

                        if (!Ext.isEmpty(pSuccess)) {
                            Ext.apply(result, { success: pSuccess });
                        }

                        if (!Ext.isEmpty(pErrorMessage)) {
                            Ext.apply(result, { errorMessage: pErrorMessage });
                        }

                        if (!Ext.isEmpty(pScript)) {
                            Ext.apply(result, { script: pScript });
                        }

                        if (!Ext.isEmpty(pViewState)) {
                            Ext.apply(result, { viewState: pViewState });
                        }

                        if (!Ext.isEmpty(pViewStateEncrypted)) {
                            Ext.apply(result, { viewStateEncrypted: pViewStateEncrypted });
                        }

                        if (!Ext.isEmpty(pEventValidation)) {
                            Ext.apply(result, { eventValidation: pEventValidation });
                        }

                        if (!Ext.isEmpty(pServiceResponse)) {
                            Ext.apply(result, { serviceResponse: eval("(" + pServiceResponse + ")") });
                        }

                        if (!Ext.isEmpty(pUserParamsResponse)) {
                            Ext.apply(result, { extraParamsResponse: eval("(" + pUserParamsResponse + ")") });
                        }

                        if (!Ext.isEmpty(pResult)) {
                            Ext.apply(result, { result: eval("(" + pResult + ")") });
                        }

                        return { result: result, exception: false };
                    }
                    else {
                        return { result: response.responseXML, exception: false }; // root.text || root.textContent;
                    }
                }

                //json parsing
                result = eval("(" + text + ")");

            } catch (e) {
                result.success = false;
                exception = true;
                if (response.responseText.length === 0) {
                    result.errorMessage = "NORESPONSE";
                } else {
                    result.errorMessage = "BADRESPONSE: " + e.message;
                    result.responseText = response.responseText;
                }

                response.statusText = result.errorMessage;
            }

            return { result: result, exception: exception };
        },

        listeners: {
            beforerequest: {
                fn: function(conn, options) {
                    o = options || {};
                    o.eventType = o.eventType || "event";

                    var isStatic = o.eventType == "static",
                        isInstance = o.eventType == "public",
                        isRequired = o.eventType == "event" || o.eventType == "custom" || o.eventType == "proxy" || o.eventType == "postback";

                    var submitConfig = {};
                    o.extraParams = o.extraParams || {};

                    switch (o.eventType) {
                        case "event":
                        case "custom":
                        case "proxy":
                        case "postback":
                        case "public":
                            if (isInstance) {
                                o.action = o.name;
                            }

                            o.control = o.control || {};
                            o.type = o.type || "submit";
                            o.viewStateMode = o.viewStateMode || "default";
                            o.action = o.action || "Click";
                            o.headers = { "X-Coolite": "delta=true" };

                            if (o.type == "submit") {
                                o.form = Ext.get(o.formProxyArg);

                                if (Ext.isEmpty(o.form) && !Ext.isEmpty(o.control.el)) {
                                    if (Ext.isEmpty(o.control.isComposite) || o.control.isComposite === false) {
                                        o.form = o.control.el.up("form");
                                    } else {
                                        o.form = Ext.get(o.control.elements[0]).up("form");
                                    }
                                }
                            } else if (o.type == "load" && Ext.isEmpty(o.method)) {
                                o.method = "GET";
                            }

                            if (Ext.isEmpty(o.form) && Ext.isEmpty(o.url)) {
                                var forms = Ext.select("form").elements;

                                if (forms.length > 0) {
                                    if (o.type == "submit") {
                                        o.form = Ext.get(forms[0]);
                                    } else {
                                        o.url = forms[0].dom.action || Coolite.Ext.Url || window.location.href;
                                    }
                                }
                            }

                            var argument = String.format("{0}|{1}|{2}", o.proxyId || o.control.proxyId || o.control.id || "-", o.eventType, o.action);

                            if (!Ext.isEmpty(o.form)) {
                                this.setValue(o.form.dom, "__EVENTTARGET", Coolite.Ext.ScriptManagerUniqueID);
                                this.setValue(o.form.dom, "__EVENTARGUMENT", argument);
                                Ext.getDom(o.form).ignoreAllSubmitFields = true;
                            } else {
                                o.url = o.url || Coolite.Ext.Url || window.location.href;
                                Ext.apply(submitConfig, { __EVENTTARGET: Coolite.Ext.ScriptManagerUniqueID, __EVENTARGUMENT: argument });
                            }

                            if (o.viewStateMode != "default") {
                                Ext.apply(submitConfig, { viewStateMode: o.viewStateMode });
                            }

                            if (o.before) {
                                if (o.before(o.control, o.eventType, o.action, o.extraParams) === false) {
                                    return false;
                                }
                            }

                            Ext.apply(submitConfig, { extraParams: o.extraParams || {} });

                            if (!Ext.isEmpty(o.serviceParams)) {
                                Ext.apply(submitConfig, { serviceParams: o.serviceParams });
                            }

                            o.params = { submitAjaxEventConfig: Ext.encode({ config: submitConfig }) };
                            if (!Ext.isEmpty(o.form)) {
                                var enctype = Ext.getDom(o.form).getAttribute("enctype");
                                if ((enctype && enctype.toLowerCase() == 'multipart/form-data') || o.isUpload) {
                                    Ext.apply(o.params, { "__CooliteAjaxEventMarker": "delta=true" });
                                }
                            }

                            if (o.cleanRequest) {
                                o.params = Ext.apply({}, o.extraParams || {});
                            }

                            if (!Ext.isEmpty(o.form)) {
                                o.form.dom.action = o.form.dom.action || o.form.action || o.url || Coolite.Ext.Url || window.location.href;
                            }

                            break;
                        case "static":
                            o.headers = { "X-Coolite": "delta=true,staticmethod=true" };

                            if (Ext.isEmpty(o.form) && Ext.isEmpty(o.url)) {
                                var forms = Ext.select("form").elements;
                                o.url = (forms.length > 0) ? forms[0].action : Coolite.Ext.Url || window.location.href;
                            }

                            if (o.before) {
                                if (o.before(o.control, o.eventType, o.action, o.extraParams) === false) {
                                    return false;
                                }
                            }

                            o.params = Ext.apply(o.extraParams, { "_methodName_": o.name });
                            break;
                    }

                    o.scope = this;

                    //--Common part----------------------------------------------------------

                    var el, em = o.eventMask || {};

                    if ((em.showMask === true)) {
                        switch (em.target || "page") {
                            case "this":
                                if (o.control.getEl) {
                                    el = o.control.getEl();
                                } else if (o.control.dom) {
                                    el = o.control;
                                }
                                break;
                            case "parent":
                                if (o.control.getEl) {
                                    el = o.control.getEl().parent();
                                } else if (o.control.parent) {
                                    el = o.control.parent();
                                }
                                break;
                            case "page":
                                el = Ext.getBody().createChild({ style: "position:absolute;left:0;top:0;width:100%;height:100%;z-index:20000;background-color:Transparent;" });
                                var scroll = Ext.getBody().getScroll();
                                el.setLeftTop(scroll.left, scroll.top);
                                break;
                            case "customtarget":
                                var trg = em.customTarget || "";
                                el = Ext.get(trg);
                                if (Ext.isEmpty(el)) {
                                    el = trg.getEl ? trg.getEl() : null;
                                }
                                break;
                        }

                        if (el !== undefined && el !== null) {
                            el.mask(em.msg || "Working...", em.msgCls || "x-mask-loading");
                            o.el = el;
                        }
                    }

                    var removeMask = function(o) {
                        if (o.el !== undefined && o.el !== null) {
                            var delay = 0,
                                em = o.eventMask || {};
                            if (em && em.minDelay) {
                                delay = em.minDelay;
                            }

                            var remove = (em.target || "page") == "page",
                            task = new Ext.util.DelayedTask(
                                function(o, remove) {
                                    o.scope.delayedF(o.el, remove);
                                },
                                o.scope,
                                [o, remove]
                            ).delay(delay);
                        }
                    };

                    var executeScript = function(o, result, response) {
                        var delay = 0;
                        var em = o.eventMask || {};
                        if (em.minDelay) {
                            delay = em.minDelay;
                        }

                        var task = new Ext.util.DelayedTask(
                            function(o, result, response) {
                                if (result.script && result.script.length > 0) {
                                    eval(result.script);
                                }

                                if (o.userSuccess) {
                                    o.userSuccess(response, result, o.control, o.eventType, o.action, o.extraParams, o);
                                }
                            },
                            o.scope, [o, result, response]).delay(delay);
                    };


                    o.failure = function(response, options) {
                        var o = options;
                        removeMask(o);
                        if (o.userFailure) {
                            o.userFailure(response, { "errorMessage": response.statusText }, o.control, o.eventType, o.action, o.extraParams, o);
                        } else {
                            if (o.showWarningOnFailure !== false) {
                                o.scope.showFailure(response, "");
                            }
                        }
                    };

                    o.success = function(response, options) {
                        var o = options;
                        removeMask(o);

                        var parsedResponse = o.scope.parseResponse(response);

                        if (!Ext.isEmpty(parsedResponse.result.documentElement)) {
                            executeScript(o, parsedResponse.result, response);
                            return;
                        }
                        var result = parsedResponse.result,
                            exception = parsedResponse.exception;

                        if (result.success === false) {
                            if (o.userFailure) {
                                o.userFailure(response, result, o.control, o.eventType, o.action, o.extraParams, o);
                            } else {
                                if (o.showWarningOnFailure !== false) {
                                    var errorMsg = "";
                                    if (!exception && result.errorMessage && result.errorMessage.length > 0) {
                                        errorMsg = result.errorMessage;
                                    }
                                    o.scope.showFailure(response, errorMsg);
                                }
                            }

                            return;
                        }

                        if (!Ext.isEmpty(result.viewState) && o.form !== null) {
                            o.scope.setValue(o.form.dom, "__VIEWSTATE", result.viewState);

                            if (!Ext.isEmpty(result.viewStateEncrypted) && o.form !== null) {
                                o.scope.setValue(o.form.dom, "__VIEWSTATEENCRYPTED", result.viewStateEncrypted);
                            }

                            if (!Ext.isEmpty(result.eventValidation) && o.form !== null) {
                                o.scope.setValue(o.form.dom, "__EVENTVALIDATION", result.eventValidation);
                            }
                        }

                        executeScript(o, result, response);
                    };
                }
            }
        }
    });

    Coolite.AjaxMethod = {
        request: function(name, options) {
            options = options || {};

            if (typeof options !== "object") {
                throw { message: "The AjaxMethod options object is an invalid type: typeof " + typeof options };
            }
            
            if (!Ext.isEmpty(name) && typeof name === "object" && Ext.isEmptyObj(options)) {
                options = name;
            }

            var obj = {
                name: options.name || name,
                control: Ext.isEmpty(options.control) ? null : { id: options.control },
                eventType: options.specifier || "public",
                type: options.type || "submit",
                method: options.method || "POST",
                eventMask: options.eventMask,
                extraParams: options.params,
                ajaxMethodSuccess: options.success,
                ajaxMethodFailure: options.failure,
                userSuccess: function(response, result, control, eventType, action, extraParams, o) {
                    if (!Ext.isEmpty(o.ajaxMethodSuccess)) {
                        o.ajaxMethodSuccess(Ext.isEmpty(result.result) ? result : result.result, response, extraParams);
                    }
                },
                userFailure: function(response, result, control, eventType, action, extraParams, o) {
                    if (!Ext.isEmpty(o.ajaxMethodFailure)) {
                        o.ajaxMethodFailure(result.errorMessage, response, extraParams);
                    }
                }
            };

            Coolite.AjaxEvent.request(Ext.apply(options, obj));
        }
    };

    Ext.Panel.override({
        getCollapsedField: function() { return Ext.get(this.id + "_Collapsed"); },

        getBody: function() {
            return Ext.get(this.id + "_Body") || this.body;
        },

        setAutoScroll: function() {
            if (this.rendered && this.autoScroll) {
                var el = this.body || this.el;
                if (el) {
                    el.setOverflow("auto");
                    // Following line required to fix autoScroll
                    el.dom.style.position = "relative";
                }
            }
            return this;
        },

        // private
        isIFrame: function(cfg) {
            var frame = false;
            if (typeof cfg == "string" && cfg.indexOf("://") >= 0) {
                frame = true;
            } else if (cfg.mode) {
                if (cfg.mode == "iframe") {
                    frame = true;
                }
            } else if (cfg.url && cfg.url.indexOf("://") >= 0) {
                frame = true;
            } else if ((this.getAutoLoad().url && this.autoLoad.url.indexOf("://") >= 0)
                    || (this.getAutoLoad().mode && this.autoLoad.mode == "iframe")) {
                frame = true;
            }

            return frame;
        },

        load: function(config) {
            if (!Ext.isEmpty(config) && !Ext.isEmptyObj(config)) {
                if (this.isIFrame(config)) {
                    return this.loadIFrame(config);
                }

                var um = this.body.getUpdater();
                um.update.apply(um, arguments);
            }
            return this;
        },

        doAutoLoad: function() {
            this.load(this.getAutoLoad());
        },

        reload: function(nocache) {
            this.getAutoLoad().nocache = nocache || this.autoLoad.nocache;
            this.doAutoLoad();
        },

        getAutoLoad: function() {
            this.autoLoad = this.autoLoad || {};
            return this.autoLoad;
        },

        // private
        loadIFrame: function(config) {
            var al = this.getAutoLoad(), url;

            if (typeof config == "string") {
                al.url = config;
            } else if (typeof config == "object") {
                Ext.apply(al, config);
            }

            url = al.url;

            if (al.nocache == true) {
                url = url + "?" + new Date().getTime();
            }

            if (Ext.isEmpty(this.iframe)) {
                var iframeObj = {
                    tag: "iframe",
                    width: "100%",
                    height: "100%",
                    frameborder: 0,
                    id: this.id + "_IFrame",
                    name: this.id + "_IFrame",
                    src: url
                };
                this.iframe = Ext.get(Ext.DomHelper.insertFirst(this.body, iframeObj));
                this.iframe.on("load", this.afterLoad, this);
                this.fireEvent("beforeupdate", this, { url: url, iframe: this.iframe });
            } else {
                this.fireEvent("beforeupdate", this, { url: this.iframe.dom.src, iframe: this.iframe });
                this.iframe.dom.src = url;
            }

            if (al.showMask) {
                this.body.mask(al.maskMsg || "Loading...", al.maskCls || "x-mask-loading");
            }
            this.autoLoad = al;
            return this;
        },

        afterLoad: function() {
            if (this.autoLoad.showMask) {
                this.body.unmask();
            }
            this.fireEvent("update", this, { iframe: this.iframe, url: this.iframe.dom.src });
        },

        autoLoadBeforeUpdate: function(el, url, params) {
            this.fireEvent("beforeupdate", this, { url: url, params: params });
            if (this.autoLoad.showMask) {
                this.body.mask(this.autoLoad.maskMsg || "Loading...", this.autoLoad.maskCls || "x-mask-loading");
            }
        },

        autoLoadUpdate: function(el, response) {
            if (this.autoLoad.showMask) {
                this.body.unmask();
            }
            this.fireEvent("update", this, { response: response });
        },

        autoLoadFailure: function(el, response) {
            if (this.autoLoad.showMask) {
                this.body.unmask();
            }
            this.fireEvent("failure", this, { response: response });
        }
    });

    Ext.Panel.prototype.beforeDestroy = Ext.Panel.prototype.beforeDestroy.createInterceptor(function() {
        if (this.iframe) {
            this.iframe.remove();
        }
    });

    Ext.Panel.prototype.initComponent = Ext.Panel.prototype.initComponent.createSequence(function() {
        this.addEvents("beforeupdate", "update", "failure");

        if (this.autoLoad) {
            this.on('render', function() {
                var updater = this.getUpdater();
                updater.showLoadIndicator = false;

                updater.on("beforeupdate", this.autoLoadBeforeUpdate, this);
                updater.on("update", this.autoLoadUpdate, this);
                updater.on("failure", this.autoLoadFailure, this);
            }, this);
        }
    });

    Ext.Panel.prototype.onCollapse = Ext.Panel.prototype.onCollapse.createSequence(function(doAnim, animArg) {
        var f = this.getCollapsedField();
        if (!Ext.isEmpty(f)) {
            f.dom.value = "true";
        }
    });

    Ext.Panel.prototype.onExpand = Ext.Panel.prototype.onExpand.createSequence(function(doAnim, animArg) {
        var f = this.getCollapsedField();
        if (!Ext.isEmpty(f)) {
            f.dom.value = "false";
        }
    });

    Coolite.Ext.TaskResponse = { stopTask: -1, stopAjax: -2 };

    Coolite.Ext.TaskManager = function(config) {
        Coolite.Ext.TaskManager.superclass.constructor.call(this);
        Ext.apply(this, config);
        return new Ext.util.DelayedTask(this.initManager, this).delay(this.autoRunDelay || 50);
    };

    Ext.extend(Coolite.Ext.TaskManager, Ext.util.Observable, {
        tasksConfig: [],
        tasks: [],

        getTasks: function() { return this.tasks; },

        initManager: function() {
            this.runner = new Ext.util.TaskRunner(this.interval || 10);
            var task;
            for (var i = 0; i < this.tasksConfig.length; i++) {
                task = this.createTask(this.tasksConfig[i]);
                this.tasks.push(task);
                if (task.executing && task.autoRun) {
                    this.startTask(task);
                }
            }
        },

        getTask: function(id) {
            if (typeof id == "object") {
                return id;
            } else if (typeof id == "string") {
                for (var i = 0; this.tasks.length; i++) {
                    if (this.tasks[i].id == id) {
                        return this.tasks[i];
                    }
                }
            } else if (typeof id == "number") {
                return this.tasks[id];
            }
            return null;
        },

        startTask: function(task) {
            if (this.executing) {
                return;
            }

            task = this.getTask(task);

            if (task.onstart) {
                task.onstart.apply(task.scope || task);
            }

            this.runner.start(task);
        },

        stopTask: function(task) { this.runner.stop(this.getTask(task)); },

        startAll: function() {
            for (var i = 0; i < this.tasks.length; i++) {
                this.startTask(this.tasks[i]);
            }
        },

        stopAll: function() { this.runner.stopAll(); },

        //private
        createTask: function(config) {
            return Ext.apply({}, config, {
                owner: this,
                executing: true,
                interval: 1000,
                autoRun: true,
                onStop: function(t) {
                    this.executing = false;
                    if (this.onstop) {
                        this.onstop();
                    }
                },
                run: function() {
                    if (this.clientRun) {
                        var rt = this.clientRun.apply(arguments);

                        if (rt === Coolite.Ext.TaskResponse.stopAjax) {
                            return;
                        } else if (rt === Coolite.Ext.TaskResponse.stopTask) {
                            return false;
                        }
                    }
                    if (this.serverRun) {
                        var params = arguments;
                        this.serverRun.control = this.owner;
                        Coolite.AjaxEvent.request(this.serverRun);
                    }
                }
            });
        }
    });

    Ext.tree.TreeLoader.override({
        requestData: function(node, callback) {
            if (this.fireEvent("beforeload", this, node, callback) !== false) {
                this.transId = Ext.Ajax.request({
                    method: this.requestMethod,
                    url: this.dataUrl || this.url,
                    success: this.handleResponse,
                    failure: this.handleFailure,
                    scope: this,
                    timeout: this.timeout || 30000,
                    argument: { callback: callback, node: node },
                    params: this.getParams(node)
                });
            } else {
                if (typeof callback == "function") {
                    callback();
                }
            }
        },
        createNode: function(attr) {
            if (this.baseAttrs) {
                Ext.applyIf(attr, this.baseAttrs);
            }
            if (this.applyLoader !== false) {
                attr.loader = this;
            }
            if (typeof attr.uiProvider == 'string') {
                attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider);
            }

            var node;
            if (attr.nodeType) {
                node = new Ext.tree.TreePanel.nodeTypes[attr.nodeType](attr);
            } else {
                node = attr.leaf ?
                            new Ext.tree.TreeNode(attr) :
                            new Ext.tree.AsyncTreeNode(attr);
            }

            if (this.preloadChildren) {
                this.doPreload(node);
            }

            return node;
        }
    });

    Coolite.Ext.WebServiceTreeLoader = Ext.extend(Ext.tree.TreeLoader, {
        // private override
        processResponse: function(response, node, callback) {
            var xmlData = response.responseXML;
            var root = xmlData.documentElement || xmlData;
            var json = Ext.DomQuery.selectValue("json", root, "");

            try {
                var o = eval("(" + json + ")");
                node.beginUpdate();
                for (var i = 0, len = o.length; i < len; i++) {
                    var n = this.createNode(o[i]);
                    if (n) {
                        node.appendChild(n);
                    }
                }
                node.endUpdate();
                if (typeof callback == "function") {
                    callback(this, node);
                }
            } catch (e) {
                this.handleFailure(response);
            }
        }
    });

    Coolite.Ext.PageTreeLoader = Ext.extend(Ext.tree.TreeLoader, {
        load: function(node, callback) {
            if (this.clearOnLoad) {
                while (node.firstChild) {
                    node.removeChild(node.firstChild);
                }
            }
            if (this.doPreload(node)) {
                if (typeof callback == "function") {
                    callback();
                }
            } else {
                this.requestData(node, callback);
            }
        },

        requestData: function(node, callback) {
            if (this.fireEvent("beforeload", this, node, callback) !== false) {
                var config = {};

                Ext.apply(config, {
                    control: node.getOwnerTree(),
                    eventType: "postback",
                    action: "nodeload",
                    userSuccess: this.handleSuccess,
                    userFailure: this.handleFailure,
                    argument: { callback: callback, node: node },
                    extraParams: this.getParams(node),
                    method: this.method,
                    timeout: this.timeout || 30000,
                    isUpload: this.isUpload,
                    viewStateMode: this.viewStateMode,
                    type: this.type,
                    url: this.url,
                    formProxyArg: this.formProxyArg,
                    eventMask: this.eventMask
                });
                Coolite.AjaxEvent.request(config);

            } else {
                if (typeof callback == "function") {
                    callback();
                }
            }
        },

        handleFailure: function(response, result, context, type, action, extraParams) {
            var loader = context.getLoader();
            loader.transId = false;
            var a = response.argument;
            loader.fireEvent("loadexception", loader, a.node, response, result.errorMessage || response.statusText);
            if (typeof a.callback == "function") {
                a.callback(loader, a.node);
            }
        },

        handleSuccess: function(response, result, context, type, action, extraParams) {
            var loader = context.getLoader();
            var serviceResponse = result.serviceResponse || {};

            loader.transId = false;
            var a = response.argument;
            loader.processResponse(response, serviceResponse.Data || [], a.node, a.callback);
            loader.fireEvent("load", loader, a.node, response);
        },

        getParams: function(node) {
            var buf = {}, bp = this.baseParams;
            for (var key in bp) {
                if (typeof bp[key] != "function") {
                    buf[key] = bp[key];
                }
            }
            buf["node"] = node.id;
            return buf;
        },

        processResponse: function(response, data, node, callback) {
            try {
                var o = data;
                node.beginUpdate();
                for (var i = 0, len = o.length; i < len; i++) {
                    var n = this.createNode(o[i]);
                    if (n) {
                        node.appendChild(n);
                    }
                }
                node.endUpdate();
                if (typeof callback == "function") {
                    callback(this, node);
                }
            } catch (e) {
                this.handleFailure(response);
            }
        }
    });

    Ext.tree.AsyncTreeNode.override({
        loadNodes: function(nodes) {
            this.beginUpdate();

            for (var i = 0, len = nodes.length; i < len; i++) {
                var n = this.getOwnerTree().getLoader().createNode(nodes[i]);

                if (!Ext.isEmpty(n)) {
                    this.appendChild(n);
                }
            }
            
            this.endUpdate();
            this.loadComplete();
        }
    });

    Coolite.Ext.lazyInit = function(controls) {
        if (!Ext.isArray(controls)) { return; }
        for (var i = 0; i < controls.length; i++) {
            window[controls[i]] = Ext.getCmp(controls[i]);
        }
    };

    Coolite.Ext.setValues = function(controls) {
        if (!Ext.isArray(controls)) { return; }
        for (var i = 0; i < controls.length; i++) {
            controls[i][0].setValue(controls[i][1]);
            controls[i][0].clearInvalid();
        }
    };

    Coolite.Ext.doPostBack = function(config) {
        if (config.before) {
            if (config.before(config.control, config.extraParams || {}) === false) {
                return;
            }
        }

        if (config.extraParams) {
            var form = document.forms[0];
            if (!Ext.isEmpty(form)) {
                form = Ext.get(form);
                var id = "__CoolitePostBackParams";
                var el = form.insertFirst({ tag: "input", id: id, name: id, type: "hidden" });
                el.dom.value = Ext.encode(config.extraParams);
            }
        }

        config.fn();
    };

    Coolite.Ext.TriggerField = Ext.extend(Ext.form.TriggerField, {
        initComponent: function() {
            Coolite.Ext.TriggerField.superclass.initComponent.call(this);

            this.addEvents("triggerclick");

            if (this.triggersConfig) {

                var cn = [];
                for (var i = 0; i < this.triggersConfig.length; i++) {
                    var trigger = this.triggersConfig[i];
                    var triggerCfg = {
                        tag: "img",
                        "ext:qtip": trigger.qtip || "",
                        src: Ext.BLANK_IMAGE_URL,
                        cls: "x-form-trigger" + (trigger.triggerCls || "") + " " + (trigger.iconCls || "x-form-ellipsis-trigger")
                    };

                    if (trigger.hideTrigger) {
                        Ext.apply(triggerCfg, { style: "display:none" });
                    }
                    cn.push(triggerCfg);
                }

                this.triggerConfig = { tag: 'span', cls: 'x-form-twin-triggers', cn: cn };
            }
        },

        getTrigger: function(index) {
            return this.triggers[index];
        },

        initTrigger: function() {
            var ts = this.trigger.select('.x-form-trigger', true);
            this.wrap.setStyle('overflow', 'hidden');
            var triggerField = this;
            ts.each(function(t, all, index) {
                t.hide = function() {
                    var w = triggerField.wrap.getWidth();
                    this.dom.style.display = 'none';
                    triggerField.el.setWidth(w - triggerField.trigger.getWidth());
                };
                t.show = function() {
                    var w = triggerField.wrap.getWidth();
                    this.dom.style.display = '';
                    triggerField.el.setWidth(w - triggerField.trigger.getWidth());
                };

                t.on("click", this.onTriggerClick, this, { index: index, t: t, preventDefault: true });
                t.addClassOnOver('x-form-trigger-over');
                t.addClassOnClick('x-form-trigger-click');
            }, this);
            this.triggers = ts.elements;
        },

        onTriggerClick: function(evt, el, o) {
            this.fireEvent("triggerclick", this, o.t, o.index);
        }
    });

    Ext.reg('coolitetrigger', Coolite.Ext.TriggerField);

    Ext.form.DateField.override({
        onTriggerClick: function() {
            if (this.disabled) {
                return;
            }
            if (Ext.isEmpty(this.menu)) {
                this.menu = new Ext.menu.DateMenu();
            }

            if (this.menu.isVisible()) {
                this.menu.hide();
                return;
            }

            Ext.apply(this.menu.picker, {
                minDate: this.minValue,
                maxDate: this.maxValue,
                disabledDatesRE: this.ddMatch,
                disabledDatesText: this.disabledDatesText,
                disabledDays: this.disabledDays,
                disabledDaysText: this.disabledDaysText,
                format: this.format,
                showToday: this.showToday,
                minText: String.format(this.minText, this.formatDate(this.minValue)),
                maxText: String.format(this.maxText, this.formatDate(this.maxValue))
            });

            if (this.cancelText) {
                Ext.apply(this.menu.picker, { cancelText: this.cancelText });
            }
            if (this.dayNames) {
                Ext.apply(this.menu.picker, { dayNames: this.dayNames });
            }
            if (this.monthNames) {
                Ext.apply(this.menu.picker, { monthNames: this.monthNames });
            }
            if (this.monthYearText) {
                Ext.apply(this.menu.picker, { monthYearText: this.monthYearText });
            }
            if (this.nextText) {
                Ext.apply(this.menu.picker, { nextText: this.nextText });
            }
            if (this.okText) {
                Ext.apply(this.menu.picker, { okText: this.okText });
            }
            if (this.prevText) {
                Ext.apply(this.menu.picker, { prevText: this.prevText });
            }
            if (this.startDay) {
                Ext.apply(this.menu.picker, { startDay: this.startDay });
            }
            if (this.todayText) {
                Ext.apply(this.menu.picker, { todayText: this.todayText });
            }
            if (this.todayTip) {
                Ext.apply(this.menu.picker, { todayTip: this.todayTip });
            }

            this.menu.on(Ext.apply({}, this.menuListeners, {
                scope: this
            }));
            this.menu.picker.setValue(this.getValue() || new Date());
            this.menu.show(this.el, "tl-bl?");
        }
    });

    Ext.layout.FormLayout.override({
        // private
        renderItem: function(c, position, target) {
            if (c && !c.rendered && c.isFormField && c.inputType != 'hidden') {
                var args = [
                       c.id, c.fieldLabel,
                       (this.labelStyle || '') + ';' + (c.labelStyle || ''),
                       this.elementStyle || '',
                       typeof c.labelSeparator == 'undefined' ? this.labelSeparator : c.labelSeparator,
                       (c.itemCls || this.container.itemCls || '') + (c.hideLabel ? ' x-hide-label' : ''),
                       c.clearCls || 'x-form-clear-left'
                ];
                if (typeof position == 'number') {
                    position = target.dom.childNodes[position] || null;
                }
                if (position) {
                    this.fieldTpl.insertBefore(position, args);
                } else {
                    this.fieldTpl.append(target, args);
                }
                c.render('x-form-el-' + c.id);
            } else {
                Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
            }
        },

        setContainer: function(ct) {
            Ext.layout.FormLayout.superclass.setContainer.call(this, ct);

            if (ct.labelAlign) {
                ct.addClass('x-form-label-' + ct.labelAlign);
            }

            this.elementStyle = this.elementStyle || "";
            this.labelStyle = this.labelStyle || "";

            if (ct.hideLabels) {
                this.labelStyle += "display:none";
                this.elementStyle += "padding-left:0;";
                this.labelAdjust = 0;
            } else {
                this.labelSeparator = ct.labelSeparator || this.labelSeparator;
                ct.labelWidth = ct.labelWidth || 100;
                if (typeof ct.labelWidth == 'number') {
                    var pad = (typeof ct.labelPad == 'number' ? ct.labelPad : 5);
                    this.labelAdjust = ct.labelWidth + pad;
                    this.labelStyle += "width:" + ct.labelWidth + "px;";
                    this.elementStyle += "padding-left:" + (ct.labelWidth + pad) + 'px';
                }
                if (ct.labelAlign == 'top') {
                    this.labelStyle += "width:auto;";
                    this.labelAdjust = 0;
                    this.elementStyle += "padding-left:0;";
                }
            }

            if (!this.fieldTpl) {
                // the default field template used by all form layouts
                var t = new Ext.Template(
                    '<div class="x-form-item {5}" tabIndex="-1">',
                        '<label for="{0}" style="{2}" class="x-form-item-label">{1}{4}</label>',
                        '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
                        '</div><div class="{6}"></div>',
                    '</div>');
                t.disableFormats = true;
                t.compile();
                Ext.layout.FormLayout.prototype.fieldTpl = t;
            }
        }
    });

    Ext.namespace('Ext.ux.layout');

    Ext.form.Field.override({
        setReadOnly: function(readOnly) {
            if (this.rendered) {
                this.el.dom.setAttribute('readOnly', readOnly);
                this.el.dom.readOnly = readOnly;
            }
            else {
                this.readOnly = readOnly;
            }
        },
        getReadOnly: function() {
            return this.rendered ? this.el.dom.readOnly : this.readOnly;
        }
    });

    Ext.TabPanel.override({
        onStripMouseDown: function(e) {
            if (e.button !== 0) {
                return;
            }
            e.preventDefault();
            var t = this.findTargets(e);
            if (t.close) {
                this.closeTab(t.item);
                return;
            }
            if (t.item && t.item != this.activeTab) {
                this.setActiveTab(t.item);
            }
        },

        closeTab: function(tab, closeAction) {
            if (typeof tab == 'string') {
                tab = this.getItem(tab);
            }
            else if (typeof tab == 'number') {
                tab = this.items.get(tab);
            }

            if (Ext.isEmpty(tab)) {
                return;
            }

            var eventName = tab.closeAction || closeAction || 'close';
            var destroy = eventName == 'close';

            if (tab.fireEvent('before' + eventName, tab) === false) {
                return;
            }

            this.hideTabStripItem(tab);
            tab.addClass('x-hide-display');
            tab.fireEvent('close', tab);
            this.remove(tab, destroy);
        },

        addTab: function(tab, index, activate) {
            config = {};

            if (!Ext.isEmpty(index)) {
                if (typeof index == 'object') {
                    config = index;
                }
                else if (typeof index == 'number') {
                    config.index = index;
                }
                else {
                    config.activate = index;
                }
            }

            if (!Ext.isEmpty(activate)) {
                config.activate = activate;
            }

            if (this.items.getCount() === 0) {
                this.activeTab = null;
            }

            if (!Ext.isEmpty(config.index) && config.index >= 0) {
                this.insert(config.index, tab);
            }
            else {
                this.add(tab);
            }

            if (config.activate !== false) {
                this.setActiveTab(tab);
            }
        }
    });

    Ext.namespace('Ext.ux');

    Ext.override(Ext.Component, {
        /*    override by Animal (http://extjs.com/forum/showthread.php?t=26484)
        that allows us to find the dollar fields parent form. Very nice.
        */
        findParentBy: function(fn) {
            for (var p = this.ownerCt; (p !== null && typeof (p) != "undefined") && !fn(p); p = p.ownerCt);
            return p;
        },

        findParentByType: function(xtype) {
            return typeof xtype == 'function' ?
            this.findParentBy(function(p) {
                return p.constructor === xtype;
            }) :
            this.findParentBy(function(p) {
                return p.constructor.xtype === xtype;
            });
        }
    });

    Ext.util.Format.usMoneyNull = function(v, cents) {
        // -- allows clearing of field value (so that $0.00 only shows if you
        // explicitly entered zero for a value).
        if (v === null || v === '') {
            return '';
        } else if (v > 999999999999) {
            return '';
        } else {
            // Modified version from Ext.util.Format.usMoney checks the cents
            // parameter to determine whether or not to display decimal places
            v = Math.round((v - 0) * 100) / 100;
            v = (v == Math.floor(v)) ? v + ".00" : ((v * 10 == Math.floor(v * 10)) ? v + "0" : v);
            v = String(v);
            var ps = v.split('.');
            var whole = ps[0];
            var sub = ps[1] ? '.' + ps[1] : '.00';
            var r = /(\d+)(\d{3})/;
            while (r.test(whole)) {
                whole = whole.replace(r, '$1' + ',' + '$2');
            }
            v = (cents) ? whole + sub : whole;
            if (v.charAt(0) == '-') {
                return '-$' + v.substr(1);
            }
            return "$" + v;
        }
    };


    /* NumberField Implementation */
    Ext.ux.dollarField = function(config) {
        //-- Add any numberfield default settings here:
        var defaultConfig = {
            allowDecimals: true,
            allowNegative: false,
            decimalPrecision: 2,
            maxValue: 1000000000,
            minValue: 0,
            selectOnFocus: true,
            value: null,
            itemCls: 'rmoney' // to right-align dollar field, define style: .rmoney .x-form-field {text-align:right;}
        };

        Ext.ux.dollarField.superclass.constructor.call(this, Ext.apply(defaultConfig, config));

        this.on('change', this._onChange, this);
        this.on('focus', this._onFocus);
        this.on('blur', this._onBlur);
        this.on('render', this._onRender);
        this.dollarNumericValue = config.value || null;
    };

    Ext.extend(Ext.ux.dollarField, Ext.form.NumberField, {
        dollarNumericValue: null,

        initSelf: function() {
            // When form loads, bare number is loaded and displayed. Call this (via listener, typically)
            // to format value to dollar.
            if (this.value === null || this.value === '') {
                this.dollarNumericValue = null;
            } else {
                this.dollarNumericValue = this.value;
            }
            this.setRawValue(this.formatter(this.dollarNumericValue));

            // prevent field from reporting itself as "dirty" after form load (isDirty check):
            this.originalValue = this.dollarNumericValue;
        },

        getValue: function() {
            //return this.value+"".replace(/[^0-9.-]/g,"")-0; strip out any formatting characters from string.
            if (this.value === '' || this.value === null) {
                return null;
            } else if (isNaN(this.value)) {
                this.value = 0;
            } else {
                return Number(this.value);
            }
        },

        _onChange: function(field, newVal, oldVal) {
            // n will always be unformatted numeric as STRING! So "-0" to force numeric type:
            if (newVal === '') {
                this.dollarNumericValue = null;
            } else {
                this.dollarNumericValue = newVal - 0;
            }
        },

        _onBeforeAction: function(form, action) {
            this.setRawValue(this.getValue());
        },

        _onRender: function(cmp) {
            this.setRawValue(this.formatter(this.dollarNumericValue));
            if (this.isFormField) {    // Is this check necessary?
                var parentForm = this.findParentByType('form');
                if (typeof (parentForm) == "undefined") {
                    this.isFormField = false;
                    return;
                }
                /*
                Note: If client-side validation is enabled, unformatted numbers get posted on save. Good!

                (The field's "isValid" method just does this for some reason, which works to our advantage.)

                BUT (there's always a "but"), we then need to apply back the dollar formatting so that the
                numbers aren't left displayed as plain.
                */

                // Format dollar after successful form save:
                parentForm.on('actioncomplete', function() { cmp.initSelf(); });

                // Format back to dollar after failed save attempt.
                parentForm.on('actionfailed', function() { cmp.initSelf(); });

                // doLayout is called on initial page load.
                parentForm.on('afterLayout', function() { cmp.initSelf(); });

                parentForm.on('beforeaction', this._onBeforeAction, this);

                // Formats dollar after client-side validation fails...maybe...still investigating this.
                // parentForm.on('beforeaction', function() {cmp.initSelf();});

                /*
                Depends on order of any success/actioncomplete/actionfailed listeners???
                Or maybe you are checking if the form isValid yourself by listening to the
                form's beforeaction, type action.type=='submit' and then returning false to
                cancel the action.    Still looking into all this.

                More on clientValidation:
                Before the form submits (doAction 'submit' with clientValidation not set to false...
                from docs: "If undefined, pre-submission field validation is performed.") the call
                to form "isValid" will turn the dollarfield back to a plain, unformatted number,
                which will get posted.
                */

            }
        },

        formatter: function(value) {
            var showCents = (this.decimalPrecision !== 0);

            // usMoneyNull formatter *always* includes 2 decimal places at the end (".00"). If decimalPrecision is set to 0, lob off the decimals.

            if (value === 0) {
                return Ext.util.Format.usMoneyNull("0", showCents);  // returns '$0.00/$0' instead of ''.
            } else {
                return Ext.util.Format.usMoneyNull(value, showCents);
            }
        },

        _onBlur: function(field) {
            /*
            always update dollarNumericValue with the actual RawValue (which right here (onBlur) will
            *always* be numeric    (remember: when focused, it's unformatted numeric entry...just like
            numberfield does. So onBlur, grab that numeric value and save it to this.dollarNumericValue,
            then apply formatting back to RawValue for display.
            */

            if (field.getRawValue().substring(0, 1) != '$') {
                if (field.getRawValue() === '') {
                    this.dollarNumericValue = null;
                } else {
                    this.dollarNumericValue = field.getRawValue() - 0;
                }

                field.setRawValue(this.formatter(this.dollarNumericValue));

                if (this.dollarNumericValue !== this.value) {
                    /* for some reason, when zero'ing out a value (or clearing), the onChange event is not firing 
                    and this.value is not getting set to the new zero or blank value. This fixes that:
                    */
                    this.value = this.dollarNumericValue;
                }

            }
        },

        _onFocus: function(field) {
            if (this.dollarNumericValue === null || this.dollarNumericValue === '') {
                field.setRawValue('');
            } else {
                // remove formatting by restoring RawValue to dollarNumericValue.
                field.setRawValue((this.dollarNumericValue - 0).toFixed(this.decimalPrecision));
            }
        },

        processValue: function(value) {
            return value;
        },

        validateValue: function(value) {
            if (!Ext.form.NumberField.superclass.validateValue.call(this, value)) {
                return false;
            }
            if (value.length < 1) { // if it's blank and textfield didn't flag it then it's valid
                return true;
            }
            value = Number(this.value);
            if (isNaN(value)) {
                this.markInvalid(String.format(this.nanText, value));
                return false;
            }
            var num = this.parseValue(value);
            if (num < this.minValue) {
                this.markInvalid(String.format(this.minText, this.minValue));
                return false;
            }
            if (num > this.maxValue) {
                this.markInvalid(String.format(this.maxText, this.maxValue));
                return false;
            }
            return true;
        },

        initAllSiblings: function() {
            /*
            Sometimes need to call this manually after complex form loads
            */
            if (this.isFormField) {    // Is this check necessary?
                var parentForm = this.findParentByType('form');

                var dollarFields = parentForm.findByType('dollarfield');
                Ext.each(dollarFields, function(dollarfield) { dollarfield.initSelf(); });
            }
        },

        clearDirty: function() {
            /* needed for a calculated display-only fields whose submitted value is ignored */
            this.originalValue = this.getRawValue();
        }

    });

    Ext.reg('dollarfield', Ext.ux.dollarField);

    Ext.apply(Ext.form.VTypes, {
        daterange: function(val, field) {
            var date = field.parseDate(val);

            var dispUpd = function(picker) {
                var ad = picker.activeDate;
                if (ad) {
                    picker.activeDate = null;
                    picker.update(ad);
                }
            };

            if (field.startDateField) {
                var sd = Ext.getCmp(field.startDateField);
                sd.maxValue = date;
                if (sd.menu && sd.menu.picker) {
                    sd.menu.picker.maxDate = date;
                    dispUpd(sd.menu.picker);
                }
            }
            else if (field.endDateField) {
                var ed = Ext.getCmp(field.endDateField);
                ed.minValue = date;
                if (ed.menu && ed.menu.picker) {
                    ed.menu.picker.minDate = date;
                    dispUpd(ed.menu.picker);
                }
            }
            return true;
        }
    });

    if (!Ext.isIE6) {
        if (Ext.isIE) {
            Ext.util.CSS.createStyleSheet(".x-btn button{width:100%;}");
        }
        Ext.util.CSS.createStyleSheet(".x-form-radio-group .x-panel-body,.x-form-check-group .x-panel-body{background-color:transparent;}.x-form-cb-label-nowrap{white-space:nowrap;}");
    }
    
    Coolite.Ext.setTheme = function(url) {
        var token = "COOLITE_EXT_THEME";
        if (url === "Default") {
            Ext.util.CSS.removeStyleSheet(token);
        } else {
            Ext.util.CSS.swapStyleSheet(token, url);
        }
    };

    Coolite.Ext.getEl = function(el) {
        if (el.getEl) {
            return el.getEl();
        }

        var cmp = Ext.getCmp(el);
        if (!Ext.isEmpty(cmp)) {
            return cmp.getEl();
        }

        return Ext.get(el);
    };

if(typeof Sys!=="undefined"){Sys.Application.notifyScriptLoaded();}