Ext.ns('Imhotep');

Imhotep.toast = function(config) {
    var config = config || {};
    var internal_config = {
        title: 'Message',
        autoDestroy: true,//default = true
        autoHeight: true,
        autoHide: true,//default = true
        bodyStyle: 'text-align:center; padding: 10px;',
        handleHelp: function(){
        //console.info('help requested');
        },
        hideFx: {
            delay: 5000,
            //duration: 0.25,
            mode: 'standard',//null,'standard','custom',or default ghost
            useProxy: false //default is false to hide window instead
        },
        html: 'No message...',
        iconCls: 'icon-info',

        //optionally enable sound...see http://efattal.fr/extjs/examples/toastwindow/
        //if you want to enable sound with this
        /*
        listeners: {
            'beforerender': function() {
                Sound.enable();
                Sound.play(this.config.path.component + 'burp.wav');
                Sound.disable();
            },
            scope: this
        },
        */

        showFx: {
            delay: 0,
            //duration: 0.5, //defaults to 1 second
            mode: 'standard',//null,'standard','custom',or default ghost
            useProxy: false //default is false to hide window instead
        },
        width: 250 //optional (can also set minWidth which = 200 by default)
    };
    Ext.applyIf(config, internal_config);
    new Ext.ux.window.MessageWindow(config).show(Ext.getDoc());
},

Imhotep.Ajax = {

    /**
     * Tableau des codes HTTP dont on ne veut pas en afficher l'erreur par
     * cette classe, parce qu'elle est geree ailleurs (par exemple le cas
     * du testeur d'autentification)
     * @var array
     */
    skippedStatus: [],

    /**
     * Methode generale qui affiche un probleme en cas de non succes du script
     * mais de succes quand meme au niveau du dialogue client-serveur
     *
     * @param object cfg un objet de config pour la boite de message
     * @return void
     */
    unsuccess: function(cfg) {
        var c = cfg || {};
        Ext.Msg.show(Ext.apply({
            title   : c.title || 'Error',
            msg     : c.msg || c.error || c.message || 'Error',
            buttons : Ext.Msg.OK,
            icon    : Ext.Msg.ERROR
        }, c));
    },

    /**
     * Methode generale qui affiche un probleme en cas de non succes du
     * dialogue client-serveur
     *
     * @param XmlHttpRequest response
     * @param Object cfg
     * @return void
     */
    failure: function(response, cfg) {
        // si le status vaut "non autorise", on skip la failure
        for (var i = 0; i < Imhotep.Ajax.skippedStatus; i++) {
            if (response.status == Imhotep.Ajax.skippedStatus[i]) return;
        }

        // autrement, on gere le message d'erreur
        var str = '';
        if (Ext.isObject(response)) {
            for (var i in response) {
                str += i + ' : ' + response[i];
            }
        }
        Imhotep.Ajax.unsuccess(Ext.apply({
            msg: str,
            title: response.statusText
        }, cfg || {}));
    },

    /**
     * Affiche une erreur de maniere comprehensible
     *
     * @param Exception e
     * @param Object cfg
     * @return void
     */
    error: function(e, cfg) {
        cfg = cfg || {};
        // autrement, on gere le message d'erreur
        var str = '';
        for (var i in e) {
            if (!cfg.stack && i === 'stack') continue;
            str += i + ' : ' + e[i] + '<br/>';
        }
        Imhotep.Ajax.unsuccess(Ext.apply({
            msg: str,
            title: 'error'
        }, cfg || {}));
    },

    /**
     * Retourne le json de la reponse serveur
     *
     * Necessite que le json ait une cle "success" qui vaudra true ou false
     * et une cle "error" si "success" = false
     *
     * @param XMLHttpRequest response
     * @param boolean setSuccessIfUndefined mettre true pour setter automatiquement json.success a true s'il n'est pas defini
     * @return Object
     */
    getJsonResponse: function(response, setSuccessIfUndefined) {
        var json = {};
        try {
            json = Ext.decode(response.responseText);
            // si le success n'est pas defini, on le set a true, signifiant
            // que tout est ok
            if (setSuccessIfUndefined && !Ext.isDefined(json.success)) {
                json.success = true;
            }
        } catch(e) {
            json = {success: false, error: response.responseText};
        }
        return json;
    }

};

