// define Pelorous namespace
Ext.namespace('Pelorous', 'Pelorous.viewport', 'Pelorous.tinyMce', 'Pelorous.gridRenderer');

// define default state provider
Ext.state.Manager.setProvider(
    new Ext.state.CookieProvider({expires: null})
);


Pelorous.security = function() {
    var userRoles = {};
    
    return {
        WEB_ADMIN: 'Web Admin',
        WORKSPACE_ADMIN: 'Workspace Admin',
        DEVELOPER: 'Developer',
        
        /**
         * Check if current logged in user has one or more roles
         * 
         * @param {Array} roles
         * @return void
         */
        hasRoles: function(roles, callback) {
            // make sure we have a valid callback function
            if (typeof callback == 'undefined') {
                alert('callback function not defined');
            }
            
            // check cache and work out which roles still need checking
            var result = {};
            var toCheck = [];
            for (var i = 0; i < roles.length; i++) {
                if (typeof userRoles[roles[i]] != 'undefined') {
                    result[roles[i]] = userRoles[roles[i]];
                } else {
                    toCheck.push(roles[i]);
                }
            }
            
            if (toCheck.length > 0) {
                Ext.Ajax.request({
                    url: '/xhr_has_roles/',
                    params: { 'roles[]': toCheck },
                    success: function(r) {
                        var response = Ext.decode(r.responseText);
                        for (var i = 0; i < toCheck.length; i++) {
                            userRoles[toCheck[i]] = response[toCheck[i]];
                            result[toCheck[i]] = response[toCheck[i]];
                        }
                        callback(result);
                    }
                });
            } else {
                callback(result);
            }
        },
        
        /**
         * Check if current logged in user has a given role
         * 
         * @param {String} role
         * @return void
         */
        hasRole: function(role, callback){
            Pelorous.userHasRoles([role], callback);
        }
    };
}();

/**
 * Viewport
 */
Pelorous.viewport = function () {
    var showHeader = true,
        showLeftMenu = false,
        initialised = false,
        replacementIds = [],
        centerPanelReplacement = null;
    
    return {
        header : new Ext.Panel({
            id: 'viewportHeader',
            region:'north',
            border: false,
            contentEl: 'header',
            height: 40,
            hidden: true,
            margins:'0 0 5 0'
        }),
        
        cardPanel: new Ext.Panel({
            region: 'center',
            layout: 'card'
        }),
        
        centerPanel: null,
        
        leftMenu : new Ext.Panel({
            title: 'Main Menu',
            region:'west',
            border: false,
            bodyStyle: 'border-top: 1px solid #99BBE8;',
            margins:'0 0 5 5',
            cmargins: '0 0 5 0',
            split:true,
            width: 160,
            minSize: 135,
            maxSize: 200,
            collapsible: true,
            animCollapse: false,
            hidden: true,
            stateful: true,
            stateId: 'viewPortLeftMenu',
            stateEvents: [ 'collapse', 'expand' ],
            collapseMode: 'mini',
            layout:'accordion',
            cls: 'mainMenu'
        }),
        
        /**
         * Initialise and display view port
         */
        init : function() {
            if (initialised) { return; }

            var topMargin = (showHeader) ? 0 : 5;
            var leftMargin = (showLeftMenu) ? 0 : 5;
            
            var margins = (showLeftMenu) ? topMargin + ' 5 5 ' + leftMargin : topMargin + ' 5 5 ' + leftMargin;
            
            
            this.centerPanel = new Ext.Panel({
                region: 'center',
                contentEl: 'pageContent',
                autoScroll: false,
                border: true,
                layout: 'fit',
                margins: margins
            });
            this.centerPanel.on('afterrender', function(p){
                if (centerPanelReplacement) {
                    p.removeAll();
                    p.add(centerPanelReplacement);
                }
            });

            if (showHeader) {
                this.header.show();
            }
            
            if (showLeftMenu) {
                this.leftMenu.show();
            }
        
            this.viewport = new Ext.Viewport({
                layout: 'border',
                items: [
                    this.header,
                    this.centerPanel,
                    this.leftMenu
                ]
            });
            
            // init publishing object
            Pelorous.publishing.init();
            
            initialised = true;
        },

        /**
         * Set value for show header
         * 
         * @return    void
         */
        setShowHeader: function(val) {
            showHeader = val;
        },

        /**
         * Set value for show left menu
         * 
         * @return    void
         */
        setShowLeftMenu: function(val) {
            showLeftMenu = val;
        },
        
        /**
         * Add item to left menu
         * 
         * @return  void
         */
        addLeftMenuItem: function(item) {
            if (!showLeftMenu) {
                showLeftMenu = true;
            }
            this.leftMenu.add(item);
        },
        
        /**
         * Set menu title
         * 
         * @return    void
         */
        setMenuTitle: function(title) {
            this.leftMenu.setTitle(title);
        },
        
        replaceCenterPanel: function(newItem) {
            if (this.centerPanel === null) {
                centerPanelReplacement = newItem;
                
            } else {
                this.centerPanel.removeAll();
                this.centerPanel.add(newItem);
                this.centerPanel.doLayout();
            }
        }
    };
}();

