﻿/* Slide menu */
/* Copyright (c) 2010 FoXSE Ltd */

/**************************************
 * MenuModes
 *************************************/
function _MenuModes() { }
_MenuModes.prototype.MENU_MODE_CLOSED = 0;
_MenuModes.prototype.MENU_MODE_OPENING = 1;
_MenuModes.prototype.MENU_MODE_OPEN = 2;
_MenuModes.prototype.MENU_MODE_CLOSING = 3;
var MenuModes = new _MenuModes();

/**************************************
* MenuConstants
*************************************/
function _MenuConstants() { }
_MenuConstants.prototype.WKM_WIDTH_ADJUST = 5;
_MenuConstants.prototype.IE6_FIXED_WIDTH = 100;

_MenuConstants.prototype.SLIDE_MENU_HIDE_NORMAL = 1000;
_MenuConstants.prototype.SLIDE_MENU_HIDE_NORMAL_WKM = 3000;
_MenuConstants.prototype.SLIDE_MENU_HIDE_CLEANUP = 2000;
_MenuConstants.prototype.SLIDE_MENU_HIDE_CLEANUP_WKM = 4000;
_MenuConstants.prototype.SLIDE_MENU_ROLL_AMOUNT_PX = 10;

var MenuConstants = new _MenuConstants();

/**************************************
* SlideMenu
*************************************/
function SlideMenu() { }
SlideMenu.prototype.panelId = null;
SlideMenu.prototype.mode = MenuModes.MENU_MODE_CLOSED;
SlideMenu.prototype.mouseInBodyOrTitle = false;
SlideMenu.prototype.tempInnerHTML = null;

/* dimensions */
SlideMenu.prototype.menuPanelWidth = null;
SlideMenu.prototype.menuPanelHeight = null;

/* timers */
SlideMenu.prototype.hideTimer = null;
SlideMenu.prototype.cleanupTimer = null;
SlideMenu.prototype.doneTimer = null;

/**************************************
* Globals
*************************************/
var SLIDE_PANEL_GLOBAL_ZINDEX = 1000;
var SLIDE_PANEL_GLOBAL_OPEN = new Array();

/**************************************
* Show menu
*************************************/
function startOpening(panelId) {
    try {
        //LOGGER.trace("startOpening " + panelId);

        var panelObj = document.getElementById(panelId);
        var mo = panelObj.menu;

        mo.mode = MenuModes.MENU_MODE_OPENING;

        /*
        * Set panel width.
        */
        if (!mo.menuPanelWidth) {
            if (is_ie6) {
                //fixed width hack for IE6
                mo.menuPanelWidth = MenuConstants.IE6_FIXED_WIDTH;

            } else if (is_webkitmobile_mode) {
                //fixed and full width for iPhone
                mo.menuPanelWidth = getCurrentWKMWidth() - MenuConstants.WKM_WIDTH_ADJUST;
                panelObj.style.left = 0;

            } else {
                /*
                * Explicitly set width to clientwidth, before we
                * remove the panel's contents (or it will collapse
                * to 0).
                */
                mo.menuPanelWidth = panelObj.clientWidth;
            }
        }

        if (mo.menuPanelWidth && mo.menuPanelWidth > 0) {
            panelObj.style.width = mo.menuPanelWidth + "px";
        }

        //remove/save content
        if (!mo.tempInnerHTML) {
            mo.tempInnerHTML = panelObj.innerHTML;
        }
        panelObj.innerHTML = "";

        //set z-index
        try {
            SLIDE_PANEL_GLOBAL_ZINDEX++;
            panelObj.style.zIndex = SLIDE_PANEL_GLOBAL_ZINDEX;

        } catch (exZindex) {
            wrapEx("error setting z-index for panelId: " + panelId, exZindex);
        }

        //set mo back on element
        panelObj.menu = mo;

        //add to global array
        SLIDE_PANEL_GLOBAL_OPEN.push(panelObj);

        panelObj.style.visibility = "visible";

        //start cleanup timer
        deactivateAndClearTimers(mo);
        mo.cleanupTimer = setTimeout("hideMenuCleanup(\"" + panelObj.id + "\")", getSlideMenuHideCleanup());

        //start opening
        rollObject(panelObj, 0, mo.menuPanelHeight, "menuShowDone(\"" + panelId + "\")", "+", MenuConstants.SLIDE_MENU_ROLL_AMOUNT_PX);

    } catch (ex) {
        wrapEx("error in startOpening, panelId:" + panelId, ex);
    }
}