Imhotep.lib = {
    
    /**
     * ----------------------------------------------------------------------------
     *                METHODS
     * ----------------------------------------------------------------------------
     */
    
    /**
     * Load a js file in the HTML flow
     *
     * @param string className the classname of the file to load (like Zend_Loader)
     * @return void
     */
    loadClass: function(className, path) {
        var tmp = className.split('_');
        // remove 1st index (because it's the "jscripts" folder)
        tmp.shift();
        var libraryName = path + tmp.join('/') + '.js';
        // inserting via DOM fails in Safari 2.0, so brute force approach
        document.write('<script type="text/javascript" src="' + libraryName + '"></script>');
    },
    /**
     * Load an array of js files in the HTML flow
     *
     * @param array classes classnames to load (like Zend_Loader)
     * @return void
     */
    loadClasses: function(classes, path) {
        for (var i = 0; i < classes.length; i++) {
            Imhotep.lib.loadClass(classes[i], path);
        }
    },
	
    is_object: function( mixed_var ){
        // http://kevin.vanzonneveld.net
        // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
        // +   improved by: Legaev Andrey
        // +   improved by: Michael White (http://crestidg.com)
        // *     example 1: is_object('23');
        // *     returns 1: false
        // *     example 2: is_object({foo: 'bar'});
        // *     returns 2: true
        // *     example 3: is_object(null);
        // *     returns 3: false
	 
        if(mixed_var instanceof Array) {
            return false;
        } else {
            return (mixed_var !== null) && (typeof( mixed_var ) == 'object');
        }
    },

    applyAmbiguous: function(object, ambiguous) {
        if (Ext.isArray(ambiguous)) {
            ambiguous = {};
        }

        return Ext.apply(object, ambiguous);
    },
    
    /**
     * ----------------------------------------------------------------------------
     *                OBJECTS
     * ----------------------------------------------------------------------------
     */
    String: {
        ucfirst: function(str) {
            return str.substr(0,1).toUpperCase() + str.substr(1,str.length);
        }
    },
    Wrapper: {
        /**
         * Get an HTML element with its id
         *
         * @param string id obj the id of the HTML element
         * @return HTMLelement
         */
        get : function (obj) {
            return $(obj);
        },
        /**
         * Observer for an element
         */
        observe : function (obj, evName, func, moz) {
            Event.observe(obj, evName, func, moz);
            return $(element);
        },
        /**
         * Get an array of elements with CSS selector
         *
         * @param string selector the CSS selector
         * @return array an array of HTML elements
         */
        getElementsByClassName : function (selector) {
            return $$(selector);
        },
        /**
         * Add a CSS classname to the HTML element
         *
         * @param string id obj the id of the HTML element
         * @param string cls the CSS classname to add
         * @return HTMLelement given
         */
        addClassName : function (obj, cls) {
            $(obj).addClassName(cls);
            return $(obj);
        },
        /**
         * Remove a CSS classname to the HTML element
         *
         * @param string id obj the id of the HTML element
         * @param string cls the CSS classname to remove
         * @return HTMLelement given
         */
        removeClassName : function (obj, cls) {
            $(obj).removeClassName(cls);
            return $(obj);
        },
        /**
         * In an event context, to be sure to get the right element (by css classname),
         * even if it was one of its sub-element that triggered the event.
         *
         * @param event The triggered event
         * @param classname The CSS classname that identifies the element to fetch
         * @return HTMLelement
         */
        getElementWithClassNameInsideEvent: function(event, classname) {
            var elem;
            if (event.element().hasClassName(classname)) {
                elem = event.element();
            } else {
                elem = event.element().up('.' + classname);
            }

            return elem;
        }
    },
    Debug: {
        /**
         * Display an object. Clear content in container before display
         *
         * @param Object obj object to check
         * @param string html element id in which to put object content
         * @param boolean add true for adding content instead of clearing it
         * @return void
         */
        show: function (obj, html, add) {
            var str = '';
            if (typeof obj == 'object') {
                for (var i in obj) {
                    str += i + ' : ' + obj[i] + '<br/><br/>';
                }
            } else {
                str = obj;
            }
            if (!html) html = 'debug';
            if (add) {
                document.getElementById(html).innerHTML += str;
            } else {
                document.getElementById(html).innerHTML = str;
            }
        },
        /**
         * Display an object after the content which is already displayed
         *
         * @param Object obj object to check
         * @param string html element id in which to put object content
         * @return void
         */
        add: function (obj, html) {
            this.show(obj, html, true);
        }
    },
    Image: {
        switchSrcOver: function(img) {
            var src_img = img.getAttribute('src');
            var arr_src_img = src_img.split('/');
            var img_name = arr_src_img.pop();
            if (img_name.include('_over.')) {
                img_name = img_name.gsub('_over.', '.');
            } else {
                var arr_img_name = img_name.split('.');
                var ext = arr_img_name.pop();
                img_name = arr_img_name.join('.') + '_over.' + ext;
            }
            img.setAttribute('src', arr_src_img.join('/') + '/' + img_name);
        }
    },
    Animation: {
        _toastInfo: Imhotep.toast
    }
};

