/*********************************************************************
 **
 **   server/appx-client-menu.js - Client Menu/Toolbar processing
 **
 **   This module contains code to process Appx Menus and Toolbars.
 **
 *********************************************************************/

// what_str =  "@(#)Appx $Header: /src/cvs/appxHtml5/server/appx-client-menu.js,v 1.73 2016/04/28 19:50:48 jnelson Exp $";

var menugroups = [];
var menulabels = [];
var menuitems = [];
var menu = {};
var menu2 = {};

function MenuTree() {
    this.fileMenu = null;
    this.userMenu = [];
    this.optnMenu = null;
    this.helpMenu = null;
}

function MenuNode(label, widget) {
    this.label = label;
    this.widget = widget;
    this.children = [];
}

function MenuItem(label, widget) {
    this.label = label;
    this.widget = widget;
}

function mGroup(menuGroup, label, widget) {
    this.menuGroup = menuGroup;
    this.label = label;
    this.widget = widget;
    this.children = [];
}

function mChild(menuLabel, label, widget) {
    this.menuLabel = menuLabel;
    this.label = label;
    this.widget = widget;
}

function initializeMenu() {
    $("#appx-softkeys-container .toolbaritem").remove();
    $("#appx-defaulttools-container .toolbaritem").remove();
    appx_session.currentmenu = {};
    appx_session.currentmenu.groupsprocessed = [];
    appx_session.currentmenu.groups = {};
    appx_session.currentmenu.groupsprocessed.push("top_menu");
    appx_session.menucache = {};
    appx_session.menucache.currentmenuitems = appx_session.currentmenuitems;
    appx_session.menucache.currentmenu = appx_session.currentmenu;
    appx_session.currentmenuitems = {};
    appx_session.currentmenuitems.all = [];
    appx_session.currentmenuitems.toolbar = [
        [],
        [],
        []
    ];
    appx_session.currentmenuitems.dropdown = [
        [],
        [],
        []
    ];
    appx_session.currentmenuitems.popup = [
        [],
        [],
        []
    ];
    appx_session.currentmenu.block = {};
    appx_session.currentmenu.header = [];
}

//MENU Message Handler
function appxmenuhandler(x) {
    appx_session.currentmenu.block = x;
    appx_session.currentmenu.header.push(new Widget(null, null, appx_session.currentmenu.block.data.headerdata));
    //In LOCALOS for testing
    appxmenushandler(x);
}

//Menus Message Handler
function appxmenushandler(x) {
    var menu = x.data;
    var menuType = menu.type[0];
    //split menu.headerdata into vars
    var mw = new Widget(null, null, null);
    mw.widgetData = x.data.headerdata;
    var menuheader = mw.parseDataIntoPairs();
    $.each(menuheader, function (k, v) {
        menuheader[v.key] = v.value;
    });
    //if use=t, reuse last menu
    if (menuheader.USE) {
        switch (menuheader.USE.trim()) {
            case "T":
                appx_session.currentmenuitems.toolbar[menuType] = appx_session.menucache.currentmenuitems.toolbar[menuType];
                appx_session.currentmenuitems.dropdown[menuType] = appx_session.menucache.currentmenuitems.dropdown[menuType];
                appx_session.currentmenuitems.popup[menuType] = appx_session.menucache.currentmenuitems.popup[menuType];
                break;
            default:
        }
    }
    else {
        if (menu.items.length > 0) {
            var i = 1;
            while (menu.items.length > 0) {
                var mx = menu.items.shift();
                mx.widget = new Widget(null, null, mx.data);
                appx_session.currentmenuitems.all.push(mx.widget);
                if (mx.widget.wUsageToolbar == true) {
                    appx_session.currentmenuitems.toolbar[menuType].push(mx.widget);
                }
                if (mx.widget.wUsagePopup == true) {
                    appx_session.currentmenuitems.popup[menuType].push(mx.widget);
                }
                if (mx.widget.wUsageMenu == true) {
                    appx_session.currentmenuitems.dropdown[menuType].push(mx.widget);
                }
            }
        }
    }
}