function menuShowDone(panelId) {
    try {
        //LOGGER.trace("menuShowDone " + panelId);

        var panelObj = document.getElementById(panelId);
        var mo = panelObj.menu;

        if (mo) {
            if (mo.mode != MenuModes.MENU_MODE_OPENING) {
                //LOGGER.debug("Skipping open completion for " + panelId);

            } else {
                //LOGGER.debug("Processing open completion for " + panelId);

                if (!panelObj.innerHTML) {
                    panelObj.innerHTML = mo.tempInnerHTML;
                }
                //mo.tempInnerHTML = null;

                mo.mode = MenuModes.MENU_MODE_OPEN;

                panelObj.menu = mo;
            }
        }

    } catch (ex) {
        wrapEx("error in menuShowDone, panelId:" + panelId, ex);
    }
}

/**************************************
* Hide menu
*************************************/
function hideOpenMenus() {
    try {
        //LOGGER.debug("Hiding " + SLIDE_PANEL_GLOBAL_OPEN.length + " open/opening menus");

        //hide open menus
        if (SLIDE_PANEL_GLOBAL_OPEN && SLIDE_PANEL_GLOBAL_OPEN.length > 0) {

            //copy the global array
            var openCopy = new Array();
            for (i = SLIDE_PANEL_GLOBAL_OPEN.length - 1; i >= 0; i--) {
                var openObj = SLIDE_PANEL_GLOBAL_OPEN[i];
                openCopy.push(openObj);
            }

            //loop through copy (cleanup activities will modify global array)
            for (i = openCopy.length - 1; i >= 0; i--) {
                var openObj = openCopy[i];

                //start close process
                hideMenuNormal(openObj.id);
            }
        }

    } catch (exHideExisting) {
        wrapEx("error hiding open/opening menus", exHideExisting);
    }
}

function hideMenuNormal(panelId) {
    try {
        //LOGGER.trace("hideMenuNormal " + panelId);

        var panelObj = document.getElementById(panelId);
        var mo = panelObj.menu;

        if (mo && !mo.mouseInBodyOrTitle) {
            hideMenu(panelId);
        }

    } catch (ex) {
        wrapEx("error in hideMenuNormal, panelId:" + panelId, ex);
    }
}

function hideMenuCleanup(panelId) {
    try {
        //LOGGER.trace("hideMenuCleanup " + panelId);

        hideMenu(panelId);

    } catch (ex) {
        wrapEx("error in hideMenuCleanup, panelId:" + panelId, ex);
    }
}

function hideMenu(panelId) {
    try {
        //LOGGER.trace("hideMenu " + panelId);

        var panelObj = document.getElementById(panelId);

        //remove from the global array
        var globalIdx = SLIDE_PANEL_GLOBAL_OPEN.indexOf(panelObj);
        if (globalIdx > -1) {
            SLIDE_PANEL_GLOBAL_OPEN.splice(globalIdx, 1);
        }

        //update menu object
        var mo = panelObj.menu;
        if (mo) {
            //clear timeouts
            if (mo.cleanupTimer) {
                clearTimeout(mo.cleanupTimer);
                mo.cleanupTimer = null;
            }
            if (mo.hideTimer) {
                clearTimeout(mo.hideTimer);
                mo.hideTimer = null;
            }

            //do if OPEN only
            if (mo.mode == MenuModes.MENU_MODE_OPEN) {
                //LOGGER.debug("Grabbing HTML of open menu " + panelId);

                if (!mo.tempInnerHTML) {
                    mo.tempInnerHTML = panelObj.innerHTML;
                }
                panelObj.innerHTML = "";
            }

            //do if OPEN or OPENING
            if (mo.mode == MenuModes.MENU_MODE_OPEN
                || mo.mode == MenuModes.MENU_MODE_OPENING) {

                //LOGGER.debug("Starting close of open/opening menu " + panelId);

                mo.mode = MenuModes.MENU_MODE_CLOSING;
                deactivateAndClearTimers(mo);
                panelObj.menu = mo;

                //start close
                rollObject(panelObj, mo.menuPanelHeight, 0, "menuHideDone(\"" + panelId + "\")", "-", MenuConstants.SLIDE_MENU_ROLL_AMOUNT_PX);
            }
        }

    } catch (ex) {
        wrapEx("error in hideMenu, panelId:" + panelId, ex);
    }
}