if (typeof Ext != 'undefined') {

Ext.onReady(function(){
    ///
    // Set des boutons de changement de langue
    ///
    var languages = Ext.query('.imhotep-language');
    for (var i = 0; i < languages.length; i++) {
        Ext.EventManager.on(languages[i], 'click', function() {
            var id = this.id.split('_')[2];
            window.location.href = window.location.href + '&lang=' + id;
        }, languages[i]);
    }
});

Ext.override(Ext.Element, {
    contains : function(el){
        try {
            return !el ? false : Ext.lib.Dom.isAncestor(this.dom, el.dom ? el.dom : el);
        } catch(e) {
            return false;
        }
    }
});
Ext.override(Ext.grid.GridView, {
    handleHdMenuClick : function(item){
        var index = this.hdCtxIndex;
        var cm = this.cm, ds = this.ds;
        switch(item.itemId){
            case "asc":
                ds.sort(cm.getDataIndex(index), "ASC");
                break;
            case "desc":
                ds.sort(cm.getDataIndex(index), "DESC");
                break;
            default:
                index = item.itemId ? cm.getIndexById(item.itemId.substr(4)) : -1;
                if(index != -1){
                    if(item.checked && cm.getColumnsBy(this.isHideableColumn, this).length <= 1){
                        this.onDenyColumnHide();
                        return false;
                    }
                    cm.setHidden(index, item.checked);
                }
        }
        return true;
    }
});
Ext.override(Ext.layout.MenuLayout, {
    renderItem : function(c, position, target){
        if (!this.itemTpl) {
            this.itemTpl = Ext.layout.MenuLayout.prototype.itemTpl = new Ext.XTemplate(
                '<li id="{itemId}" class="{itemCls}">',
                    '<tpl if="needsIcon">',
                        '<img src="{icon}" class="{iconCls}"/>',
                    '</tpl>',
                '</li>'
            );
        }
        if(c && !c.rendered){
            if(Ext.isNumber(position)){
                position = target.dom.childNodes[position];
            }
            var a = this.getItemArgs(c);
            c.render(c.positionEl = position ?
                this.itemTpl.insertBefore(position, a, true) :
                this.itemTpl.append(target, a, true));
            c.positionEl.menuItemId = c.itemId || c.id;
            if (!a.isMenuItem && a.needsIcon) {
                c.positionEl.addClass('x-menu-list-item-indent');
            }
            this.configureItem(c, position);
        }else if(c && !this.isValidParent(c, target)){
            if(Ext.isNumber(position)){
                position = target.dom.childNodes[position];
            }
            target.dom.insertBefore(c.getActionEl().dom, position || null);
        }
    },
    getItemArgs: function(c) {
        var isMenuItem = c instanceof Ext.menu.Item;
        return {
            isMenuItem: isMenuItem,
            needsIcon: !isMenuItem && (c.icon || c.iconCls),
            icon: c.icon || Ext.BLANK_IMAGE_URL,
            iconCls: 'x-menu-item-icon ' + (c.iconCls || ''),
            itemId: 'x-menu-el-' + c.id,
            itemCls: 'x-menu-list-item' /*+ (this.extraCls || '')*/
        };
    }
});
Ext.override(Ext.layout.TableLayout, {
    renderItem : function(c, position, target){
        if(c && !c.rendered){
            c.render(this.getNextCell(c));
            /*if(this.extraCls){
                var t = c.getPositionEl ? c.getPositionEl() : c;
                t.addClass(this.extraCls);
            }*/
            this.configureItem(c, position);
        }
    }
});
Ext.override(Ext.layout.FormLayout, {
    renderItem : function(c, position, target){
        if(c && !c.rendered && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){
            var args = this.getTemplateArgs(c);
            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);
            this.configureItem(c, position);
        }else {
            Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
        }
    }
});
Ext.apply(Ext, {
    in_array: function(arr, val) {
        if (typeof arr == 'undefined' || arr.length == 0) return false;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] == val) return true;
        }
        return false;
    },
    applyAmbiguous: function(object, ambiguous) {
        if (Ext.isArray(ambiguous)) {
            ambiguous = {};
        }

        return Ext.apply(object, ambiguous);
    }
});
Ext.override(Ext.data.Store, {
    changeUrl: function(url) {
        this.proxy.url = url;
        this.proxy.conn.url = url;
        this.proxy.setUrl(url, true);
        for (var i in this.proxy.api) {
            this.proxy.api[i].url = url;
        }
        return this;
    }
});