/*
**Function that takes 2 menus in and checks the first menus objects against the second
**menus children objects. If they are a match then it will add the second menus child
**objects children to the matching first menu object. If the same menu object is sent
**as both object parameters then the boolean parameter should be set to true. If this
**is set, then if it does find a match, after copying the objects children it will 
**delete the object from the second menu.
**
**@param mMenu: menu to place items in.
**@param mTemp: menu containing temporary items that had no group created in main menu.
**@param mTempSent: boolean to tell whether we sent in temp menu as mMenu. 
**
**@return mMenu: Object containing menu items.
**
*/
function placeMenuItems(mMenu, mTemp, mTempSent){
    for (var tKeys in mTemp){
	var placed = false;
	for (var mKeys in mMenu){
	    if (mMenu[mKeys].hasOwnProperty("children") && mMenu[mKeys].children.hasOwnProperty(tKeys)){
		mMenu[mKeys].children[tKeys].children = mTemp[tKeys].children;
		if (mTempSent){
		    delete mTemp[tKeys];
		}
		placed = true;
		break;
	    }
	}
	if(!placed){
	    mMenu[tKeys] = mTemp[tKeys];
	}
    }
    return mMenu
}

/*
**Function to take an list of widgets and turn them into a nested object for
**properly displaying menus.
**
**@param m: array of widgets.
**
**@return menu: object containing menu items.
*/
function fixMenuLabelsAndGroups(m) {
    try{
	/*
	**Recursive function to search through the menu and check if an items group 
	**already exists. If group exists then it will place item in that groups
	**children. If group doesn't exist it returns false value.
	**
	**@param mMenu: menu to search through.
	**@param mGroup: group name to search for.
	**@param mLabel: name of current item.
	**
	**@return boolean: Whether group was found.
	**
	*/
	function findGroup(mMenu, mGroup, mLabel){
	    found = false;
	    children = mMenu.hasOwnProperty("children");
	    if (mMenu.hasOwnProperty(mGroup) || (children && mMenu.children.hasOwnProperty(mGroup))){
		if (children){
		    if (mMenu.children[mGroup].hasOwnProperty("children")){
			mMenu.children[mGroup].children[mLabel] = {}
			mMenu.children[mGroup].children[mLabel].command = m[i].wCommand;
			mMenu.children[mGroup].children[mLabel].widget = m[i];
		    }else{
			mMenu.children[mGroup].children = {};
			mMenu.children[mGroup].children[mLabel] = {}
			mMenu.children[mGroup].children[mLabel].command = m[i].wCommand;
			mMenu.children[mGroup].children[mLabel].widget = m[i];
		    }
		}else{
		    if (mMenu[mGroup].hasOwnProperty("children")){
			mMenu[mGroup].children[mLabel] = {}
			mMenu[mGroup].children[mLabel].command = m[i].wCommand;
			mMenu[mGroup].children[mLabel].widget = m[i];
		    }else{
			mMenu[mGroup].children = {};
			mMenu[mGroup].children[mLabel] = {}
			mMenu[mGroup].children[mLabel].command = m[i].wCommand;
			mMenu[mGroup].children[mLabel].widget = m[i];
		    }

		}
		return true;
	    }else{
		for (var keys in mMenu){
		    if (keys != "widget"){
			found = findGroup(mMenu[keys], mGroup, mLabel);
		    }
		}
	    }
	    return found;
	}


	/*
	**Recursive function to search through the menu and check if an item is 
	**marked as hidden. If marked then we remove item from menu.
	**
	**@param mMenu: menu to search through.
	**
	*/
	function removeHidden(mMenu){
	    for (var keys in mMenu){
		children = mMenu[keys].hasOwnProperty("children");
		widget = mMenu[keys].hasOwnProperty("widget");
		if ( widget && mMenu[keys].widget.wVisible === false) {
		    delete mMenu[keys];
		}else if (children) {
		    removeHidden(mMenu[keys].children);
		}
	    }
	}
	
	var menu = {};
	var temp = {};
	//populate menu object
	for (var i = 0; i < m.length; i++){
	    var label = m[i].wLabel;

	    /*If it has group name check for group, else create item in top
	    **level of menu.*/  
	    if (m[i].wGroupName && m[i].wGroupName != ""){
		var group = m[i].wGroupName;
		var foundMenu = false;
		var foundTemp = false;

		foundMenu = findGroup(menu, group, label);
		if (!foundMenu){
		    foundTemp = findGroup(temp, group, label);
		}
		
		//If group was not found then create the group in temp object
		if (!foundMenu && !foundTemp){
		    temp[group] = {};
		    temp[group].autoCreate = true;
		    temp[group].children = {};
		    temp[group].children[label] = {};
		    temp[group].children[label].command = m[i].wCommand;
		    temp[group].children[label].widget = m[i];
		}
	    }else{
		menu[label] = {};
		menu[label].autoCreate = true;
		menu[label].command = m[i].wCommand;
		menu[label].widget = m[i];
	    }
	}

	/*Call placeMenuItems. Once to make sure temp doesn't contain any objects
	**that should be nested within itself and the second time to place all the
	**temp menu objects into the menu object.*/
	temp = placeMenuItems(temp, temp, true);
	menu = placeMenuItems(menu, temp, false);

	/*Call removeHidden to check for menu items that should not be displayed*/
	removeHidden(menu);
	
	/*Remove any automatically added parents that have no children and add them 
	**to top level menu based on menu name it was received from*/
	for (var keys in menu){
	    if ( menu[keys].autoCreate === true && ((!menu[keys].hasOwnProperty("children")) || jQuery.isEmptyObject(menu[keys].children)) && menu[keys].widget != null  ){
		var menuUse = menu[keys].widget.wMenuUse;
		if (!menu.hasOwnProperty(menuUse)){
		    menu[menuUse] = {};
		    menu[menuUse].children = {};
		}
		menu[menuUse].children[keys] = menu[keys];
		delete menu[keys];
	    }
	}
    }
    catch(e){
	console.log(e);
	console.log(e.stack);
    }
    return menu;
}

