var RightClick = RightClick || {};

(function(window, $, exports, undefined) {
    'use strict';

    exports.appName = 'files_rightclick';
    exports.selectors = {
        containerId: 'rightClickMenus',
        detectorId: 'rightClickDetector',
        menuId: 'rightClickMenu',
        menuClass: 'rightClickMenu',
        subMenuClass: 'rightClickSubMenu',
        openedClass: 'rightClickOpened',
        arrowClass: 'rightClickArrow',
    };

    // Object where all options are listed for one (sub)menu
    exports.Options = function (options) {
        this.options = [];

        this.getIndexFromOptionName = function (name) {
            return this.getNbrOfOptions(); // TODO
        };

        // Add one or more options
        this.add = function (options, index) {
            if (!(typeof index === 'number'))
                index = this.getIndexFromOptionName(index);

            if (index === undefined)
                index = this.getNbrOfOptions();

            if (typeof options === 'string' || typeof options === 'number')
                options = new exports.Option(options);

            if (options instanceof exports.Option)
                this.options.splice(index, 0, options);
            else if (options !== undefined && Array.isArray(options)) {
                for (var name in options) {
                    var option = options[name];

                    if (typeof option !== 'function') {
                        if (typeof option === 'string' || typeof option === 'number')
                            option = new exports.Option(option);
                    }

                    if (option instanceof exports.Option)
                        this.options.splice(index, 0, option);
                }
            }

            return this;
        };

        this.prepend = function (options) {
            return this.add(options, 0);
        };

        this.append = function (options) {
            return this.add(options, this.getNbrOfOptions());
        };

        // Generate all html options
        this.generate = function () {
            var ul = $('<ul>');

            for (var name in this.options) {
                var li = this.options[name].generate();

                if (li) {
                    li.addClass('action-' + name);
                    ul.append(li);
                }
            }

            return ul;
        };

        this.getNbrOfOptions = function () {
            return this.options.length;
        };

        this.isDisabled = function () {
            for (var name in this.options) {
                if (!this.options[name].isDisabled())
                    return false;
            }

            return true;
        };

        this.isFirstDisabled = function () {
            if (this.getNbrOfOptions() === 0)
                return true;
            else
                return this.options[Object.keys(this.options)[0]].isDisabled();
        };

        this.add(options);
    };

    exports.Option = function (name, text, icon, onClick, subOptions) {
        this.name = name;
        this.text = text;
        this.icon = icon;
        this.onClick = onClick;
        this.subOptions = subOptions;
        var option = this;

        this.printIfAppEnabled = function (appName) {
            this.appName = appName;
            this.printIfNoApp = false;
        }

        this.enableIfAppEnabled = function (appName) {
            this.appName = appName;
            this.printIfNoApp = true;
        }

        this.generate = function () {
            var a = $('<a>', {
                'class': 'menu-option option-' + this.name.toLowerCase()
            }).css('width', '100%');
            var iconSpan = $('<span>', {
                'class': 'icon ' + this.icon
            });
            var textSpan = $('<span>', {
                'text': this.text,
            });

            if (this.appName && !this.printIfNoApp && !exports.isAppAvailable(this.appName))
                return;

            if (this.isDisabled()) {
                a.attr('disabled', true).css({
                    'cursor': 'default',
                    'background-color': '#AAA'
                });

                iconSpan.css('cursor', 'default');
                textSpan.css('cursor', 'default');
            }

            if (typeof this.onClick === 'string') {
                a.on('click', function (event) {
                    event.stopPropagation();
                    event.preventDefault();

                    var $temp = $("<input>");
                    $("body").append($temp);
                    $temp.val(option.onClick).select();
                    document.execCommand("copy");
                    $temp.remove();

                    var html = textSpan.html();
                    textSpan.html(t('files_rightclick', 'Copied !'));

                    setTimeout(function () {
                        textSpan.html(html);
                    }, 1000);
                });
            }
            else {
                a.on('click', function (event) {
                    event.stopPropagation();
                    event.preventDefault();

                    exports.closeAllMenus();

                    onClick(event, option);
                });
            }


            var li = $('<li>').append(a.append(iconSpan).append(textSpan));

            if (this.subOptions instanceof exports.Options && this.subOptions.getNbrOfOptions() > 0) {
                var sub = $('<a>').append($('<span>').text('▶')
                    .css('padding-right', '10px')).addClass(exports.selectors.arrowClass)
                    .attr('style', 'width: auto; padding-right: 0px !important');

                new exports.Menu(sub, this.subOptions, li).setAsSubMenu().setAlsoOnHover().setAlsoOnLeftClick();
                li.append(sub);
            }

            return li;
        };

        this.isDisabled = function () {
            if (this.appName && !exports.isAppAvailable(this.appName))
                return true;

            return this.onClick === undefined;
        };
    };

    exports.menus = [];
    exports.Menu = function (delimiter, options, context, onClose) {
        this.delimiter = $(delimiter);
        this.context = context;
        this.currentContext = undefined;
        this.options = options || new exports.Options();
        this.onClose = onClose;
        this.isSubMenu = false;

        if (delimiter === undefined)
            return undefined;

        // Allow onClick function to access to menu data
        var menu = this;

        this.setContext = function (context) {
            this.context = context;

            return this;
        };

        this.isOpened = function () {
            return this.element !== undefined;
        }

        var onClick = function (event, originalEvent) {
            event.stopPropagation();
            event.preventDefault();

            if (originalEvent) {
                event.clientX = originalEvent.clientX;
                event.clientY = originalEvent.clientY;
            }

            var delimiter = $(this);
            var context = menu.context;
            var options = menu.options;
            var params = menu.params;

            if (menu.isSubMenu) {
                if (!exports.closeAllSubMenus()) {
                    return !exports.clean();
                }
            }
            else if (!exports.closeAllMenus()) {
                return !exports.clean();
            }

            if (menu.isOpened()) {
                return !exports.clean();
            }

            exports.prepare();

            menu.attachedEvent = event;

            if (typeof context === "function")
                context = context(event);

            context = (context === undefined) ? delimiter : $(context[0]);
            menu.currentContext = context;

            if (typeof options === "function")
                options = options(event, context, delimiter);

            if (options.getNbrOfOptions() === 0) {
                return !exports.clean();
            }

            var className = exports.selectors.menuClass + ' bubble open';

            menu.element = $('<div>', menu.isSubMenu ? {
                'class': exports.selectord.subMenuClass +  ' ' + className
            } : {
                'id': exports.selectors.menuId,
                'class': className
            }).append(options.generate());

            menu.element.appendTo(exports.container);

            if (menu.isSubMenu) {
                var menuPosition = context.parents('.rightClick').first().position();
                var contextPosition = context.position();
                var top = menuPosition.top - contextPosition.top;
                var left = menuPosition.left + context.width() + 2;
            }
            else {
                var top = event.clientY - parseInt(menu.element.css("marginTop").replace('px', ''));
                var left = event.clientX - parseInt(menu.element.css("marginLeft").replace('px', ''));
            }

            var height = menu.element.outerHeight();
            var width = menu.element.outerWidth();

            if (left + width >= $(window).width()) {
                left -= width;
            }
            if (top + height >= $(window).height()) {
                top -= height;
            }

            if (top < 0) {
                top = 0;
            }
            if (left < 0) {
                left = 0;
            }

            menu.element.css({
                'top': top,
                'left': left,
                'right': 'auto',
            });

            var optionsDisabled = options.isDisabled();

            if (optionsDisabled)
                menu.element.css('background-color', '#AAA');

            menu.element.on('contextmenu', function () {
                return false;
            });
            menu.element.on('mouseleave', function (event) {
                if (menu.isOpenedOnHover)
                    menu.close();
            });

            return false;
        };

        this.close = function () {
            if (!this.isOpened())
                return true;

            if (this.element) {
                if (this.onClose) {
                    if (this.onClose(this.attachedEvent, this.currentContext, this.delimiter) === false)
                        return false;
                }

                this.element.remove();
                delete this.element;

                exports.clean();
            }

            return true;
        };

        this.setAlsoOnLeftClick = function () {
            this.delimiter.on('click', function (event) {
                if (menu.isOpened() && !menu.isOpenedOnHover) {
                    menu.close();

                    return false;
                }

                menu.isOpenedOnHover = false;
            }).on('click', onClick);

            return this;
        };

        this.setAlsoOnHover = function () {
            this.delimiter.on('mouseenter', function (event) {
                menu.isOpenedOnHover = true;
            }).on('mouseenter', onClick);

            return this;
        };

        this.setAsSubMenu = function (isSubMenu) {
            this.isSubMenu = isSubMenu || true;

            return this;
        };

        this.delimiter.contextmenu(onClick);
        exports.menus.push(this);
    };

    exports.closeAllMenus = function () {
        for (var key in exports.menus) {
            if (exports.menus.hasOwnProperty(key)) {
                if (exports.menus[key].close() === false)
                    return false;
            }
        }

        return true;
    };

    exports.closeAllSubMenus = function () {
        for (var key in exports.menus) {
            if (exports.menus.hasOwnProperty(key)) {
                if (exports.menus[key].isSubMenu) {
                    if (exports.menus[key].close() === false)
                        return false;
                }
            }
        }

        return true;
    };

    exports.isAMenuOpened = function () {
        for (var key = 0; key < exports.menus.length; key++) {
            if (exports.menus[key].isOpened()) {
                return true;
            }
        }

        return false;
    };

    exports.prepare = function () {
        if (!exports.isAMenuOpened()) {
            $(window).on('resize', exports.closeAllMenus);
            $('body').addClass(exports.selectors.openedClass);
        }

        $('#' + exports.selectors.detectorId).css('display', 'block');
    }

    exports.onKeyUp = function (event) {
        event = event || window.event;
        var isEscape = false;

        if ("key" in event) {
            isEscape = (event.key == "Escape" || event.key == "Esc");
        } else {
            isEscape = (event.keyCode === 27);
        }

        if (isEscape) {
            if (exports.isAMenuOpened()) {
                exports.closeAllMenus();

                event.stopPropagation();
            }
        }
    };

    exports.clean = function () {
        if (!exports.isAMenuOpened()) {
            $(window).off('resize', exports.closeAllMenus);
            $('body').removeClass(exports.selectors.openedClass);
            $('#' + exports.selectors.detectorId).css('display', 'none');

            return true;
        }

        return false;
    };

    exports.propagateRightClick = function (event) {
        exports.closeAllMenus();
        event.preventDefault();
        event.stopPropagation();

        $(document.elementFromPoint(event.clientX, event.clientY)).trigger('contextmenu', event);
    }

    exports.container = $('<div id="' + exports.selectors.containerId + '"></div>').appendTo('body');
    exports.detector = $('<div id="' + exports.selectors.detectorId + '"></div>').appendTo('body');

    exports.detector.on('click resize', exports.closeAllMenus);
    exports.detector.on('contextmenu', exports.propagateRightClick);

    document.onkeyup = exports.onKeyUp;
})(window, jQuery, RightClick);