Ext.override(Ext.grid.GridView, {
    doRender : function(cs, rs, ds, startRow, colCount, stripe){
        var ts = this.templates, ct = ts.cell, rt = ts.row, last = colCount-1;
        var tstyle = 'width:'+this.getTotalWidth()+';';
        // buffers
        var buf = [], cb, c, p = {}, rp = {tstyle: tstyle}, r;
        var groupIndex = null, groupColumn = null;
        if (typeof this.getGroupField == 'function') {
            var groupField = this.getGroupField();
            groupIndex = groupField ? this.cm.findColumnIndex(groupField) : null;
            var groupId = groupIndex ? this.cm.getColumnId(groupIndex) : null;
            groupColumn = groupId ? (this.cm.getColumnById(groupId) || {}) : {};
        }
        for(var j = 0, len = rs.length; j < len; j++){
            r = rs[j]; cb = [];
            var rowIndex = (j+startRow);
            for(var i = 0; i < colCount; i++){
                c = cs[i];
                p.id = c.id;
                p.css = i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
                p.attr = p.cellAttr = '';
                p.value = c.renderer.call(c.scope, r.data[c.name], p, r, rowIndex, i, ds);
                p.style = c.style;
                if(Ext.isEmpty(p.value)){
                    p.value = ' ';
                }
                if(this.markDirty && r.dirty && Ext.isDefined(r.modified[c.name])){
                    p.css += ' x-grid3-dirty-cell';
                }
                if (i === groupIndex && groupColumn.hideContentWhenGrouped) {
                    p.css += ' x-grid3-cell-content-hide ';
                }
                cb[cb.length] = ct.apply(p);
            }
            var alt = [];
            if(stripe && ((rowIndex+1) % 2 === 0)){
                alt[0] = 'x-grid3-row-alt';
            }
            if(r.dirty){
                alt[1] = ' x-grid3-dirty-row';
            }
            rp.cols = colCount;
            if(this.getRowClass){
                alt[2] = this.getRowClass(r, rowIndex, rp, ds);
            }
            rp.alt = alt.join(' ');
            rp.cells = cb.join('');
            buf[buf.length] =  rt.apply(rp);
        }
        return buf.join('');
    }
});
Ext.lib.Ajax.isCrossDomain = function(u) {
	var match = /(?:(\w*:)\/\/)?([\w\.]*(?::\d*)?)/.exec(u);
	if (!match[1]) return false; // No protocol, not cross-domain
	return (match[1] != location.protocol) || (match[2] != location.host);
};