Pelorous.fetchedScripts = [];

/**
 * Include a dependant javascript file
 * 
 * @param   {String} script
 * @param   {Function} callback
 * @return  void
 */
Pelorous.includeScript = function(script, callback) {
    // if we have an array of items, recurse through each one
    if (script instanceof Array) {
        if (script.length == 1) {
            Pelorous.includeScript(script[0], callback);
            return;
        } else {
            // fetch script
            scriptSrc = script.pop();
            
            // if script has already been included, move on to next one
            for (var i in Pelorous.fetchedScripts) {
                if (Pelorous.fetchedScripts[i] == scriptSrc) {
                    Pelorous.includeScript(script, callback);
                    return;
                }
            }
            
            // fetch current script, and move on to next one
            $.getScript(scriptSrc, function(data, status) {
                Pelorous.fetchedScripts.push(scriptSrc);
                Pelorous.includeScript(script, callback);
            });
            
            return;
        }
    }
    
    // make sure we have a valid callback function
    if (typeof callback == 'undefined') {
        callback = function() {};
    }
    
    // if script has already been included, just call callback
    for (var i in Pelorous.fetchedScripts) {
        if (Pelorous.fetchedScripts[i] == script) {
            try {
                callback();
            } catch (e) {
                alert(e);
            }
            
            return;
        }
    }
    
    // fetch script
    $.getScript(script, function(data, status) {
        Pelorous.fetchedScripts.push(script);
        try {
            // apply call back
            callback();
        } catch (e) {
            alert(e);
        }
    });
};

/**
 * Tiny Mce Manager
 */