function buildMenuHTMLtree(menuNode, topLevel) {
    if (menuNode == null || !(menuNode.hasOwnProperty("children"))){
        return "";
    }
    var cmd = (menuNode.widget == null ? '' : " onclick='appxwidgetcallback(" + menuNode.widget.wCommand + ")'");
    if (topLevel){
	var wHTML = "<li" + cmd + " class='appx-menu-item'>" + (menuNode.widget == null ? menuNode.label : menuNode.widget.wLabel) + "<ul>";
    }else{
	var wHTML;
	if (menuNode.widget != null){
	    var shortCut = menuNode.widget.wShortcut;
	    var label = menuNode.widget.wLabel;
	    var shortReplace = label.replace(shortCut, "<span class='accesskeyunderline'>" + shortCut + "</span>");
	    if (shortCut != null){
		wHTML = "<li" + cmd + " class='appx-menu-item'> <a href='#' accesskey='" + shortCut + "' class='hasSub'>" + shortReplace  + "</a><ul>";
	    }else{
		wHTML = "<li" + cmd + " class='appx-menu-item'> <a href='#' class='hasSub'>" + label + "</a><ul>";
	    }
	    
	}else{
	    wHTML = "<li" + cmd + " class='appx-menu-item'> <a href='#' class='hasSub'>" + menuNode.label + "</a><ul>";
	}
    }
    for (var keys in menuNode.children) {
        var menuObj = menuNode.children[keys];
        if (menuObj.hasOwnProperty("children")) {
            wHTML += buildMenuHTMLtree(menuObj, false);
        }
        else {
            var cmd = null;
            var lbl = null;
	    var sepbefore = false;
            var sepafter = false;
            var disabled = '';
	    var tbvisible = true;
	    var cls = " class='appx-menu-item'";	    
	    
            if (menuObj.widget) {
		appxWidgetCheckSelected(menuObj.widget);
		if (menuObj.widget.wSelected == true){
		    var cls = " class='appx-menu-item appx-menu-item-selected'";
		}
		var tbvisible = menuObj.widget.wVisible == null ? true : menuObj.widget.wVisible;
                cmd = " onclick='appxwidgetcallback(" + menuObj.widget.wCommand + ")'";
                lbl = menuObj.widget.wLabel;
                sepbefore = menuObj.widget.wSepBefore == null ? false : true;
                sepafter = menuObj.widget.wSepAfter == null ? false : true;
                disabled = menuObj.widget.wEnabled == false ? ' disabled' : '';
                cmd = menuObj.widget.wEnabled == false ? "" : cmd;
            }
            else {
                lbl = menuObj.wLabel;
            }

	    if (tbvisible) {
		var li = $("<li" + cmd + "" + disabled + ">");
		var a = $("<a href='#'" + "" + cls + ">");
		a.text(lbl);
		$(li).append(a)
		if (sepbefore) $(li).addClass("sepbefore");
		if (sepafter) $(li).addClass("sepafter");
		if (disabled) $(li).addClass("disabled-item");

		if (menuObj.widget.wIconEnabled){
		    $(a).addClass(AppxResource.load(menuObj.widget.wIconEnabled));
		    $(a).addClass("appx-hasbg");
		}
		wHTML += $(li)[0].outerHTML;
	    }
        }
    }
    wHTML += "</ul></li>";
    return wHTML;
}