Ext.override(Ext.data.Connection, {

    remoteRequest : function(o){
        if(this.fireEvent("beforerequest", this, o) !== false){
            var p = o.params;

            if(typeof p == "function"){
                p = p.call(o.scope||window, o);
            }
            if(typeof p == "object"){
                p = Ext.urlEncode(p);
            }
            if(this.extraParams){
                var extras = Ext.urlEncode(this.extraParams);
                p = p ? (p + '&' + extras) : extras;
            }

            var url = o.url || this.url;
            if(typeof url == 'function'){
                url = url.call(o.scope||window, o);
            }

            if(o.form){
                var form = Ext.getDom(o.form);
                url = url || form.action;

                var enctype = form.getAttribute("enctype");
                if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
                    return this.doFormUpload(o, p, url);
                }
                var f = Ext.lib.Ajax.serializeForm(form);
                p = p ? (p + '&' + f) : f;
            }

            var hs = o.headers;
            if(this.defaultHeaders){
                hs = Ext.apply(hs || {}, this.defaultHeaders);
                if(!o.headers){
                    o.headers = hs;
                }
            }

            var cb = {
                success: this.handleResponse,
                failure: this.handleFailure,
                scope: this,
                argument: {options: o},
                timeout : this.timeout
            };

            var method = o.method||this.method||(p ? "POST" : "GET");

            if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
                url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
            }

            if(typeof o.autoAbort == 'boolean'){ // options gets top priority
                if(o.autoAbort){
                    this.abort();
                }
            }else if(this.autoAbort !== false){
                this.abort();
            }
            if((method == 'GET' && p) || o.xmlData || o.jsonData){
                url += (url.indexOf('?') != -1 ? '&' : '?') + p;
                p = '';
            }
            if (o.scriptTag || this.scriptTag || Ext.lib.Ajax.isCrossDomain(url)) {
               this.transId = this.scriptRequest(method, url, cb, p, o);
            } else {
               this.transId = Ext.lib.Ajax.request(method, url, cb, p, o);
            }
            return this.transId;
        }else{
            Ext.callback(o.callback, o.scope, [o, null, null]);
            return null;
        }
    },

    scriptRequest : function(method, url, cb, data, options) {
        var transId = ++Ext.data.ScriptTagProxy.TRANS_ID;
        var trans = {
            id : transId,
            cb : options.callbackName || "stcCallback"+transId,
            scriptId : "stcScript"+transId,
            options : options
        };

        url += (url.indexOf("?") != -1 ? "&" : "?") + data + String.format("&{0}={1}", options.callbackParam || this.callbackParam || 'callback', trans.cb);

        var conn = this;
        window[trans.cb] = function(o){
            conn.handleScriptResponse(o, trans);
        };

//      Set up the timeout handler
        trans.timeoutId = this.handleScriptFailure.defer(cb.timeout, this, [trans]);

        var script = document.createElement("script");
        script.setAttribute("src", url);
        script.setAttribute("type", "text/javascript");
        script.setAttribute("id", trans.scriptId);
        document.getElementsByTagName("head")[0].appendChild(script);

        return trans;
    },

    handleScriptResponse : function(o, trans){
        this.transId = false;
        this.destroyScriptTrans(trans, true);
        var options = trans.options;

//      Attempt to parse a string parameter as XML.
        var doc;
        if (typeof o == 'string') {
            if (window.ActiveXObject) {
                doc = new ActiveXObject("Microsoft.XMLDOM");
                doc.async = "false";
                doc.loadXML(o);
            } else {
                doc = new DOMParser().parseFromString(o,"text/xml");
            }
        }

//      Create the bogus XHR
        response = {
            responseObject: o,
            responseText: (typeof o == "object") ? Ext.util.JSON.encode(o) : String(o),
            responseXML: doc,
            argument: options.argument
        }
        this.fireEvent("requestcomplete", this, response, options);
        Ext.callback(options.success, options.scope, [response, options]);
        Ext.callback(options.callback, options.scope, [options, true, response]);
    },

    handleScriptFailure: function(trans) {
        this.transId = false;
        this.destroyScriptTrans(trans, false);
        var options = trans.options;
        response = {
            argument:  options.argument,
            status: 500,
            statusText: 'Server failed to respond',
            responseText: ''
        };
        this.fireEvent("requestexception", this, response, options, {
            status: -1,
            statusText: 'communication failure'
        });
        Ext.callback(options.failure, options.scope, [response, options]);
        Ext.callback(options.callback, options.scope, [options, false, response]);
    },

    // private
    destroyScriptTrans : function(trans, isLoaded){
        document.getElementsByTagName("head")[0].removeChild(document.getElementById(trans.scriptId));
        clearTimeout(trans.timeoutId);
        if(isLoaded){
            window[trans.cb] = undefined;
            try{
                delete window[trans.cb];
            }catch(e){}
        }else{
            // if hasn't been loaded, wait for load to remove it to prevent script error
            window[trans.cb] = function(){
                window[trans.cb] = undefined;
                try{
                    delete window[trans.cb];
                }catch(e){}
            };
        }
    }
});