Pelorous.tinyMce = function() {
    var initialised = false;
    
    var defaultConfig = {
        script_url : '/javascript/external/tiny_mce/3.2.7.jquery/tiny_mce.js',
        mode: "none",
        theme: "advanced",
        theme_advanced_toolbar_location: "top",
        theme_advanced_toolbar_align: "left",
        theme_advanced_buttons1: "pastetext,pasteword,|,forecolor,backcolor,|,bold,italic,bullist,numlist,outdent,indent,|,justifyleft,justifycenter,justifyright,|,image,media,|,cleanup,removeformat,|,code,link",
        theme_advanced_buttons2: "styleselect,formatselect,fontsizeselect",
        theme_advanced_buttons3: "",
        //force_br_newlines : true,
        forced_root_block : "",
        relative_urls : false,
        convert_urls: false,
        external_link_list_url: "/site_manager/xhr_tiny_mce_internal_links/",
        plugins: "inlinepopups,advimage,media,style,layer,table,paste,directionality,visualchars,nonbreaking,xhtmlxtras,safari",
        paste_create_paragraphs : false,
        paste_create_linebreaks : false,
        paste_use_dialog : true,
        paste_auto_cleanup_on_paste : true,
        paste_convert_middot_lists : false,
        paste_unindented_list_class : "unindentedList",
        paste_convert_headers_to_strong : true,
        extended_valid_elements: "a[name|href|target|title|onclick],iframe[src|width|height|name|align|frameborder]",
        accessibility_warnings : false,
        content_css : "/cms/custom_css/styles/"
        /*,
        setup: function(ed) {
            ed.addButton("link", {
                title: "Link",
                onclick: function (evt) {
                    displayTinyMceLinkEditor(ed, evt);
                }
            });
        }
        */
    };
    
    var addEditor = function(selector, config, customPlugins) {
        var finalConfig = defaultConfig;
        for (var i in config) {
            finalConfig[i] = config[i];
        }
        initialised = true;
        
        $(selector).tinymce(finalConfig);
    };
        
    /**
     * Display custom link editor for tinymce
     * 
     * @param {HtmlElement} ed
     * @return void
     */
    var displayTinyMceLinkEditor = function(ed, evt) {
        var linkSelector;
        
        var win = new Ext.Window({
            title: 'Link Editor',
            modal: true,
            shadow: false,
            width: 400,
            height: 150,
            tbar: [{
                text: 'Done',
                iconCls: 'save-icon',
                handler: function() {
                    var link = Ext.fly('linkEditorLink').getValue();
                    
                    // if an existing link is being edited, use jquery 
                    // to update it
                    var node = ed.selection.getNode();
                    if (node.nodeName == 'A') {
                        var aTag = $(node);
                        aTag.attr('href', link);
                        if (Ext.getDom('linkEditorOpenInNewWindow').checked) {
                            aTag.attr('target', '_blank');
                        } else {
                            aTag.attr('target', '');
                        }
                        
                    // use tinymce to insert new links
                    } else {
                        var html = '<a href="' + link + '"';
                        if (Ext.getDom('linkEditorOpenInNewWindow').checked) {
                            html += ' target="_blank"';
                        }
                        html+= '>' 
                             + ed.selection.getContent({ format: 'text'})
                             + '</a>';
                             alert(html);
                             return;
                        ed.selection.setContent(html);
                    }
                    
                    win.close();
                }   
            },'->',{
                text: 'Cancel',
                iconCls: 'cancel-icon',
                handler: function() {
                    win.close();
                }
            }]
        });
        
        win.show();
        win.load({
            url: '/site_manager/xhr_tiny_mce_link_editor/',
            callback: function() {
                Pelorous.includeScript(
                    '/site_manager/javascript/Site.LinkSelector.js',
                    function() {
                        var linkSelectorConfig = {
                            form: 'tinyMceLinkEditor',
                            field: 'linkEditorLink',
                            displayField: 'linkEditorLinkDisplay'
                        };
                        
                        var node = ed.selection.getNode();
                        if (node.nodeName == 'A') {
                            linkSelectorConfig.value = $(node).attr('href');
                            if (node.target == '_blank') {
                                Ext.getDom('linkEditorOpenInNewWindow').checked = true;
                            }
                        }
                        
                        linkSelector = new Site.LinkSelector(linkSelectorConfig);
                        linkSelector.apply();
                        
                        /*
                        var button = '<img src="/images/tinymce-file-browser.gif" '
                                   + 'id="tinyLinkSelectorFileBrowser" '
                                   + 'class="clickable" width="16" height="16" />';
                        Ext.fly('linkEditorLinkDisplay-element').insertHtml('beforeEnd', button);
                        
                        Ext.fly('tinyLinkSelectorFileBrowser').on('click', function() {
                            displayTinyMceLinkEditorFileBrowser();
                        });
                        */
                    }
                );
            }
        });
    };
    
    var displayTinyMceLinkEditorFileBrowser = function() {
        // @todo
    };
    
    return {
        /**
         * Add editor(s)
         * 
         * @param  {String} selector
         * @param  {Object} config
         * @param  {Array|Function} customPlugins
         * @return void
         */
        addEditor: function(selector, config, customPlugins) {
            if (Object.prototype.toString.call(customPlugins) !== '[object Array]') {
                Pelorous.tinyMce.addEditor(selector, config, [customPlugins]);
                return;
            }
            
            Pelorous.includeScript(
                '/javascript/external/tiny_mce/3.2.7.jquery/jquery.tinymce.js',
                function() {
                    for (var i = 0; i < customPlugins.length; i++) {
                     //   (customPlugins[i])();
                    }
                    addEditor(selector, config);
                }
            );
        },
        
        /**
         * getDefaultConfig
         * 
         * @return array config
         */
        getDefaultConfig: function() {
            return defaultConfig;
        },

        /**
         * Media manager filebrowser plugin
         * 
         * @param  {String} fieldName
         * @param  {String} url
         * @param  {String} type
         * @param  {Ext.Window} win
         * @return false
         */
        mediaManagerBrowser: function(fieldName, url, type, win) {
           
            var cmsURL = '/media_manager/?tinyMCECall=1';
            if (cmsURL.indexOf("?") < 0) {
                //add the type as the only query parameter
                cmsURL = cmsURL + "?type=" + type;
            }
            else {
                //add the type as an additional query parameter
                // (PHP session ID is now included if there is one at all)
                cmsURL = cmsURL + "&type=" + type;
            }
    
            tinyMCE.activeEditor.windowManager.open({
                file : cmsURL,
                title : 'Pelorous Media Manager',
                width : 620,
                height : 500,
                resizable : "yes",
                inline : "yes",
                close_previous : "no"
            },{
                window : win,
                input : fieldName
            });
            
            return false;
        }
    };
}();