var topMenu = null;
/*
**Function to build dropdown menu using HTML
**
**@param menuTree: object containing menu items 
*/
function buildMenuHTML(menuTree) {
    var menunav = $("#appx-main-nav");
    var menuHTML = "";
    var nameSort = ["File","Options","Help"];

    if( topMenu == null ) {
	topMenu = $("<ul>").attr("id", "topMenu").appendTo(menunav);
    }
    //Cycle through objects in top level to process
    for (var keys in menuTree){
	var notFOH = true;

	//If object doesn't have a widget then set label to object name.
	if (!(menuTree[keys].hasOwnProperty("widget"))){
	    menuTree[keys].label = keys;
	}

	//Check if name is already in the nameSort array
	for (var i = 0; i < nameSort.length; i++){
	    if (nameSort[i] == keys){
		notFOH = false;
	    }
	}
	
	/*If name is not in nameSort array then we add it in. We are doing it
	**this way because we always want File to be the first menu item and 
	**Options & Help to be the last 2 menu items.*/
	if (notFOH){
	    if ( keys === "Process" || keys === "Application" || keys === "System" ){
		nameSort.splice(1, 0, keys);
	    }else{
		nameSort.splice((nameSort.length-2), 0, keys);
	    }
	}
    }
    
    //Create menu html code using the nameSort array order
    for (var i = 0; i < nameSort.length; i++){
	menuHTML += buildMenuHTMLtree(menuTree[nameSort[i]], true);
    }
    $(topMenu).append(menuHTML);
}

/*
**Function takes in command and returns function using command.
**Needed this so all callbacks didn't share same function.
**
**@param wCommand: string containing widget command
**
**@return function: function containing appxwidgetcallback function
*/
function popupMenuCallback(wCommand){
    return function(){
	appxwidgetcallback2(wCommand);
    };
    
}

/*
**Recursive function to populate nested items in the popup menus
**
**@param menuNode: Current level menu object
**@param childMenu: object to store children objects in
*/
function popupMenuChildren(menuNode, childMenu){
    for (var keys in menuNode){
	childMenu[keys] = {
	    "name": keys,
	};
	var menuObj = menuNode[keys];
	var icon = null;
	if( menuObj.widget && menuObj.widget.wIconEnabled ) {
	    icon = AppxResource.load(menuObj.widget.wIconEnabled);
	}

	if (menuNode[keys].hasOwnProperty("command")){
	    var wCommand = menuNode[keys].command.toString();
	    childMenu[keys].callback = popupMenuCallback(wCommand);
	    if( icon ) {
		childMenu[keys].icon = icon;
	    }
	}
	if (menuNode[keys].hasOwnProperty("children")){
	    childMenu[keys].items = {};
	    popupMenuChildren(menuNode[keys].children, childMenu[keys].items);
	}
    }
}

/*
**Function to build popup menu. Placed in subcategory of appx_session for use
**in appx-client-screen.js
**
**@param menuTree: object containing menu items 
*/
function buildPopupMenuHTML(menuTree) {
    appx_session.currentmenuitems.popupItems = {};
    var a = appx_session.currentmenuitems.popupItems;
    for (var keys in menuTree){
// Commented out code is if we want to add the high level menu group to the popup menu, the java client does not
//	a[keys] = {
//	    "name": keys,
//	};
//	if (menuTree[keys].hasOwnProperty("command")){
//	    var wCommand = menuTree[keys].command.toString();
//	    a[keys].callback = popupMenuCallback(wCommand);
//	}
	
	if (menuTree[keys].hasOwnProperty("children")){
// Commented out code is if we want to add the high level menu group to the popup menu, the java client does not
//	    a[keys].items = {};
//	    popupMenuChildren(menuTree[keys].children, a[keys].items);
	    popupMenuChildren(menuTree[keys].children, a);
	}
    }
}

