// NEED TO PHASE NCLAYOUT OUT
var ncLayout = { // Add to ap.ui
    activityIndicator: null,
    messageDiv: null,
    errorDiv: null,
    section: null,
    sideTabs: null,
    init: function()
    {
    },
    addSection: function(name, id)
    {
        ap.ui.sections.add(name, '#' + id);
    },
    addSideTab: function(name, id, disabled, callback)
    {
        if (id.length > 0) {
            id = '#' + id;
        }
        if (disabled !== false && disabled !== true) {
            disabled = false;
        }
        ap.ui.sideTabs.add(name, {
            selector: id,
            disabled: disabled,
            callback: callback
        });
    },
    deleteSideTab: function(name)
    {
        ap.ui.sideTabs.remove(name);
    },
    selectSideTab: function(name)
    {
        ap.ui.sideTabs.select(name);
    },
    unselectAllSideTags: function()
    {
        ap.ui.sideTabs.unselectAll();
    },
    enableSideTab: function(name, callback)
    {
        ap.ui.sideTabs.enable(name, callback);
    },
    disableSideTab: function(name)
    {
        ap.ui.sideTabs.disable(name);
    },
    disableAllTabs: function()
    {
        ap.ui.sideTabs.disableAll();
    },
    showActivityIndicator: function()
    {
        ap.ui.showActivityIndicator();
    },
    hideActivityIndicator: function()
    {
        ap.ui.hideActivityIndicator();
    },
    showMessage: function(message)
    {
        ap.ui.showMessage(message);
    },
    showError: function(message)
    {
        ap.ui.showError(message);
    },
    hideMessage: function()
    {
        ap.ui.hideMessage();
    },
    hideError: function()
    {
        ap.ui.hideError();
    },
    hideAll: function(exception)
    {
        return ap.ui.hideAll();
    },
    hideSection: function (section)
    {
        return ap.ui.sections.hide(section);
    },
    showSection: function(section, exceptions)
    {
        return ap.ui.sections.show(section, exceptions);
    },
    disableButtons: function(buttons)
    {
        ap.ui.disableButtons(buttons);
    },
    enableButtons: function(buttons)
    {
        ap.ui.enableButtons(buttons);
    },
    setupHideRightSidebar: function()
    {
    },
    deactivateTableActions: function()
    {
        ap.ui.table.deactivateTableActions();
    },
    activateTableActions: function()
    {
        ap.ui.table.activateTableActions();
    }
};

/**
*  Begin to convert all javascript files to this instead of the code above.
* Once all code is using this new object go back and change references to 'ncObj'
* to 'nc'
*/