/**
 * Gere les vtype en combinaison avec le allowBlank
 */
Ext.apply(Ext.form.VTypes, {

    emailblank: function(val) {
        return val ? Ext.form.VTypes.email(val) : true;
    },

    emailblankText: Ext.form.VTypes.emailText,

    emailblankMask: Ext.form.VTypes.emailMask
});


if (typeof Ext.ux != 'undefined' && typeof Ext.ux.grid != 'undefined' && typeof Ext.ux.grid.RowEditor != 'undefined') {
    Ext.override(Ext.ux.grid.RowEditor, {
        // ajout d'un if (f) pour eviter un bug si on a des colonnes hidden: true
        startEditing: function(rowIndex, doFocus){
            if(this.editing && this.isDirty()){
                this.showTooltip(this.commitChangesText);
                return;
            }
            if(Ext.isObject(rowIndex)){
                rowIndex = this.grid.getStore().indexOf(rowIndex);
            }
            if(this.fireEvent('beforeedit', this, rowIndex) !== false){
                this.editing = true;
                var g = this.grid, view = g.getView(),
                    row = view.getRow(rowIndex),
                    record = g.store.getAt(rowIndex);

                this.record = record;
                this.rowIndex = rowIndex;
                this.values = {};
                if(!this.rendered){
                    this.render(view.getEditorParent());
                }
                var w = Ext.fly(row).getWidth();
                this.setSize(w);
                if(!this.initialized){
                    this.initFields();
                }
                var cm = g.getColumnModel(), fields = this.items.items, f, val;
                for(var i = 0, len = cm.getColumnCount(); i < len; i++){
                    val = this.preEditValue(record, cm.getDataIndex(i));
                    f = fields[i];
                    if (f) {
                        f.setValue(val);
                        this.values[f.id] = Ext.isEmpty(val) ? '' : val;
                    }
                }
                this.verifyLayout(true);
                if(!this.isVisible()){
                    this.setPagePosition(Ext.fly(row).getXY());
                } else{
                    this.el.setXY(Ext.fly(row).getXY(), {duration:0.15});
                }
                if(!this.isVisible()){
                    this.show().doLayout();
                }
                if(doFocus !== false){
                    this.doFocus.defer(this.focusDelay, this);
                }
            }
        }
    });
}