/*
**Function to concatonate all the appx_session drop down menus into one object
**for further processing
*/
function createDropDownMenu() {
    $("ul#topMenu").empty();
    var a = [];
    var menuName = ["Process", "Application", "System"];
    for (var menuType = 2; menuType >= 0; menuType--) {
	var ddMenu = appx_session.currentmenuitems.dropdown[menuType];
	for (var i = 0; i < ddMenu.length; i++){
	    ddMenu[i].wMenuUse = menuName[menuType];
	}
        a = a.concat(ddMenu);
    }
    
    if (a.length > 0) {
	buildMenuHTML(fixMenuLabelsAndGroups(a));
    }
}

/*
**Function to concatonate all the appx_session popup menus into one object
**for further processing
*/
function createPopupMenu() {
    var a = [];
    for (var menuType = 2; menuType >= 0; menuType--) {
        a = a.concat(appx_session.currentmenuitems.popup[menuType]);
    }
    if (a.length > 0) {
	buildPopupMenuHTML(fixMenuLabelsAndGroups(a));
    }
}

function createdToolbarMenu() {
    var tbi = [];
    //no need to fix toolbar item hierarchy
    for (var menuType = 2; menuType >= 0; menuType--) {
        var a = appx_session.currentmenuitems.toolbar[menuType];
        for (var i = 0; i < appx_session.currentmenuitems.toolbar[menuType].length; i++) {
            tbi.push(appx_session.currentmenuitems.toolbar[menuType][i]);
        }
    }

    var $newtoolbar = $("<div>");
    var $newdeftoolbar = $("<div>");
    while (tbi.length > 0) {
        var mx = {};
        mx.widget = tbi.shift();
        var tbvisible = mx.widget.wVisible == null ? true : mx.widget.wVisible;
	if (mx.widget.wIconEnabled && tbvisible) {
            var item = $('<div>'); 
	    if (mx.widget.wSepBefore && mx.widget.wSepAfter){
		item.addClass("appx-sep-before appx-sep-after");
	    }else if (mx.widget.wSepBefore){
		item.addClass("appx-sep-before");
	    }else if (mx.widget.wSepAfter){
		item.addClass("appx-sep-after");
	    }
	    
	    if (mx.widget.wShortLabel) {
		$(item).html('<span style="vertical-align: -27px;font-size:11px;font-family:arial">' + mx.widget.wShortLabel.trim() + '</span>');
            }
            var cacheid = AppxResource.load(mx.widget.wIconEnabled);
            $(item).addClass("appxitem"); //item
            $(item).addClass("toolbaritem");
            $(item).addClass(cacheid);

            var tbenabled = mx.widget.wEnabled == null ? true : mx.widget.wEnabled;

            if (tbenabled == false) {
                $(item).addClass("tbdisabled");
            }else{
		$(item).click(function () {
                    appxwidgetcallback(this.id);
		});
	    }

            $(item).attr("id", addClientId(mx.widget.wCommand,mx.widget.wClientId));

            if (mx.widget.wTooltip) {
                $(item).prop('title', mx.widget.wTooltip);
                $(item).tooltip({
                    content: function () {
			    if( typeof this.title == 'function' )
				return this.title();
			    else
				return '';
                    }
                });
            }
            else if (mx.widget.wLabel) {
                $(item).prop('title', mx.widget.wLabel);
                $(item).tooltip({
                    content: function () {
			    if( typeof this.title == 'function' )
				return this.title();
			    else
				return '';
                    }
                });
            }



            if (tbvisible) {
                if (mx.widget.wCommand > "250") {
                    //FIX ME: deep clone keeps event, don't have to add em back with .clone(true)
                    //TODO: Fix clone
                    var ic = $(item).clone();
                    $(ic).attr("id", addClientId("sk_" + mx.widget.wCommand,mx.widget.wClientId));
                    $(ic).css({
                        "background-color": "transparent"
                    });
                    $(ic).click(function () {
			    var i = getClientId(this.id).replace("sk_", "");
                        appxwidgetcallback(i);
                    });
                    $newdeftoolbar.append(ic);
                }
                else {
                    $newtoolbar.append(item);
                }
            }
        }
    }
    $("#default-toolbar").html($newdeftoolbar);
    $("#toolbar").html($newtoolbar);
}