(function($){
    // Sets both the keyup and change event handler function for the matched elements
    $.fn.ncTextChange = function(keyUpFn, changeFn) {
        changeFn = changeFn || keyUpFn;
        if (keyUpFn instanceof Function && changeFn instanceof Function) {
            $(this).keyup(keyUpFn).change(changeFn);
        }
        return this;
    };
    // Empty a select box. If length is passed that many options will be left
    $.fn.emptySelect = function(length) {
        length = length || 0;
        return this.each(function(){
            if (this.tagName == 'SELECT') this.options.length = length;
        });
    };
    // Empty and then fill a select box. If length is passed that many options will be left before the new ones are added.
    $.fn.loadSelect = function(optionsDataArray, length) {
        return this.emptySelect(length).each(function(){
            if (this.tagName == 'SELECT') {
                var select = this;
                $.each(optionsDataArray, function (index, data) {
                    var option = new Option(data.caption, data.value);
                    if ($.browser.msie) {
                        select.add(option);
                    } else {
                        select.add(option, null);
                    }
                });
            }
        });
    };
    $.fn.addSelectOption = function(value, caption) {
        return this.each(function(){
            var option = new Option(caption, value);
            if ($.browser.msie) {
                this.add(option);
            } else {
                this.add(option, null);
            }
        });
    };
    $(document).ready(function(){
        ap.init();
    });

    var ap, nc;

    nc = window.nc = ap = window.ap = {
        /**
        * Holds the height and width of the window
        */
        window: {},

        init: function()
        {
            this.ui.init();
            this.ui.admin.init();
            this.ui.sections.init();
            this.ui.sideTabs.init();
            ncLayout.init();
            this.getWindowSize();
            this.module.init();
            if ($.validator) {
                $.validator.messages.required = 'Required';
            }
            this.myModulesNav.init();
            this.myAccount.init();
            this.sites.init();
        },
        focus: function(el)
        {
            $(el).focus();
        },
        loadFCKEditor: function(instanceName, width, height, toolbarSet, value)
        {
            if (height == undefined) {
                height = '500';
            }
            if (toolbarSet == undefined) {
                if (fckEditorToolBar != undefined) {
                    toolbarSet = fckEditorToolBar;
                } else {
                    toolbarSet = 'ncDefault';
                }
            }
            var editor = new FCKeditor(instanceName, width, height, toolbarSet, value);
            editor.BasePath = ncJsBasePath + 'fckeditor/' ;
            editor.DisplayErrors = false;
            editor.Config['CustomConfigurationsPath'] = ncJsBasePath + 'fckeditor/nc-fckconfig.js';
            return editor;
        },
        saveUserConfig: function(group, configName, configValue)
        {
            var data = 'group=' + group + '&name=' + configName + '&value=' + configValue;
            $.post(ncAdminBaseUrl + 'myaccount/saveConfig', data);
        },
        /**
        * Sets links with a rel attribute of "external" to open in a new window.
        * Adapted from Sitepoint.com (http://www.sitepoint.com/article/standards-compliant-world)
        */
        externalLinks: function() {
            //			$('a[rel=external]').attr('target', '_blank').after(' <img src="/nc/interface/admin/default/images/external.png" alt="External link" height="10" width="10">');
            $('a').filter(function() {
                return (this.href && this.hostname != undefined && this.hostname.split(':')[0] != location.hostname) || (this.rel == 'external');
            })
            .attr('target', '_blank')
            .filter(function() {
                return this.rev != 'externalSkip';
            })
            .after(' <img src="/nc/interface/admin/default/images/external.png" alt="External link" height="10" width="10">');
        },
        /**
        * Helper function to get the correct window height and width
        */
        getWindowSize: function() {
            this.window = {
                height: $(window).height(),
                width: $(window).width()
            };
        },
        /**
        * Debuging helper function.
        * Will send a message to the console (Firebug) if it exists. If not,
        * Then it'll do a simple alert box.
        */
        debug: function() {
            if (window.console && window.console.log && $.browser.safari === false) {
                window.console.log('[debug] ' + Array.prototype.join.call(arguments,''));
            } else {
                alert('[debug] ' + Array.prototype.join.call(arguments,''));
            }
        },
        /**
        * DEPRECATED
        * USE ap.ui.block()
        */
        blockUI: function(text)
        {
            ap.ui.block(text);
        },
        /**
        * DEPRECATED
        * USE ap.ui.uploadBlock()
        */
        uploadBlockUI: function()
        {
            ap.ui.uploadBlock();
        }
    };



    // User Interface methods
    ap.ui = {
        activityIndicator: null,
        messageDiv: null,
        errorDiv: null,
        init: function()
        {
            //Set the default container for messages and error messages
            this.activityIndicator = $('#activityIndicator');
            this.errorDiv = $('#errorMessages');
            this.messageDiv = $('#messages');
            this.setupHideRightSidebar();
            this.setupFloatingButtons();
        },
        setupHideRightSidebar: function()
        {
            $('a.showHideRSidebar').click(function(){
                var self = $(this);
                if (self.hasClass('showSidebar')) {
                    //The sidebar is currently being hidden and needs to be shown
                    self.removeClass('showSidebar');
                    self.html('Hide sidebar');
                    $('#tdRightContent').show();
                } else {
                    //The sidebar is currently being shown and needs to be hidden
                    self.addClass('showSidebar');
                    self.html('Show sidebar');
                    $('#tdRightContent').hide();
                }
                $('td.tdRight').toggleClass('tdRightCollapsed');
                $('div.tdLeftMainBottom').toggleClass('tdLeftMainBottomFull');
                ap.ui.admin.windowResize(); //in case there was a scroll bar and now it's gone, or vise versa
                this.blur();
                return false;
            });
        },
        setupFloatingButtons: function()
        {
            var buttons = $('div.submit:first');
            if (buttons.length > 0) {
                buttonPos = buttons.offset();
                var buttonClone = buttons.clone().removeClass('submit').addClass('submit-floating').css({display: 'none', opacity: 0.95}).insertAfter('div.submit:first');
                $(window).scroll(function(){
                    if ($(this).scrollTop() > buttonPos.top) {
                        buttonClone.show();
                    } else {
                        buttonClone.hide();
                    }
                });
            }
        },
        // Blocks the UI with the specific text
        block: function(text) {
            var loadingMsg = $('#loadingMessage');
            if (text) {
                $('p:first', loadingMsg).html(text);
            }
            $.blockUI({message: loadingMsg, baseZ: 3000});
        },
        // Convenience function to block the UI and show the same text
        uploadBlock: function(options) {
            var uploadOptions = {
                setSaveButton: false,
                saveButtonName: 'save',
                form: null
            };
            $.extend(uploadOptions, options);
            if (true === uploadOptions.setSaveButton && null !== uploadOptions.form) {
                $('<input type="hidden" name="' + uploadOptions.saveButtonName + '" value="yes" />').appendTo(uploadOptions.form);
            }
            this.block('Please wait while the information is submitted...');
        },
        showActivityIndicator: function()
        {
            this.activityIndicator.show();
        },
        hideActivityIndicator: function()
        {
            this.activityIndicator.hide();
        },
        /**
        * Gets the message dom object
        * @param string message The message text
        */
        getMessage: function(message) {
            var c = this.messageDiv.clone(true);
            c.html(message).css('backgroundColor', '#c2ebc3').removeClass('errorMsg').addClass('message');
            return c;
        },
        /**
        * Gets the error message dom object
        * @param string message The error message text
        */
        getErrorMessage: function(message) {
            var c = this.errorDiv.clone(true);
            c.html(message).css('backgroundColor', '#fcbdc4').removeClass('message').addClass('errorMsg');
            return c;
        },
        showMessage: function(message)
        {
            this.hideActivityIndicator();
            if (message != undefined) {
                this.hideError();
                this.messageDiv.html(message).css('backgroundColor', '#c2ebc3').removeClass('errorMsg').addClass('message').show().animate({backgroundColor: '#E2F9E3'}, 1500);
                //this.messageDiv.html(message).css('backgroundColor', '#c2ebc3').removeClass('errorMsg').addClass('message').show();
                ap.ui.admin.windowResize(); //Because the message could push down the content and create a scroll bar which would affect the window width
            }
        },
        showError: function(message)
        {
            this.hideActivityIndicator();
            if (message != undefined) {
                this.hideMessage();
                this.errorDiv.html(message).css('backgroundColor', '#fcbdc4').removeClass('message').addClass('errorMsg').show().animate({backgroundColor: '#FFEDEF'}, 1500, 'linear');
                ap.ui.admin.windowResize(); //Because the message could push down the content and create a scroll bar which would affect the window width
            }
        },
        hideMessage: function()
        {
            if (this.messageDiv != undefined) {
                this.messageDiv.hide();
            }
        },
        hideError: function()
        {
            if (this.errorDiv != undefined) {
                this.errorDiv.hide();
            }
        },
        hideMessageAndError: function() {
            this.hideMessage();
            this.hideError();
        },
        hideAll: function(exception)
        {
            this.hideActivityIndicator();
            if (exception == undefined || typeof exception == 'string') {
                if (exception != 'message') this.hideMessage();
                if (exception != 'error') this.hideError();
            } else if (exception instanceof Array) {
                if ($.inArray('message', exception) == -1) this.hideMessage();
                if ($.inArray('error', exception) == -1) this.hideError();
            }
            ap.ui.sections.hideAll(exception);
            return false;
        },
        disableButtons: function(buttons)
        {
            $(buttons).attr('disabled', 'disabled');
        },
        enableButtons: function(buttons)
        {
            $(buttons).removeAttr('disabled');
        }
    };
    /**
    * Handles the My Account link
    */
    ap.myAccount = {
        init: function() {
            var self = this;
            $('#myAccount').click(function() {
                var dialog = new ap.ui.dialog({title: 'My Account'}, {
                    load: function(box) {
                        $('#myAccountTabs', box).tabs();
                        ap.focus('#IDEditUsername');
                    }
                });
                dialog.open(ncAdminBaseUrl + 'myaccount/ajax');
                return false;
            });
        }
    };

    /**
    * Handles the Microsite link
    */
    ap.sites = {
        init: function() {
            var self = this;
            $('#apSites').click(function() {
                var dialog = new ap.ui.dialog({title: 'Sites &amp; Microsites'});
                dialog.open(ncAdminBaseUrl + 'site/browser');
                return false;
            });
        }
    };

    /**
    * Sets up a dialog box.
    * Intended to be used as the onlick event for navigation
    * @param object dialogOptions The options for the jQuery UI dialog box
    * @param object options The general options for this box
    */
    ap.ui.setupDialog = function(url, dialogOptions, options) {
        var dialog = new ap.ui.dialog(dialogOptions, options);
        dialog.open(url);
        return false;
    };

    /**
    * Create a dialog box on the fly that can handle forms and
    * display form messages.

    * The options for the jQuery UI dialog and this object are kept separate
    * so that with future versions of jQuery UI there isn't a possibility of
    * using a option name internally that is used in the jQuery UI dialog options.
    *
    * @param object dialogOptions The options for the jQuery UI dialog box
    * @param object options The general options for this box
    */
    ap.ui.dialog = function(dialogOptions, options) {
        // Holds the dialog dom object
        this.box = null;

        // Holds the URL to be loaded
        this.url = null;

        var self = this;

        // Holds the options for the dialog box
        this.dialogOptions = {
            height: '90%',
            width: '75%',
            minHeight: 200,
            minWidth: 300,
            modal: true,
            position: 'center',
            open: function() {self.load(); },
            close: function() {self.close(); }
        };
        $.extend(this.dialogOptions, dialogOptions);

        // Holds the general options
        this.options = {
            ajaxForm: true, // Whether or not the form will be submitted via ajax.
            load: null // Callback function for after the content is loaded
        };
        $.extend(this.options, options);

        // If the height and width are percents then get the pixel height
        if (typeof this.dialogOptions.height == 'string' && this.dialogOptions.height.indexOf('%') > -1) {
            this.dialogOptions.height = (parseInt(this.dialogOptions.height) / 100) * ap.window.height;
        }
        if (typeof this.dialogOptions.width == 'string' && this.dialogOptions.width.indexOf('%') > -1) {
            this.dialogOptions.width = (parseInt(this.dialogOptions.width) / 100) * ap.window.width;
        }

    };

    ap.ui.dialog.prototype = {
        open: function(url) {
            this.url = url;
            var html = '<div class="apuiDialog"><div class="apuiDialogMsg"></div><div class="apuiDialogContent"><div class="apuiDialogLoading"></div></div></div>';
            this.box = $(html).appendTo('body').dialog(this.dialogOptions);
            $('.apuiDialogLoading', this.box).height(this.box.height()).css('minHeight', this.box.css('minHeight'));
        },
        load: function() {
            var self = this;
            var saving = $('<div class="apuiDialogSave">Saving</div>');
            $('.apuiDialogContent', this.box).load(this.url, null, function(responseText, textStatus, XMLHttpRequest) {
                if ($.isFunction(self.options.load)) {
                    self.options.load.call(this, self.box, self.options, responseText, textStatus, XMLHttpRequest);
                }
                var submit = $('.submit', self.box);
                if (self.options.ajaxForm) {
                    $('form', self.box).ajaxForm({
                        dataType: 'json',
                        beforeSubmit: function() {
                            saving.appendTo(self.box).insertAfter(submit).show();
                            submit.hide()
                        },
                        success: function(response) {
                            if (response.error == undefined) {
                                if (response.msg != undefined) {
                                    $('.apuiDialogMsg', self.box).html(ap.ui.getMessage(response.msg));
                                }
                            } else {
                                $('.apuiDialogMsg', self.box).html(ap.ui.getErrorMessage(response.error));
                            }
                            $('.apuiDialogSave', self.box).remove();
                            submit.show();
                        }
                    });
                }
                $('a.cancel,a.close', self.box).click(function (){
                    self.box.dialog('close');
                    return false;
                });
            });
        },
        close: function() {
            this.box.remove();
        }
    };


    ap.ui.sections = {
        sections: null,
        init: function()
        {
            this.sections = {};
        },
        add: function(name, selector)
        {
            selector = selector || '#' + name;
            this.sections[name] = $(selector);
        },
        tabSetup: function(selector)
        {
            // Find all divs with the class name of selector
            selector = selector || 'div.tabSections';
            $(selector).each(function(i){
                // Get the id and parse of "Section" text
                if (this.id.length > 0) {
                    // The id should be in the form of idSection
                    // Remove "Section" from the id
                    var id = this.id.replace('Section', '');
                    // Find the tab that matches the section
                    // Tabs should have ids in the form of idTab
                    // 'id' comes from the modified section id
                    var tabId = '#' + id + 'Tab';
                    var name = 'nc' + id;
                    // If this is the first section, show it, otherwise hide it
                    if (i > 0) {
                        this.style.display = 'none';
                    } else {
                        this.style.display = 'block';
                    }
                    ap.ui.sections.add(name, '#' + this.id);
                    ap.ui.sideTabs.add(name, tabId);
                }
            });
        },
        hide: function (section)
        {
            this.sections[section].hide();
            ap.ui.admin.windowResize(); //in case there was a scroll bar and now it's gone, or vise versa
            return false;
        },
        show: function(section, exceptions)
        {
            if (exceptions instanceof Array) {
                exceptions.push(section);
                this.hideAll(exceptions);
            } else {
                this.hideAll(section);
            }
            this.sections[section].show();
            ap.ui.admin.windowResize(); //in case there was a scroll bar and now it's gone, or vise versa
            return false;
        },
        hideAll: function(exception)
        {
            for (var x in this.sections) {
                var hideThis = true;
                if (typeof exception == 'string' && exception == x) {
                    hideThis = false;
                } else if (exception instanceof Array && $.inArray(x, exception) != -1) {
                    hideThis = false;
                }
                if (true === hideThis) {
                    this.sections[x].hide();
                }
            }
        },
        exists: function(name)
        {
            var set = false;
            if (null != this.sections) {
                if (this.sections[name] != undefined) {
                    set = true;
                }
            }
            return set;
        }
    };
    /**
    * Create vertical tabs.
    * Requires the jquery UI Tabs
    * The selector shoudd be a div around a ul, which will
    * be converted to tabs.  Each tab panel will be a div
    * within the selector. The divs will be given a width of
    * 100% - 160px and floated right. The tabs will be floated
    * left. A clearing div will be added right after the
    * floated panels.
    */
    ap.ui.verticalTabs = {
        init: function(selector) {
            selector = $(selector);
            if (selector.length > 0) {
                selector.tabs({
                    deselectableClass: 'ap-vtabs-deselectable',
                    disabledClass: 'ap-vtabs-disabled',
                    hideClass: 'ap-vtabs-hide',
                    idPrefix: 'ap-vtabs',
                    loadingClass: 'ap-vtabs-loading',
                    navClass: 'ap-vtabs-nav ap-vtabs-widget-header',
                    panelClass: 'ap-vtabs-panel',
                    selectedClass: 'ap-vtabs-selected ap-vtabs-state-active'
                }).addClass('ap-vtabs');
                var panel = $('.ap-vtabs-panel:first', selector);
                var tabs = $('.ap-vtabs-nav', selector);
                var tabHeight = tabs.height();
                var width = selector.width() - tabs.width() - (panel.outerWidth() - panel.innerWidth()) - parseInt(panel.css('borderLeftWidth')) - parseInt(panel.css('borderRightWidth'));
                $('.ap-vtabs-panel', selector).each(function() {
                    // Make sure that the panel isn't shorter than the tabs
                    var p = $(this);
                    if (p.height() < tabHeight) {
                        p.css('minHeight', tabHeight);
                        /**
                        * Test again to see if the height is the same as the tabs. If it is not then
                        * min-height is not supported (IE). The 'height' css property should be used
                        * instead.
                        */
                        if (p.height() < tabHeight) {
                            p.height(tabHeight);
                        }
                    }
                });
                // Add class for the last tab
                $('li:last', tabs).addClass('ap-vtabs-last');
            }
        }
    };
    ap.ui.sideTabs = {
        tabs: null,
        init: function()
        {
            this.tabs = {};
        },
        add: function(name, options)
        {
            var tabOptions = {
                selector: null,
                disabled: false,
                callback: null
            }
            if (options.constructor == Object) {
                $.extend(tabOptions, options);
            } else if (options.constructor == String) {
                // If options is a string assume that it's the selector
                tabOptions.selector = options;
            }
            tabOptions.selector = tabOptions.selector || '#' + name;
            this.tabs[name] = $(tabOptions.selector);
            if (true === tabOptions.disabled) {
                this.tabs[name].addClass('disabled').click(function(){
                    return false;
                });
            } else if (null != tabOptions.callback) {
                this.tabs[name].click(function(){
                    this.blur();
                    ap.ui.sideTabs.select(name);
                    tabOptions.callback();
                    return false;
                });
            } else {
                this.tabs[name].click(function(){
                    this.blur();
                    ap.ui.sideTabs.select(name);
                    if (ap.ui.sections.exists(name)) {
                        ap.ui.sections.show(name);
                    }
                    return false;
                });
            }
        },
        remove: function(name)
        {
            delete this.tabs[name];
        },
        select: function(name)
        {
            this.unselectAll();
            this.tabs[name].addClass('active');
        },
        unselectAll: function()
        {
            $.each(this.tabs, function(i, tab){
                ap.ui.sideTabs.tabs[i].removeClass('active');
            });
        },
        enable: function(name, callback)
        {
            this.tabs[name].removeClass('disabled').unbind('click').click(function(){
                this.blur();
                callback();
                ap.ui.sideTabs.select(name);
                return false;
            });
        },
        disable: function(name)
        {
            this.tabs[name].addClass('disabled').unbind('click').click(function() {this.blur();return false;});
        },
        disableAll: function()
        {
            $.each(this.tabs, function(i, tab) {
                ap.ui.sideTabs.tabs[i].addClass('disabled').unbind('click').click(function(){this.blur();return false;});
            });
        }
    };
    /**
    * Helper object for setting up a new apGrid.
    */
    ap.ui.grid = {
        opts: {
            // The base path used for ajax requests
            basePath: '',
            // Whether or not to display the delete button
            deleteBtn: true,
            // The delete button text
            deleteBtnText: 'Delete selected',
            // A function to be called after the item(s) are deleted
            deleteCallback: null,
            // The message to show if there was an error with the ajax request that was not a 404 error
            deleteErrorMsg: 'There was a problem deleting {plural} due to a system error. Please try again later.',
            // The message to show if a 404 response is returned (most likely due to permission issues).
            deleteError404Msg: '0 {plural} were deleted because you do not have permission to delete {plural}',
            // A custom message to be shown after the initial delete confirmation message
            deleteMsg: '',
            // The module path to delete an item
            deletePath: 'delete',
            // Any apGrid specific options
            gridOpts: {},
            // The plural version of the item in each row. Used in delete messages.
            plural: '',
            // The singular version of the item in each row. Used in delete messages.
            singular: '',
            // The table selector
            tableSelector: 'table.apTbl',
            // Whether or not the grid has a tree
            tree: false
        },
        init: function(options) {
            $.extend(this.opts, options);
            var self = this;

            var gridOpts = {
                toolbar: null,
                tree: this.opts.tree
            };
            // Setup the delete button if necessary
            if (this.opts.deleteBtn) {
                var deleteBtn = {
                    text: this.opts.deleteBtnText,
                    btnClass: 'delete',
                    disabled: true,
                    onEvent: function(table, rows, checkboxes, options) {
                        var count = checkboxes.boxes.length
                        var item = count > 1 ? count + ' selected ' + self.opts.plural : 'selected ' + self.opts.singular;
                        if (confirm('Are you sure that you want to deleted the ' + item + '? ' + self.opts.deleteMsg)) {
                            // Just hide the rows right now so that they can be brought back if there are any errors
                            $.each(checkboxes.boxes, function(i, box) {
                                table.apGrid('hideRow', box.row);
                            });
                            table.apGrid('update');

                            ap.ui.showActivityIndicator();

                            $.ajax({
                                data: checkboxes.data,
                                dataType: 'json',
                                error: function (request, textStatus, errorThrown) {
                                    if (request.status == '404') {
                                        var msg = self.opts.deleteError404Msg.replace('{singular}', self.opts.singular, 'gi');
                                        msg = msg.replace('{plural}', self.opts.plural, 'gi');
                                        ap.ui.showError(msg);
                                    } else {
                                        var msg = self.opts.deleteErrorMsg.replace('{singular}', self.opts.singular, 'gi');
                                        msg = msg.replace('{plural}', self.opts.plural, 'gi');
                                        ap.ui.showError(msg);
                                    }
                                    $.each(checkboxes.boxes, function(i, box) {
                                        table.apGrid('showRow', box.row);
                                    });
                                },
                                success: function(response) {
                                    if (response.error == undefined) {
                                        ap.ui.showMessage(response.msg);
                                        $.each(checkboxes.boxes, function(i, box) {
                                            table.apGrid('removeRow', box.row);
                                        });
                                        table.apGrid('update');
                                    } else {
                                        ap.ui.showError(response.error);
                                        $.each(checkboxes.boxes, function(i, box) {
                                            table.apGrid('showRow', box.row);
                                        });
                                        table.apGrid('update');
                                    }
                                },
                                type: 'POST',
                                url: self.opts.basePath + self.opts.deletePath
                            });
                        }
                    }
                };
                if (!$.isArray(this.opts.gridOpts.toolbar)) {
                    this.opts.gridOpts.toolbar = [];
                }
                this.opts.gridOpts.toolbar.push(deleteBtn);
            }

            // Add any apGrid options
            $.each(this.opts.gridOpts, function(key, val) {
                gridOpts[key] = val;
            });

            $(this.opts.tableSelector).apGrid(gridOpts);
        }
    };
    ap.ui.table = {
        form: null,
        table: null,
        idCheckboxes: null,
        selectAll: null,
        actionLinks: null,
        options: {
            tableSelector: 'table.tblList',
            formSelector: '#listForm',
            deleteSelector: '#delete',
            sort: true,
            sortHeaders: {},
            singular: '',
            plural: '',
            deleteMsg: '',
            basePath: '',
            deletePath: 'delete',
            deleteCallback: null
        },
        init: function(options)
        {
            $.extend(this.options, options);
            this.form = $(this.options.formSelector);
            // Cancel the form submission
            this.form.submit(function(){
                return false;
            });
            this.table = $(this.options.tableSelector);
            this.setupActionLinks();
            this.setupIdCheckboxes();
            this.setupSelectAll();
            this.deactivateTableActions();
            this.setupDelete();
            if (true === this.options.sort) {
                this.sort()
            }
        },
        setupActionLinks: function()
        {
            this.actionLinks = $('a.actionLink', $('div.tblActions'));
        },
        setupDelete: function()
        {
            var self = this;
            $(this.options.deleteSelector).click(function(){
                var count = self.countCheckboxes();
                if (count > 0) {
                    var item = count > 1 ? 'these ' + count + ' ' + self.options.plural : 'this ' + self.options.singular;
                    if (confirm('Are you sure you want to delete ' + item + '? ' + self.options.deleteMsg)) {
                        var data = self.deleteRows();
                        if (data.length > 0) {
                            ap.ui.showActivityIndicator();
                            $.post(self.options.basePath + self.options.deletePath, data, function(response) {
                                if (response.error == undefined) {
                                    ap.ui.showMessage(response.msg);
                                } else {
                                    ap.ui.showError(response.error);
                                }
                                if (self.options.deleteCallback != undefined) {
                                    self.options.deleteCallback(response);
                                }
                            }, 'json');
                        }
                        self.applyWidgets();
                    }
                } else {
                    alert('You must click the checkbox next to at least one ' + self.options.singular);
                }
                this.blur();
                return false;
            });
        },
        setupSelectAll: function()
        {
            var self = this;
            this.selectAll = $('a.selectAll', this.form);
            this.selectAll.click(function(){
                if ($(this).html() == 'select all') {
                    self.selectAllCheckboxes();
                } else {
                    self.unselectAllCheckboxes();
                }
                this.blur();
                return false;
            });
        },
        selectAllCheckboxes: function()
        {
            this.idCheckboxes.attr('checked', 'checked');
            if (this.countCheckboxes() > 0) {
                this.selectAll.html('unselect');
                this.activateTableActions();
            }
        },
        unselectAllCheckboxes: function()
        {
            this.selectAll.html('select all');
            this.idCheckboxes.removeAttr('checked');
            this.deactivateTableActions();
        },
        setupIdCheckboxes: function()
        {
            var self = this;
            this.idCheckboxes = $(':checkbox[name="id[]"]', $('td.col_1', this.form));
            if (this.idCheckboxes.length > 0) {
                $('td.col_1', this.form).click(function() {
                    var checkbox = $(':checkbox', this);
                    if (true == checkbox.attr('checked')) {
                        checkbox.removeAttr('checked');
                    } else {
                        checkbox.attr('checked', 'checked');
                    }
                    self.handleCheckboxClick(checkbox);
                });
            }
            this.idCheckboxes.click(function(e){
                self.handleCheckboxClick(this);
                e.stopPropagation();
                //                if (true === this.checked) {
                //                    self.activateTableActions();
                //                } else {
                //                    if (self.countCheckboxes() == 0) {
                //                        self.deactivateTableActions();
                //                    }
                //                }
            });
        },
        handleCheckboxClick: function(checkbox)
        {
            checkbox = $(checkbox);
            if (true === checkbox.checked || checkbox.attr('checked')) {
                ap.ui.table.activateTableActions();
            } else {
                if (ap.ui.table.countCheckboxes() == 0) {
                    ap.ui.table.deactivateTableActions();
                }
            }
        },
        countCheckboxes: function()
        {
            return this.idCheckboxes.filter(':checked').length;
        },
        /**
        * Handles deleting items from a table list
        */
        deleteRows: function()
        {
            data = '';
            this.idCheckboxes.filter(':checked').each(function(i){
                if (data.length > 0) {
                    data += '&';
                }
                data += 'id%5B%5D=' + this.value;
                var tr = this.parentNode.parentNode;
                $(tr).remove();
            });
            this.setupIdCheckboxes();
            this.unselectAllCheckboxes();
            return data;
        },
        getRowIdQuery: function()
        {
            data = '';
            this.idCheckboxes.filter(':checked').each(function(i){
                if (data.length > 0) {
                    data += '&';
                }
                data += 'id%5B%5D=' + this.value;
            });
            return data;
        },
        deactivateTableActions: function()
        {
            if (null === this.actionLinks) {
                this.setupActionLinks();
            }
            this.actionLinks.addClass('disabled');
        },
        activateTableActions: function()
        {
            if (null === this.actionLinks) {
                this.setupActionLinks();
            }
            this.actionLinks.removeClass('disabled');
        },
        sort: function(sorting)
        {
            if (sorting == undefined) {
                this.table.tablesorter({
                    headers: this.options.sortHeaders,
                    widgets: ['zebra', 'rowover']
                });
            } else {
                this.table.trigger('sorton', [sorting]);
            }
        },
        applyWidgets: function()
        {
            this.table.trigger('applyWidgets');
        },
        update: function()
        {
            this.table.trigger('update');
            this.applyWidgets();
        },
        addRow: function(row, tbody)
        {
            tbody = tbody || $('tbody', this.table);
            tbody.append(row);
            domRow = $('tr:last', tbody);
            this.setupIdCheckboxes();
            this.update();
            return domRow;
        }
    };
    // Admin specific methods.
    ap.ui.admin = {
        init: function() {
            this.setupFormFocus();
            ap.externalLinks();
            this.setupMainNavigation();
            this.setupSubNavigation();
            $(window).resize(function() {
                ap.ui.admin.windowResize();
            });
        },
        windowResize: function()
        {
            ap.getWindowSize();
            //this.setupSubNavigation();
            ap.myModulesNav.setup();
        },
        /**
        * Sets the display for form fields when they receive focus
        */
        setupFormFocus: function() {
            //$(':text', 'textarea', ':password').each(function(){
            $(':text, textarea, :password').each(function(){
                var el = $(this);
                var bgColor = el.css('background-color');
                el.blur(function() {
                    this.style.backgroundColor = bgColor;
                }).focus(function() {
                    this.style.backgroundColor = '#ffffbb';
                });
            });
        },


        /**
        * Adds the hover functionality to the li items so that the dropdowns can be displayed.
        * That functionality is for IE as it doesn't support :hover on anything but links.
        * This also will hide the current dropdown sub navigation if it exists while the other
        * main navigation items are moused over.
        */
        setupMainNavigation: function() {
            var nav = $('#nav > ul:first');
            var liActive = $('li.active', nav);

            nav.children().each (function(i){
                var el = $(this);
                el.mouseover(function() {
                    if (!el.hasClass('active')) {
                        liActive.addClass('activeOut');
                    }
                    el.addClass('over');
                });
                el.mouseout(function() {
                    if (!el.hasClass('active')) {
                        liActive.removeClass('activeOut');
                    }
                    el.removeClass('over');
                });
            });
        },
        /**
        * For some reason IE won't keep the width of nested UL tags at 100%. It will
        * respect pixel widths, though.  So we'll set the width of all the sub nav items
        * to be the width of the window
        */
        setupSubNavigation: function() {
            var windowWidth = $(window).width();
            $('li > ul', $('#nav')).each(function(){
                this.style.width = windowWidth + 'px';
            });
        }
    };
    // String filters.  Not the same as javascript dom filters
    ap.filter = {
        // Filters the string
        key: function(text) {
            text = $.trim(text.toLowerCase());
            text = text.replace(/\W+/g, ' ');
            text = text.replace(/\s+|_+|-{2,}/g, '-');
            return text;
        }
    };
    /**
    * Module specific code. This would be defined in the javascript for the
    * specific module.
    */
    ap.module = {
        init: function(){}
    };

    ap.myModulesNav = {
        btn: null,
        wrapper: null,
        wrapperHeight: null,
        hoveringBtn: false,
        hoveringWrapper: false,
        json: null,
        columnWidth: 200,
        numColumns: 0,
        init: function() {
            this.btn = $('#myModulesBtn');
            var self = this;
            if (this.btn.length > 0) {
                this.wrapper = $('#myModulesWrapper');
                this.setup();
                this.btn.hoverIntent({
                    over: function() {self.hoveringBtn = true; self.show(); },
                    out: function() {self.hoveringBtn = false; self.hide(); },
                    timeout: 0
                });
                this.wrapper.hover(
                function() {self.hoveringWrapper = true; self.show(); },
                function() {self.hoveringWrapper = false; self.hide(); }
                );
            }
        },
        setup: function() {
            // Get the window height
            var windowHeight = $(window).height();
            if (this.btn != undefined && this.btn.length > 0) {
                // Get the position of the MyModules button
                var btnTop = this.btn.offset().top;
                var btnHeight = this.btn.height();
                // Set the position and height of the My Modules Wrapper
                var wrapperY = btnTop + btnHeight;
                this.wrapperHeight = windowHeight - btnTop - btnHeight;
                this.wrapper.css({top: wrapperY, height: this.wrapperHeight});
                var wrapperWidth = this.wrapper.width();
                // Set the height of the container
                $('#myModulesContainer').css({height: this.wrapperHeight - 10, width: wrapperWidth - 42});
                this.calculateColumns(wrapperWidth);
                this.setText();
            }
        },
        calculateColumns: function(wrapperWidth) {
            this.numColumns = Math.floor(wrapperWidth / this.columnWidth);
        },
        setText: function() {
            if (this.json == undefined) {return;}
            var self = this;
            var html = '<table cellspacing="0"><tbody>';
            var column = 1;
            $.each(self.json, function(n, data) {
                if (column > self.numColumns) {
                    html += '</tr>';
                    column = 1;
                }
                if (column == 1) {
                    html += '\n<tr>';
                }
                html += '\n<td width="' + self.columnWidth + '">';
                html += '<h2><a href="' + data.url + '">' + data.text + '</a></h2>';
                if (data.subs != undefined) {
                    html += '<ul>';
                    $.each(data.subs, function() {
                        html += self.setSubText(this);
                    });
                    html += '</ul>';
                }
                html += '</td>';
                column ++;
            });
            if (column <= self.numColumns) {
                while (column <= self.numColumns) {
                    html += '<td width="' + self.columnWidth + '">&nbsp;</td>';
                    column ++;
                }
                html += '</tr>';
            }
            html += '</tbody></table>';
            $('#myModulesContainer').html(html);
        },
        setSubText: function(data) {
            var self = this;
            var html = '<li>';
            html += '<a href="' + data.url + '">' + data.text + '</a>';
            if (data.subs != undefined) {
                html += '<ul>';
                $.each(data.subs, function() {
                    html += self.setSubText(this);
                });
                html += '</ul>';
            }
            html += '</li>';
            return html;
        },
        show: function() {
            this.wrapper.fadeIn(100);
        },
        hide: function() {
            setTimeout(function() {
                ap.myModulesNav.testHide();
            }, 200);
        },
        testHide: function() {
            // Only hide if not hovering on the button or wrapper
            if (this.hoveringBtn == false && this.hoveringWrapper == false) {
                this.wrapper.fadeOut(200);
            }
        }
    };

})(jQuery);