/**
 * Extjs grid renderers
 */
Pelorous.gridRenderer = function() {
    return {
        bit: function (value) {
            return (value == 1) ? 'Y' : 'N';
        },

        date: function (value, metaData, record) {
            var v = Ext.util.Format.date(value, 'd/m/Y');
            if (v == '28/02/1900') {
                return;
            }
            return v;
        },

        dateTime: function (value, metaData, record) {
            var v = Ext.util.Format.date(value, 'd/m/Y H:i');
            if (v == '28/02/1900 00:00') {
                return;
            }
            return v;
        },
        
        decimal: function(value) {
            return Ext.util.Format.number(value, '0.00');
        },
        
        ukMoney: function(value) {
            return '&pound;' + value.toFixed(2);
        },
        

        combo: function(combo) {
            return function(value, meta, record) {
                var returnValue = value;
                var valueField = combo.valueField;
                    
                var idx = combo.store.findBy(function(record) {
                    if (record.get(valueField) == value) {
                        returnValue = record.get(combo.displayField);
                        return true;
                    }
                });
                
                return returnValue;
             };
        }
    };
}();

// Some utility functions
/**
 * Loading message
 * 
 * @param   {String} message
 * @return  {String}
 */
Pelorous.loadingMessage = function(message) {
    var html = '<div style="background: url(\'/images/loading.gif\') ' 
             + 'no-repeat; padding-left: 20px; margin: 5px; height: 18px;">'
             + message + '</div>';
    
    return html;
};

/**
 * Display status message
 * 
 * @param   {String} message
 * @param   {Number} width
 * @return  void
 */
Pelorous.statusMessage = function(message, width, fn) {
    width = width || 600;
    fn = fn || null;
    Ext.Msg.show({
        title: 'Status',
        msg: message,
        width: width,
        buttons: Ext.Msg.OK,
        fn: fn
    });
};


/**
 * Work out max z-index of a component
 * 
 * Code below original taken from http://www.west-wind.com/Weblog/posts/876332.aspx
 * 
 * @params  {Object} opt
 * @return  Number
 */
Pelorous.maxZIndex = $.fn.maxZIndex = function(opt) {
    var def = { inc: 10, group: "*" };
    $.extend(def, opt);
    var zmax = 0;
    $(def.group).each(function() {
        var cur = parseInt($(this).css('z-index'));
        zmax = cur > zmax ? cur : zmax;
    });
    if (!this.jquery)
        return zmax;

    return this.each(function() {
        zmax += def.inc;
        $(this).css("z-index", zmax);
    });
}

/**
 * Add query date picker to components
 * 
 *  @param  {String} selector
 *  @return void
 */
Pelorous.addDatePicker = function(selector, config) {
    config = config || {};
    defaultConfig = {
        dateFormat: 'yy-mm-dd',
        changeMonth: true,
        changeYear: true,
        showButtonPanel: true,
        showOn: 'both',
        buttonImage: '/images/calendar.gif',
        buttonImageOnly: true,
        beforeShow: function() { 
            $('#ui-datepicker-div').maxZIndex(); 
        }
    };
    
    for (var i in config) {
        defaultConfig[i] = config[i];
    }
    
    $(selector).datepicker(defaultConfig);
}

/**
 * Data manager class - instantiate to create a new data manager
 * 
 * @param   {Object} config
 * @return  void
 */
