﻿// ---------- nav panel center helper class ---------- //
Ext.ux.NavPanelCenterHelper = Ext.extend(Ext.util.Observable, {

    // internal fields
    m_tabDataTabs: null,
    m_tabDataLinks: null,
    m_tabDataAdHocPanels: null,

    m_aTabImageIds: [],
    m_aLinkImageIds: [],

    m_defaultTabId: "",
    m_currentTabId: "",
    m_currentAdHocPanelId: "",

    m_displayMode: g_panelTypeTab,
    m_searchOnLoad: false,

    // store a flag to indicate if the panel has been loaded
    // so the next time we want to display the panel, we don't have to reload
    m_aTabPanelsLoaded: [],
    m_aAdHocPanelsLoaded: [],

    m_previousHash: null,
    m_lastHash: null,

    // standard constructor
    constructor: function(contentElementIdPrefix) {

        // args passed in
        this.m_contentElementIdPrefix = contentElementIdPrefix;

        // add custom events
        this.addEvents(g_customEvent_navPanelCenterHelper_displayPanelContent);

        Ext.ux.NavPanelCenterHelper.superclass.constructor.call(this);
    },

    // standard initializer
    initComponent: function() {
        Ext.ux.NavPanelCenterHelper.superclass.initComponent.apply(this, arguments);

        // extra args have to go here as base class initComponent doesn't get called for some reason
        var config = {};

        Ext.apply(this, config);
        Ext.apply(this.initialConfig, config);
    },


    // initialize main tabs & corresponding links in tab reflections
    initialize: function(tabs, links, adHocPanels, currentTab) {

        this.m_tabDataTabs = tabs;
        this.m_tabDataLinks = links;
        this.m_tabDataAdHocPanels = adHocPanels;

        // set the display mode, based on controller
        var currentTabData = this.getTabTabDataById(currentTab);
        if (currentTabData === null) {
            this.setDisplayMode(g_panelTypeAdHoc);
        }

        this.initializeInt(tabs, this.m_aTabImageIds, currentTab, delegate(this, this.handleTabClick));
        this.initializeInt(links, this.m_aLinkImageIds, currentTab, delegate(this, this.handleTabClick));
    },

    // initialize main tabs & corresponding links in tab reflections (only the ones which aren't disabled)
    initializeInt: function(items, tabImageIds, currentTab, clickHandler) {
        for (var i = 0; i < items.length; i++) {
            if (!items[i].isDisabled) {
                $("#" + items[i].handlerLinkId + "").bind("click", items[i].stringData, clickHandler);
                $.preloadImages(items[i].activeImagePath, items[i].hoverImagePath, items[i].inactiveImagePath);
                $.merge(tabImageIds, [[items[i].imageId, items[i].handlerImageId, items[i].inactiveImagePath]]);

                // bind standard hover images
                $.bindHoverImages(
                    items[i].imageId,
                    items[i].hoverImagePath,
                    items[i].inactiveImagePath,
                    items[i].stringData,
                    delegate(this, this.checkIsActive),
                    null, null, null, null, null);

                // bind handler hover images
                $.bindHoverImages(
                    items[i].handlerImageId,
                    items[i].hoverImagePath,
                    items[i].inactiveImagePath,
                    items[i].stringData,
                    delegate(this, this.checkIsActive),
                    null, null, null, null, null);

                // store default and current tab for hover handler
                var stringData = items[i].stringData.toLowerCase();

                if (items[i].isDefault !== 0) {
                    this.setDefaultTabId(stringData);
                }

                // initialise 'loaded' flag for current tab
                // note that current tab is loaded when the page is initially rendered, so its flag is set to true
                if (stringData == currentTab.toLowerCase()) {
                    this.m_currentTabId = stringData;
                    this.m_aTabPanelsLoaded[stringData] = true;
                }
                else {
                    this.m_aTabPanelsLoaded[stringData] = false;
                }
            }
        }
    },

    // checks to see if the # location hash changed and then kicks off
    // the loading of that page content using navPanelCenterHelper
    // This function is called periodically by a setInterval to handle the 
    // case of when back and forward browser navigation is done.
    checkLocationChange: function() {
        var panelId = '';

        if (window.location.hash != this.m_lastHash) {
            if ((!window.location.hash || window.location.hash == '#') && (!this.m_lastHash || this.m_lastHash == '#')) {
                return;
            }

            this.m_previousHash = this.m_lastHash;
            this.m_lastHash = window.location.hash;


            // only load content if we haven't redirected from a hashless version of the same page
            // or the content is empty (perhaps the user reloaded the page)
            if ((this.m_previousHash !== null) || (g_emptyPartialRequest)) {

                if (window.location.hash && window.location.hash != '#') {
                    panelId = window.location.hash.substr(1);
                }

                // trim leading and trailing slashes
                panelId = panelId.lTrim('/');
                panelId = panelId.rTrim('/');

                // we have a valid url, so attempt to display the appropriate panel
                if (panelId !== '') {

                    // check if the specified tab or adhoc panel exists.
                    // If it does, initiate display process. if not, display a 404
                    var tabData = this.getTabTabDataById(panelId);
                    var adHocPanelData = this.getAdHocPanelDataById(panelId);

                    if (tabData != null) {
                        this.showTabPanel(panelId, false);
                    }
                    else if (adHocPanelData != null) {
                        this.showAdHocPanel(panelId);
                    }
                    else {
                        this.showAdHocPanel(g_adHocPanel_http404);
                    }
                }
                else {
                    // we have a hash but nothing following it, so redirect to the default page, into
                    window.location.hash = "#/" + g_adHocPanel_info.ucFirst() + "/";
                }
            }
        }
    },

    // retrieve the set of tab tabdata given its id
    // note: different to ContentPanelHelper
    getTabTabDataById: function(tabId) {
        var tabData = null;

        for (var i = 0; i < this.m_tabDataTabs.length; i++) {
            if (this.m_tabDataTabs[i].stringData.toLowerCase() == tabId.toLowerCase()) {
                tabData = this.m_tabDataTabs[i];
                break;
            }
        }

        return tabData;
    },

    // retrieve the set of link tabdata given its id
    // note: different to ContentPanelHelper
    getTabLinkDataById: function(tabId) {
        var tabData = null;

        for (var i = 0; i < this.m_tabDataLinks.length; i++) {
            if (this.m_tabDataLinks[i].stringData.toLowerCase() == tabId.toLowerCase()) {
                tabData = this.m_tabDataLinks[i];
                break;
            }
        }

        return tabData;
    },

    // retrieve the set of adhoc data given its id
    getAdHocPanelDataById: function(adHocPanelId) {
        var adHocPanelData = null;

        for (var i = 0; i < this.m_tabDataAdHocPanels.length; i++) {
            if (this.m_tabDataAdHocPanels[i].stringData.toLowerCase() == adHocPanelId.toLowerCase()) {
                adHocPanelData = this.m_tabDataAdHocPanels[i];
                break;
            }
        }

        return adHocPanelData;
    },

    // set the default tabId
    setDefaultTabId: function(defaultTabId) {
        this.m_defaultTabId = defaultTabId.toLowerCase();
    },

    // get the default tabId
    getDefaultTabId: function() {
        return this.m_defaultTabId;
    },

    // set the current tabId
    setCurrentTabId: function(currentTabId) {
        this.m_currentTabId = currentTabId.toLowerCase();
    },

    // get the current tabId
    getCurrentTabId: function() {
        return this.m_currentTabId;
    },

    // set the current ad-hoc panel id
    setCurrentAdHocPanelId: function(currentAdHocPanelId) {
        this.m_currentAdHocPanelId = currentAdHocPanelId.toLowerCase();
    },

    // get the current ad-hoc panel id
    getCurrentAdHocPanelId: function() {
        return this.m_currentAdHocPanelId;
    },

    // set whether or not the next tab to be loaded should initiate a search
    setSearchOnLoad: function(searchOnLoad) {
        this.m_searchOnLoad = searchOnLoad;
    },

    // get whether or not the next tab to be loaded should initiate a search
    getSearchOnLoad: function() {
        return this.m_searchOnLoad;
    },

    // return true if the specified tab is the currently active one
    checkIsActive: function(tabId) {
        return tabId.toLowerCase() == this.m_currentTabId.toLowerCase();
    },

    // set a flag indicating the specified tab has been loaded
    setTabPanelIsLoaded: function(tabId) {
        this.m_aTabPanelsLoaded[tabId.toLowerCase()] = true;
    },

    // return true if the specified tab has been loaded
    getTabPanelIsLoaded: function(tabId) {
        return this.m_aTabPanelsLoaded[tabId.toLowerCase()];
    },

    // set a flag indicating the specified adhoc panel has been loaded
    setAdHocPanelIsLoaded: function(adHocPanelId) {
        this.m_aAdHocPanelsLoaded[adHocPanelId.toLowerCase()] = true;
    },

    // return true if the specified adhoc panel has been loaded
    getAdHocPanelIsLoaded: function(adHocPanelId) {
        return this.m_aAdHocPanelsLoaded[adHocPanelId.toLowerCase()];
    },

    // set the display mode
    setDisplayMode: function(displayMode) {
        this.m_displayMode = displayMode;
    },

    // get the display mode
    getDisplayMode: function() {
        return this.m_displayMode;
    },

    // handle a tab click
    handleTabClick: function(event) {
        var newTabId = event.data;
        this.updateLocationHash(newTabId, false);
    },

    // update the hash & call the location change checking function (instead of waiting for the timer to call the function)
    // the hash checker will pick this change up and call showTabPanel or showAdHocPanel with the panel id
    updateLocationHash: function(panelId, searchOnLoad) {
        this.setSearchOnLoad(searchOnLoad);

        document_setLocationHash(panelId);
        this.checkLocationChange();
    },

    // show a tab panel
    showTabPanel: function(newTabId) {
        
        newTabId = newTabId.toLowerCase();
        
        var newTabData = this.getTabTabDataById(newTabId);
        var currentTabData = this.getTabTabDataById(this.getCurrentTabId());

        this.setCurrentTabId(newTabId);

        // change tab images
        var tabTabData = this.getTabTabDataById(this.getCurrentTabId());
        if (tabTabData) {
            $("#" + tabTabData.imageId + "").attr("src", tabTabData.activeImagePath);           // change image clicked on
            $("#" + tabTabData.handlerImageId + "").attr("src", tabTabData.activeImagePath);    // change handler image clicked on

            $.showInactiveImages(tabTabData.imageId, tabTabData.handlerImageId, this.m_aTabImageIds);   // change other images to inactive
        }

        // change link images
        var tabLinkData = this.getTabLinkDataById(this.getCurrentTabId());
        if (tabLinkData) {
            $("#" + tabLinkData.imageId + "").attr("src", tabLinkData.activeImagePath);         // change image clicked on
            $("#" + tabLinkData.handlerImageId + "").attr("src", tabLinkData.activeImagePath);  // change image clicked on

            $.showInactiveImages(tabLinkData.imageId, tabLinkData.handlerImageId, this.m_aLinkImageIds);    // change other images to inactive
        }

        // load panel (if necessary)
        if (((newTabData && newTabData['url'] && (newTabData['url'] !== "")) &&
            (!currentTabData || (currentTabData && ((currentTabData['url'] != newTabData['url']))))) ||
            (this.getDisplayMode() === g_panelTypeAdHoc)) {

            if (this.getTabPanelIsLoaded(newTabId)) {
                // panel has already been loaded, so simply display it
                this.displayPanelContent(newTabId, false);
            }
            else {
                // load new panel (no data to be loaded afterwards)
                this.loadPanelContent(newTabId);
            }
        }
        else {
            // nothing to do here (no data to be loaded)
        }

        return false;
    },

    // asynchronously set the content panel body to the contents of the user fron the specified tab
    // typically used to retrieve a ViewUserControl rendered by a controller
    // call the success callback when completed
    loadPanelContent: function(tabId) {

        var tabData = this.getTabTabDataById(tabId); // use tab data, not link data
        if (tabData && tabData['url'] && (tabData['url'] !== "")) {

            // show the overlay
            this.showOverlay();

            // load the content
            $.ajax({
                url: tabData['url'],
                type: g_method_get, // get so the server can distinguish between display and update of action with same name
                dataType: g_dataType_html,
                success: delegate(this, this.onLoadPanelContentSuccess),
                error: delegate(this, this.onLoadPanelContentFailed)
            });
        }
    },

    // load the returned html content into the specified element
    onLoadPanelContentSuccess: function(data) {
        var tabId = this.getCurrentTabId();
        tabId = tabId.toLowerCase();

        // if the element doesn't exist, create it as a child of ajax_page_content_wrapper
        var contentElementId = this.m_contentElementIdPrefix + tabId;
        if ($("#" + contentElementId).length === 0) {
            $("#ajax_page_content_wrapper").append('<div id="' + contentElementId + '" style="display: none;"></div>');
        }

        // insert returned content into page
        $("#" + contentElementId).html(data);

        // record the fact that this panel content has now been loaded
        this.setTabPanelIsLoaded(tabId);

        // display the panel
        this.displayPanelContent(tabId, true);
    },

    // load of ad-hoc panel content failed
    onLoadPanelContentFailed: function() {

        // hide the overlay
        this.hideOverlay();

        // contine error processing
        jQuery_ajaxRequestFailed_redirectToLogin();
    },

    // display the contents of an already-loaded panel
    displayPanelContent: function(tabId, isFirstTime) {

        tabId = tabId.toLowerCase();
        var tabData = this.getTabTabDataById(tabId); // use tab data, not link data

        // set page title
        document_setPageTitle(tabData.title);

        // animate showing of navigation buttons (if necessary) then show the current page content
        var contentElementId = this.m_contentElementIdPrefix + tabId;

        if (this.getDisplayMode() === g_panelTypeTab) {
            // swap current page content then hide top left nav buttons
            this.swapPageContent(contentElementId, tabId);
            this.setDisplayMode(g_panelTypeTab);
            this.showTopLeftNavButtons(false);

            // fire an event so listeners can update
            this.fireEvent(g_customEvent_navPanelCenterHelper_displayPanelContent, tabId, g_panelTypeTab, isFirstTime);

            // hide the overlay
            this.hideOverlay();
        }
        else {
            // swap page content
            // then animate slide-down showing of main navigation buttons and slide down of current page content
            // then show top left nav buttons
            this.swapPageContent(contentElementId, tabId);
            this.setDisplayMode(g_panelTypeTab);

            $("#slideable_content_wrapper").animate({ top: 44 }, g_pageTransitionTime_milliseconds,
                new delegate(this, function() {
                    this.showTopLeftNavButtons(false);

                    // fire an event so listeners can update
                    this.fireEvent(g_customEvent_navPanelCenterHelper_displayPanelContent, tabId, g_panelTypeTab, isFirstTime);
                }));

            // hide the overlay
            this.hideOverlay();

            // contract scrollbar smoothly
            flexscroll_adjustHeight('', -58, g_pageTransitionTime_milliseconds);
        }
    },

    // show an adhoc panel
    showAdHocPanel: function(adHocPanelId) {

        adHocPanelId = adHocPanelId.toLowerCase();
    
        var newAdHocPanelData = this.getAdHocPanelDataById(adHocPanelId);
        var currentAdHocPanelData = this.getAdHocPanelDataById(this.getCurrentAdHocPanelId());

        this.setCurrentAdHocPanelId(adHocPanelId);

        // load panel (if necessary)
        if (((newAdHocPanelData && newAdHocPanelData['url'] && (newAdHocPanelData['url'] !== "")) &&
            (!currentAdHocPanelData || (currentAdHocPanelData && ((currentAdHocPanelData['url'] != newAdHocPanelData['url']))))) ||
            (this.getDisplayMode() === g_panelTypeTab)) {

            // if panel has been loaded already, simply displayed it
            // with the exception of the account panel which should be loaded each time
            // so the values always reflect the contents of the db
            if (this.getAdHocPanelIsLoaded(adHocPanelId) && (adHocPanelId !== g_adHocPanel_account)) {
                // panel has already been loaded, so simply display it
                this.displayAdHocPanelContent(adHocPanelId, false);
            }
            else {
                // load new panel (no data to be loaded afterwards)
                this.loadAdHocPanelContent(adHocPanelId);
            }
        }
        else {
            // nothing to do here (no data to be loaded)
        }

        return false;
    },

    // load ad-hoc panel content whose pages aren't selected by clicking a tab
    loadAdHocPanelContent: function(adHocPanelId) {

        var adHocPanelData = this.getAdHocPanelDataById(adHocPanelId);
        if (adHocPanelData && adHocPanelData['url'] && (adHocPanelData['url'] !== "")) {

            // show the overlay
            this.showOverlay();

            // load the content
            $.ajax({
                url: adHocPanelData['url'],
                type: g_method_get, // get so the server can distinguish between display and update of action with same name
                dataType: g_dataType_html,
                success: delegate(this, this.onLoadAdHocPanelContentSuccess),
                error: delegate(this, this.onLoadAdHocPanelContentFailed)
            });
        }
    },

    // load the returned html content into the specified element
    onLoadAdHocPanelContentSuccess: function(data) {
        var adHocPanelId = this.getCurrentAdHocPanelId();
        adHocPanelId = adHocPanelId.toLowerCase();

        // if the element doesn't exist, create it as a child of ajax_page_content_wrapper (initally hidden)
        var contentElementId = this.m_contentElementIdPrefix + adHocPanelId;
        if ($("#" + contentElementId).length === 0) {
            $("#ajax_page_content_wrapper").append('<div id="' + contentElementId + '" style="display: none;"></div>');
        }

        // insert returned content into page
        $("#" + contentElementId).html(data);

        // record the fact that this panel content has now been loaded
        this.setAdHocPanelIsLoaded(adHocPanelId);

        // display the panel
        this.displayAdHocPanelContent(adHocPanelId, true);
    },

    // load of ad-hoc panel content failed
    onLoadAdHocPanelContentFailed: function() {

        // hide the overlay
        this.hideOverlay();

        // contine error processing
        jQuery_ajaxRequestFailed_redirectToLogin();
    },

    // display the contents of an already-loaded panel
    displayAdHocPanelContent: function(adHocPanelId, isFirstTime) {

        adHocPanelId = adHocPanelId.toLowerCase();
        var adHocData = this.getAdHocPanelDataById(adHocPanelId);

        // set page title
        document_setPageTitle(adHocData.title);

        // animate showing of navigation buttons (if necessary) then show the current page content
        var contentElementId = this.m_contentElementIdPrefix + adHocPanelId;

        if (this.getDisplayMode() === g_panelTypeTab) {
            // animate slide-up hiding of navigation buttons and slide up of current page content
            // then swap current page content & show header bar navigation buttons
            $("#slideable_content_wrapper").animate({ top: -14 }, g_pageTransitionTime_milliseconds,
                new delegate(this, function() {
                    this.swapPageContent(contentElementId, adHocPanelId);
                    this.setDisplayMode(g_panelTypeAdHoc);
                    this.showTopLeftNavButtons(true);

                    // fire an event so listeners can update
                    this.fireEvent(g_customEvent_navPanelCenterHelper_displayPanelContent, adHocPanelId, g_panelTypeAdHoc, isFirstTime);
                }));

            // hide the overlay
            this.hideOverlay();

            // extend scrollbar smoothly
            flexscroll_adjustHeight('', 58, g_pageTransitionTime_milliseconds);
        }
        else {
            // just swap page content & show top left nav buttons
            this.swapPageContent(contentElementId, adHocPanelId);
            this.setDisplayMode(g_panelTypeAdHoc);
            this.showTopLeftNavButtons(true);

            // fire an event so listeners can update
            this.fireEvent(g_customEvent_navPanelCenterHelper_displayPanelContent, adHocPanelId, g_panelTypeAdHoc, isFirstTime);

            // hide the overlay
            this.hideOverlay();
        }
    },

    // swap page content
    swapPageContent: function(contentElementId, panelId) {

        // hide all page content then show new page & set display mode
        // use css instead of show/hide because we don't know what original setting is
        // chain events so they happen in correct order
        if (this.getDisplayMode() === g_panelTypeTab) {
            for (var i = 0; i < this.m_tabDataTabs.length; i++) {
                $("#" + this.m_contentElementIdPrefix + this.m_tabDataTabs[i].stringData.toLowerCase() + "").css("display", "none");
            }
            $("#" + contentElementId).css("display", "block");
        }
        else {
            $("#" + this.m_contentElementIdPrefix + g_adHocPanel_welcome + "").css("display", "none");
            $("#" + this.m_contentElementIdPrefix + g_adHocPanel_info + "").css("display", "none");
            $("#" + this.m_contentElementIdPrefix + g_adHocPanel_account + "").css("display", "none");
            $("#" + this.m_contentElementIdPrefix + g_adHocPanel_http404 + "").css("display", "none");
            $("#" + contentElementId).css("display", "block");
        }
    },

    // show either the nav buttons on the top left or the standard 'download songshifter / music player' buttons
    showTopLeftNavButtons: function(show) {
        if (show) {
            $("#" + "header_left_standard_buttons").css("display", "none");
            $("#" + "header_left_nav_buttons_dynamic").css("display", "block");
        }
        else {
            $("#" + "header_left_nav_buttons_dynamic").css("display", "none");
            $("#" + "header_left_standard_buttons").css("display", "block");
        }
    },

    // show the overlay which disables the site while transitioning between
    // tabs / adhoc panels whehn a load is required
    showOverlay: function() {

        $('#tabtransition_overlay')
            .addClass("tabtransition_overlayBG")
            .css('opacity', g_overlayOpacityLight)
            .fadeIn(0);

        $('#tabtransition_loading')
            .fadeIn(0);

        return false;
    },

    // hide the overlay which disables the site while transitioning between
    // tabs / adhoc panels when alert load isFinite required
    hideOverlay: function() {

        $('#tabtransition_overlay')
        .fadeOut(0, function() {
            $("#tabtransition_overlay").removeClass("tabtransition_overlayBG")
            $("#tabtransition_overlay").addClass("tabtransition_hide");
        });

        $('#tabtransition_loading')
            .fadeOut(0);

        return false;
    }
});