/**
 * context menu
 */

define([
    'jquery',
    'app/render'
], ($, Render) => {

    'use strict';

    let config = {
        contextMenuContainerId: 'pf-contextmenu-container',                         // id for container element that holds (hidden) context menus
        mapContextMenuId: 'pf-map-contextmenu',                                     // id for "maps" context menu
        connectionContextMenuId: 'pf-map-connection-contextmenu',                   // id for "connections" context menu
        endpointContextMenuId: 'pf-map-endpoint-contextmenu',                       // id for "endpoints" context menu
        systemContextMenuId: 'pf-map-system-contextmenu',                           // id for "systems" context menu

        contextMenuClass: 'dropdown-menu',                                          // class for all context menus
        subMenuLeftClass: 'dropdown-submenu-left',                                  // class moves submenus to the left side

        animationInType: 'transition.flipXIn',
        animationInDuration: 150,
        animationOutType: 'transition.flipXOut',
        animationOutDuration: 150
    };

    /**
     * calc menu X coordinate
     * @param e
     * @param menuWidth
     * @returns {number|*}
     */
    let getMenuLeftCoordinate = (e, menuWidth) => {
        let mouseWidth = e.pageX;
        let openSubLeft = false;
        if(mouseWidth + menuWidth > window.innerWidth && menuWidth < mouseWidth){
            // opening menu would pass the side of the page
            openSubLeft = true;
            //return mouseWidth - menuWidth;
            mouseWidth -= menuWidth;
        }else if(mouseWidth + menuWidth * 2 > window.innerWidth && menuWidth * 2 < mouseWidth){
            // opening submenu would pass the side of the page
            openSubLeft = true;
        }
        return {
            left: mouseWidth,
            openSubLeft: openSubLeft
        };
    };

    /**
     * calc menu Y coordinate
     * @param e
     * @param menuHeight
     * @returns {number|*}
     */
    let getMenuTopCoordinate = (e, menuHeight) => {
        let mouseHeight = e.pageY;
        if(mouseHeight + menuHeight > window.innerHeight && menuHeight < mouseHeight){
            // opening menu would pass the bottom of the page
            mouseHeight -= menuHeight;
        }
        return {
            top: mouseHeight
        };
    };

    /**
     * render context menu template for maps
     * @returns {*}
     */
    let renderMapContextMenu = () => {
        let moduleData = {
            id: config.mapContextMenuId,
            items: [
                {icon: 'fa-plus', action: 'add_system', text: 'add system'},
                {icon: 'fa-object-ungroup', action: 'select_all', text: 'select all'},
                {icon: 'fa-filter', action: 'filter_scope', text: 'filter scope', subitems: [
                        {subIcon: '', subAction: 'filter_wh', subText: 'wormhole'},
                        {subIcon: '', subAction: 'filter_stargate', subText: 'stargate'},
                        {subIcon: '', subAction: 'filter_jumpbridge', subText: 'jumpbridge'},
                        {subIcon: '', subAction: 'filter_abyssal', subText: 'abyssal'}
                    ]},
                {icon: 'fa-sitemap', action: 'map', text: 'map', subitems: [
                        {subIcon: 'fa-edit', subAction: 'map_edit', subText: 'edit map'},
                        {subIcon: 'fa-street-view', subAction: 'map_info', subText: 'map info'},
                    ]},
                {divider: true, action: 'delete_systems'},
                {icon: 'fa-trash', action: 'delete_systems', text: 'delete systems'}
            ]
        };

        return Render.render('modules/contextmenu', moduleData);
    };

    /**
     * render context menu template for connections
     * @returns {*}
     */
    let renderConnectionContextMenu = () => {
        let moduleData = {
            id: config.connectionContextMenuId,
            items: [
                {icon: 'fa-hourglass-end', action: 'wh_eol', text: 'toggle EOL'},
                {icon: 'fa-exclamation-triangle', action: 'preserve_mass', text: 'preserve mass'},
                {icon: 'fa-reply fa-rotate-180', action: 'change_status', text: 'mass status', subitems: [
                        {subIcon: 'fa-circle', subIconClass: 'txt-color txt-color-gray', subAction: 'status_fresh', subText: 'stage 1 (fresh)'},
                        {subIcon: 'fa-circle', subIconClass: 'txt-color txt-color-orange', subAction: 'status_reduced', subText: 'stage 2 (reduced)'},
                        {subIcon: 'fa-circle', subIconClass: 'txt-color txt-color-redDark', subAction: 'status_critical', subText: 'stage 3 (critical)'}

                    ]},
                {icon: 'fa-reply fa-rotate-180', action: 'wh_jump_mass_change', text: 'ship size', subitems: [
                        {subIcon: 'fa-char', subChar: 'S', subAction: 'wh_jump_mass_s', subText: 'smallest ships'},
                        {subIcon: 'fa-char', subChar: 'M', subAction: 'wh_jump_mass_m', subText: 'medium ships'},
                        {subIcon: 'fa-char', subChar: 'L', subAction: 'wh_jump_mass_l', subText: 'larger ships'},
                        {subIcon: 'fa-char', subChar: 'XL', subAction: 'wh_jump_mass_xl', subText: 'capital ships'}

                    ]},
                {icon: 'fa-crosshairs', action: 'change_scope', text: 'change scope', subitems: [
                        {subIcon: 'fa-minus-circle', subIconClass: '', subAction: 'scope_wh', subText: 'wormhole'},
                        {subIcon: 'fa-minus-circle', subIconClass: 'txt-color txt-color-indigoDarkest', subAction: 'scope_stargate', subText: 'stargate'},
                        {subIcon: 'fa-minus-circle', subIconClass: 'txt-color txt-color-tealLighter', subAction: 'scope_jumpbridge', subText: 'jumpbridge'}

                    ]},
                {divider: true, action: 'separator'} ,
                {icon: 'fa-unlink', action: 'delete_connection', text: 'detach'}
            ]
        };

        return Render.render('modules/contextmenu', moduleData);
    };

    /**
     * render context menu template for endpoints
     * @returns {*}
     */
    let renderEndpointContextMenu = () => {
        let moduleData = {
            id: config.endpointContextMenuId,
            items: [
                {icon: 'fa-globe', action: 'bubble', text: 'bubbled'}
            ]
        };

        return Render.render('modules/contextmenu', moduleData);
    };

    /**
     * render context menu template for systems
     * @param systemStatusData
     * @returns {*}
     */
    let renderSystemContextMenu = systemStatusData => {
        let statusData = [];
        for(let [statusName, data] of Object.entries(systemStatusData)){
            statusData.push({
                subIcon:        'fa-tag',
                subIconClass:   data.class,
                subAction:      'change_status_' + statusName,
                subText:        data.label
            });
        }

        let moduleData = {
            id: config.systemContextMenuId,
            items: [
                {icon: 'fa-plus', action: 'add_system', text: 'add system'},
                {icon: 'fa-lock', action: 'lock_system', text: 'lock system'},
                {icon: 'fa-volume-up', action: 'set_rally', text: 'set rally point'},
                {icon: 'fa-tags', text: 'set status', subitems: statusData},
                {icon: 'fa-route', action: 'find_route', text: 'find route'},
                {icon: 'fa-object-group', action: 'select_connections', text: 'select connections'},
                {icon: 'fa-reply fa-rotate-180', text: 'waypoints', subitems: [
                        {subIcon: 'fa-flag', subAction: 'set_destination', subText: 'set destination'},
                        {subDivider: true, action: ''},
                        {subIcon: 'fa-step-backward', subAction: 'add_first_waypoint', subText: 'add new [start]'},
                        {subIcon: 'fa-step-forward', subAction: 'add_last_waypoint', subText: 'add new [end]'}
                    ]},
                {divider: true, action: 'delete_system'},
                {icon: 'fa-trash', action: 'delete_system', text: 'delete system(s)'}
            ]
        };

        return Render.render('modules/contextmenu', moduleData);
    };

    /**
     * prepare (hide/activate/disable) some menu options
     * @param menuElement
     * @param hiddenOptions
     * @param activeOptions
     * @param disabledOptions
     * @returns {*}
     */
    let prepareMenu = (menuElement, hiddenOptions, activeOptions, disabledOptions) => {
        let menuLiElements = menuElement.find('li');

        // reset all menu entries
        menuLiElements.removeClass('active').removeClass('disabled').show();

        // hide specific menu entries
        for(let action of hiddenOptions){
            menuElement.find('li[data-action="' + action + '"]').hide();
        }

        //set active specific menu entries
        for(let action of activeOptions){
            menuElement.find('li[data-action="' + action + '"]').addClass('active');
        }

        //disable specific menu entries
        for(let action of disabledOptions){
            menuElement.find('li[data-action="' + action + '"]').addClass('disabled');
        }

        return menuElement;
    };

    /**
     * close all context menus (map, connection,...)
     * @param excludeMenu
     */
    let closeMenus = excludeMenu => {
        let allMenus = $('.' + config.contextMenuClass + '[role="menu"][style*="display: block"]');
        if(excludeMenu){
            allMenus = allMenus.not(excludeMenu);
        }

        allMenus.velocity(config.animationOutType, {
            duration: config.animationOutDuration
        });
    };

    /**
     * open menu handler
     * @param menuConfig
     * @param e
     * @param context
     */
    let openMenu = (menuConfig, e, context) => {
        let menuElement = $('#' + menuConfig.id);

        // close all other context menus
        closeMenus(menuElement);

        // remove menu list click event
        // -> required in case the close handler could not remove them properly
        // -> this happens if menu re-opens without closing (2x right click)
        menuElement.off('click.contextMenuSelect', 'li');

        // hide/activate/disable
        menuElement = prepareMenu(menuElement, menuConfig.hidden, menuConfig.active, menuConfig.disabled);

        let {left, openSubLeft} = getMenuLeftCoordinate(e, menuElement.width());
        let {top} = getMenuTopCoordinate(e, menuElement.height());

        menuElement.toggleClass(config.subMenuLeftClass, openSubLeft).css({
            position: 'absolute',
            left: left,
            top: top
        }).velocity(config.animationInType, {
            duration: config.animationInDuration,
            complete: function(){
                context = {
                    original: {
                        event: e,
                        context: context,
                    },
                    selectCallback: menuConfig.selectCallback
                };

                $(this).one('click.contextMenuSelect', 'li', context, selectHandler);
            }
        });
    };

    /**
     * menu item select handler
     * @param e
     */
    let selectHandler = e => {
        if(e.data.selectCallback){
            e.data.selectCallback(
                $(e.currentTarget).attr('data-action'),
                e.data.original.context.component,
                e.data.original.event
            );
        }
    };

    /**
     * default config (skeleton) for valid context menu configuration
     * @returns {{hidden: [], active: [], disabled: [], id: string, selectCallback: null}}
     */
    let defaultMenuOptionConfig = () => ({
        'id': '',
        'selectCallback': null,
        'hidden': [],
        'active': [],
        'disabled': []
    });

    return {
        config: config,
        defaultMenuOptionConfig: defaultMenuOptionConfig,
        renderMapContextMenu: renderMapContextMenu,
        renderConnectionContextMenu: renderConnectionContextMenu,
        renderEndpointContextMenu: renderEndpointContextMenu,
        renderSystemContextMenu: renderSystemContextMenu,
        openMenu: openMenu,
        closeMenus: closeMenus
    };
});