if (typeof Ext.ux != 'undefined' && typeof Ext.ux.grid != 'undefined' && typeof Ext.ux.grid.RowActions != 'undefined') {

    if (typeof Ext.ux.grid.RowActions.getEditor !== 'function') Ext.ux.grid.RowActions.prototype.getEditor = Ext.emptyFn;

    Ext.override(Ext.ux.grid.RowActions, {
	tplRow:
		 '<div class="ux-row-action">'
		+'<tpl for="actions">'
		+'<div class="ux-row-action-item {cls} <tpl if="text">'
		+'ux-row-action-text</tpl>" style="{hide}{style}" qtip="{qtip}">'
                +'<tpl if="href"><a href="{href}" target="{target}">'
                    +'<tpl if="text"><span qtip="{qtip}">{text}</span></tpl>'
                    +'<tpl if="!text">&nbsp;</tpl>'
                +'</a></tpl>'
                +'<tpl if="!href"><tpl if="text"><span qtip="{qtip}">{text}</span></tpl></tpl>'
		+'</div></tpl>'
		+'</div>',

        getData:function(value, cell, record, row, col, store) {
            var opts = {};
            var a, index, str;
            for (var i in this.actions) {
                a = this.actions[i];
                if (a.href) {
                    index = (a.iconIndex || a.iconCls) + 'href';
                    if (typeof a.hrefFn == 'function') {
                        opts[index] = a.scope ? a.hrefFn.call(a.scope, a, record, cell, row, col, store) : a.hrefFn(a, record, cell, row, col, store);
                    } else if (a.hrefParams) {
                        str = '';
                        for (var j = 0; j < a.hrefParams.length; j++) {
                            if (record.get(a.hrefParams[j])) {
                                str += ', record.get(a.hrefParams[' + j + '])';
                            } else {
                                str += ', a.hrefParams[' + j + ']';
                            }
                        }
                        opts[index] = eval('String.format(a.href' + str + ');');
                    } else {
                        opts[index] = a.href;
                    }
                }
            }
            return Ext.apply(record.data || {}, opts);
	},

        processActions:function(actions, template) {
            var acts = [];

            // actions loop
            Ext.each(actions, function(a, i) {
                    // save callback
                    if(a.iconCls && 'function' === typeof (a.callback || a.cb)) {
                            this.callbacks = this.callbacks || {};
                            this.callbacks[a.iconCls] = a.callback || a.cb;
                    }

                    // data for intermediate template
                    var o = {
                             cls:a.iconIndex ? '{' + a.iconIndex + '}' : (a.iconCls ? a.iconCls : '')
                            ,href: a.href ? '{' + (a.iconIndex || a.iconCls) + 'href}' : null
                            ,target: a.target || '_self'
                            ,qtip:a.qtipIndex ? '{' + a.qtipIndex + '}' : (a.tooltip || a.qtip ? a.tooltip || a.qtip : '')
                            ,text:a.textIndex ? '{' + a.textIndex + '}' : (a.text ? a.text : '')
                            ,hide:a.hideIndex
                                    ? '<tpl if="' + a.hideIndex + '">'
                                            + ('display' === this.hideMode ? 'display:none' :'visibility:hidden') + ';</tpl>'
                                    : (a.hide ? ('display' === this.hideMode ? 'display:none' :'visibility:hidden;') : '')
                            ,align:a.align || 'right'
                            ,style:a.style ? a.style : ''
                    };
                    acts.push(o);

            }, this); // eo actions loop

            var xt = new Ext.XTemplate(template || this.tplRow);
            return new Ext.XTemplate(xt.apply({actions:acts}));

	}
    });

}

Ext.data.Types.JSON = {
    convert: function(v, data) {
        try {
            return eval(v)
        } catch(e) {
            Imhotep.Ajax.error(e);
        }
    },
    sortType: function(v) {
        return 1;
    },
    type: 'json'
};

}