Pelorous.dataManager = function(config) {
    var dataManager = this,
        win = null,
        formId = null,
        selectedItemId = null;
    
    // set some defaults
    config.region     = config.region || 'center';
    config.winWidth   = config.winWidth || 250;
    config.winHeight  = config.winHeight || 150;
    config.itemName   = config.itemName || 'Item';
    config.hideAddNew = config.hideAddNew || false;
    config.hideDelete = config.hideDelete || false;
    config.baseParams = config.baseParams || {};
    
    config.hidePublishTab = config.hidePublishTab || false;
    if (!config.hidePublishTab) {
        config.publish = config.publish || {};
        config.publish.types = config.publish.types || [];
        config.publish.lookups = config.publish.lookups || {};
    }
    
    // make sure we have a valid window load callback function
    if (typeof config.winLoadCallback == 'undefined') {
        config.winLoadCallback = function() {};
    }
    
    if (!config.createUrl && config.url) {
        config.createUrl = config.url;
    }
    if (!config.editUrl && config.url) {
        config.editUrl = config.url;
    }
    if (!config.deleteUrl && config.url) {
        config.deleteUrl = config.url;
    }
    
    /**
     * Reload grid
     * 
     * @return  void
     */
    var reloadGrid = function() {
        dataManager.grid.getStore().reload();
        selectedItemId = null;
    };
    
    var completeAction = function(url, params, msg) {
        var loadMask = new Ext.LoadMask(win.getId(), { msg: msg });
        loadMask.show();
        
        Ext.Ajax.request({
            url: url,
            form: formId,
            params: params,
            success: function(r) {
                loadMask.hide();
                var response = Ext.decode(r.responseText);
                if (response.success) {
                    win.close();
                    reloadGrid();
                } else {
                    Pelorous.statusMessage(response.content);
                }
            },
            failure: function(r) {
                loadMask.hide();
            }
        });
    };

    /**
     * Do form action
     *
     * @param   {String} action One of 'create', 'update' or 'delete'
     * @return  void
     */
    var doAction = function(action) {
        var msg = '', params = {};

        for (var i in config.baseParams) {
            params[i] = config.baseParams[i];
        }
        
        if (action == 'create') {
            params.create = 1;
            
            if (config.preCreate) {
                config.preCreate();
            }
            if (config.preSave) {
                config.preSave();
            }
            
            completeAction(config.createUrl, params, 'Saving...');
        } else if (action == 'update') {
            params.update = 1;
            
            if (config.preUpdate) {
                config.preUpdate();
            }
            if (config.preSave) {
                config.preSave();
            }
            
            completeAction(config.editUrl, params, 'Saving...');
        } else if (action == 'delete') {
            params['delete'] = 1;

            if (config.preDelete) {
                config.preDelete();
            }
            
            var title = 'Delete Confirmation';
            var message = 'Are you sure you want to delete this item?';
            Ext.MessageBox.confirm(title, message, function(btn){
                if (btn == 'yes') {
                    completeAction(config.deleteUrl, params, 'Deleting...');
                }
            });
        }
    };

    /**
     * Open window
     *
     * @param   {Boolean} edit To signify if this is an edit or create window
     * @return  void
     */
    var openWin = function(edit) {
        if (win) { win.close(); }
        edit = edit || false;
        
        var title = '';
        var deleteButtonHidden = true;
        var action = null;
        
        params = { '_noJson': 1 };
        for (var i in config.baseParams) {
            params[i] = config.baseParams[i];
        }
        for (var i in config.extraParams) {
            params[i] = config.extraParams[i];
        }
        
        if (edit) {
            action = 'update';
            title = 'Edit ' + config.itemName;
            params[config.idField] = selectedItemId;
            url = config.editUrl;
            deleteButtonHidden = config.hideDelete;
        } else {
            action = 'create';
            title = 'Add New ' + config.itemName;
            url = config.createUrl;
        }

        win = new Ext.Window({
            title: title,
            plain: true,
            modal: true,
            shadow: false,
            width: config.winWidth,
            height: config.winHeight,
            autoScroll: true,
            tbar: [{
                text: '<b>Save</b>',
                iconCls:'save-icon',
                handler: function() { doAction(action); }
            },{
                text: '<b>Delete</b>',
                iconCls:'delete-icon',
                hidden: deleteButtonHidden,
                handler: function() { doAction('delete'); }
            }]
        });
        
        win.on('close', reloadGrid);
        win.on('afterrender', function(w) {
            w.load({
                url: url,
                params: params,
                nocache: true,
                text: 'Loading...',
                timeout: 30,
                scripts: true,
                callback: function() {
                    try {
                        config.winLoadCallback();
                    } catch (e) {
                        console.log(e);
                    }
                    var form = w.getEl().child('form', true);
                    formId = form.id;
                }
            });
        });
        win.show();
    };
    
    /**
     * Get window
     * 
     * @return Ext.Window
     */
    var getWin = function() {
        return win;
    };

    /**
     * Select an item from grid
     *
     * @param   {SelectionModel} selectionModel
     * @param   {Number} rowIndex
     * @param   {Ext.data.Record} record
     * @return  void
     */
    var selectItem = function(selectionModel, rowIndex, record) {
        selectedItemId = record.data[config.idField];
        openWin(true);
        selectionModel.clearSelections();
    };

    var editorPanel = new Ext.Panel({
        title: '',
        region: 'center',
        margins: '0 0 0 0',
        layout: 'fit',
        border: false,
        items: [ config.grid ]
    });

    this.grid = config.grid;
    this.grid.getSelectionModel().on('rowselect', selectItem);
    
    var containerPanel = new Ext.Panel({
        border: false,
        layout: 'border',
        region: 'center',
        tbar:[],
        items: [ editorPanel ]
    });
    
    if (!config.hideAddNew) {
        containerPanel.getTopToolbar().add({
            text: 'Add New',
            iconCls:'create-icon',
            handler: function() { openWin(false); }
        });
    }
    
    this.grid.on('afterrender', function() {
        reloadGrid();
    });
    
    this.managerPanel = new Ext.Panel({
        title: config.title,
        region: config.region,
        defaults: { autoScroll: true, border: false },
        border: false,
        layout: 'fit'
    });
    
    this.managerPanel.add(containerPanel);
    
    /**
     * Get current editor window
     * 
     * @return  Ext.Window
     */
    this.getWin = function() {
        return win;
    };
    
    /**
     * Set base param
     * 
     * @param {String} param
     * @param {Mixed} value
     * @return void
     */
    this.setBaseParam = function(param, value) {
        config.baseParams[param] = value;
    };
};