function menuHideDone(panelId) {
    try {
        //LOGGER.trace("menuHideDone " + panelId);

        var panelObj = document.getElementById(panelId);

        var mo = panelObj.menu;
        mo.mode = MenuModes.MENU_MODE_CLOSED;
        panelObj.menu = mo;

        panelObj.style.visibility = "hidden";

        if (is_webkitmobile_mode) {
            //resize to prevent hidden div from expanding page width in landscape mode
            panelObj.style.width = (WKM_PORTRAIT_WIDTH - MenuConstants.WKM_WIDTH_ADJUST) + "px";
        }

    } catch (ex) {
        wrapEx("error in menuHideDone, panelId:" + panelId, ex);
    }
}

/**************************************
* Mouse events
*************************************/
function menuTitleMouseIn(panelId, menuPanelHeight) {
    try {
        //LOGGER.trace("menuTitleMouseIn " + panelId);

        var panelObj = document.getElementById(panelId);
        var mo = panelObj.menu;

        /* create if doesn't exist */
        if (!mo) {
            mo = new SlideMenu();
            mo.panelId = panelId;
            mo.mode = MenuModes.MENU_MODE_CLOSED;
            mo.mouseInBodyOrTitle = true;
            mo.menuPanelHeight = menuPanelHeight;

            panelObj.menu = mo;
        }

        /* start opening if hidden */
        if (mo.mode == MenuModes.MENU_MODE_CLOSED) {
            //LOGGER.debug("Starting open of " + panelId);

            hideOpenMenus();
            startOpening(panelId);
        }

    } catch (ex) {
        wrapEx("error in menuTitleMouseIn, panelId:" + panelId + ", menuPanelHeight:" + menuPanelHeight, ex);
    }
}

function menuTitleMouseOut(panelId) {
    try {
        //LOGGER.trace("menuTitleMouseOut " + panelId);

        var panelObj = document.getElementById(panelId);
        var mo = panelObj.menu;

        if (mo) {
            mo.mouseInBodyOrTitle = false;
            panelObj.menu = mo;
        }

    } catch (ex) {
        wrapEx("error in menuTitleMouseOut, panelId:" + panelId, ex);
    }
}

function menuBodyMouseIn(panelObj) {
    try {
        var mo = panelObj.menu;
        if (mo) {
            //LOGGER.trace("menuBodyMouseIn " + mo.panelId);

            if (mo.mode == MenuModes.MENU_MODE_OPEN) {
                mo.mouseInBodyOrTitle = true;

                //reset timers
                deactivateAndClearTimers(mo);
                mo.hideTimer = setTimeout("hideMenuNormal(\"" + panelObj.id + "\")", getSlideMenuHideNormal());
                mo.cleanupTimer = setTimeout("hideMenuCleanup(\"" + panelObj.id + "\")", getSlideMenuHideCleanup());

                panelObj.menu = mo;
            }
        }

    } catch (ex) {
        wrapEx("error in menuBodyMouseIn, panelObj:" + panelObj, ex);
    }
}

function menuBodyMouseOut(panelObj) {
    try {
        var mo = panelObj.menu;

        if (mo) {
            mo.mouseInBodyOrTitle = false;
            panelObj.menu = mo;
        }

    } catch (ex) {
        wrapEx("error in menuBodyMouseOut, panelObj:" + panelObj, ex);
    }
}

/**************************************
* Utils
*************************************/
function deactivateAndClearTimers(mo) {
    try {
        //LOGGER.trace("deactivateAndClearTimers " + mo.panelId);

        if (mo.hideTimer) {
            clearTimeout(mo.hideTimer);
            mo.hideTimer = null;
        }

        if (mo.cleanupTimer) {
            clearTimeout(mo.cleanupTimer);
            mo.cleanupTimer = null;
        }

    } catch (ex) {
        wrapEx("error in deactivateAndClearTimers, mo:" + mo, ex);
    }
}

function getSlideMenuHideNormal() {
    if (is_webkitmobile_mode) {
        return MenuConstants.SLIDE_MENU_HIDE_NORMAL_WKM;
    } else {
        return MenuConstants.SLIDE_MENU_HIDE_NORMAL;
    }
}

function getSlideMenuHideCleanup() {
    if (is_webkitmobile_mode) {
        return MenuConstants.SLIDE_MENU_HIDE_CLEANUP_WKM;
    } else {
        return MenuConstants.SLIDE_MENU_HIDE_CLEANUP;
    }
}