/**
 * Create a search bar which can be added to a panel
 * 
 * @param   {Object} config
 * @return  Ext.form.TriggerField
 */
Pelorous.searchBar = function(config) {
    config = config || {};
    var paramName = config.paramName || 'searchOptions[searchString]';
    var width = config.width || 200;
    var id = config.id || null;
    
    config.noPageBar = config.noPageBar || false;
    config.paging = config.paging || {start: 0, limit: 50};
    
    var searchBar =  new Ext.form.TriggerField({
        paramName: paramName, 
        width: width,
        id: id,
        store: config.store, 
        triggerClass: 'x-form-search-trigger',
        validationEvent: false,
        validateOnBlur: false,
        initComponent : function() {
            this.onTriggerClick = this.doSearch;
            this.on('specialkey', function(f, e) {
                if (e.getKey() == e.ENTER) {
                    this.doSearch();
                }}
            ,this);
        },
        doSearch : function () {
            var v = this.getRawValue();
            this.store.baseParams = this.store.baseParams || {};
            this.store.baseParams[this.paramName] = v;
            
            var params = {};
            if (!config.noPageBar) {
                params = config.paging;
            }
            this.store.reload({ params: params });
        }
    });
    
    return searchBar;
};

/**
 * Clear any message divs
 * 
 * @param   {Array} types Types of messages to clear
 * @return  void
 *
 * @todo - gonna finish this off at some point
 * 
Pelorous.clearMessages = function(types) {
    var selector = parentEl || '';
    if (selector !== '') {
        selector+= ' ';
    }
    selector+= '.messages';
    
    setTimeout(function() {
        Ext.select(selector).fadeOut({
            duration: 1,
            remove: true
        });
    }, 2000);
};
*/

Function.prototype.Singleton = function(instance) {
    if (!this.getInstance) {
        this.getInstance = function() { return instance; };
    };
};

