(function($) {
// CMS.$ will be passed for $
$(document).ready(function () {

    CKEDITOR.plugins.add('cmsplugins', {

        // Register the icons. They must match command names.
        icons: 'cmsplugins',

        // The plugin initialization logic goes inside this method.
        init: function(editor) {
            var that = this;

            this.options = CMS.CKEditor.options.settings;
            this.editor = editor;

            /**
             * populated with _fresh_ child plugins
             */
            this.child_plugins = [];
            this.setupCancelCleanupCallback(this.options);

            // don't do anything if there are no plugins defined
            if(this.options === undefined || this.options.plugins === undefined) return false;

            this.setupDialog();

            // add the button
            this.editor.ui.add('cmsplugins', CKEDITOR.UI_PANELBUTTON, {
                'toolbar': 'cms,0',
                'label': this.options.lang.toolbar,
                'title': this.options.lang.toolbar,
                'className' : 'cke_panelbutton__cmsplugins',
                'modes': { wysiwyg:1 },
                'editorFocus': 0,

                'panel': {
                    'css': [CKEDITOR.skin.getPath('editor')].concat(that.editor.config.contentsCss),
                    'attributes': { role: 'cmsplugins', 'aria-label': this.options.lang.aria }
                },

                // this is called when creating the dropdown list
                'onBlock': function (panel, block) {
                    block.element.setHtml(that.editor.plugins.cmsplugins.setupDropdown());

                    var anchors = $(block.element.$).find('.cke_panel_listItem a');
                        anchors.bind('click', function (e) {
                            e.preventDefault();

                            that.addPlugin($(this), panel);
                        });
                }
            });

            // handle edit event via context menu
            if(this.editor.contextMenu) {
                this.setupContextMenu();
                this.editor.addCommand('cmspluginsEdit', {
                    exec: function () {
                        var selection = that.editor.getSelection();
                        var element = selection.getSelectedElement() || selection.getCommonAncestor().getAscendant('a', true);
                        that.editPlugin(element);
                    }
                });
            }

            // handle edit event on double click
            // if event is a jQuery event (touchend), than we mutate
            // event a bit so we make the payload similar to what ckeditor.event produces
            var handleEdit = function(event) {
                if (event.type === 'touchend' || event.type === 'click') {
                    var element = event.currentTarget;
                    event.data = event.data ||  {};
                    that.editor.getSelection().fake(new CKEDITOR.dom.element(element));
                } else {
                    // heavily relies on the fact that double click
                    // also selects an element
                    var selection = that.editor.getSelection();
                    var element = selection.getSelectedElement() || selection.getCommonAncestor().getAscendant('a', true);
                }
                if(element && element.getAttribute('id').indexOf('plugin_obj_') === 0) {
                    event.data.dialog = '';
                    that.editPlugin(element);
                }
            }
            this.editor.on('doubleclick', handleEdit);
            this.editor.on('instanceReady', function () {
                CMS.$('[id*="plugin_obj_"]', CMS.$('iframe.cke_wysiwyg_frame')[0]
                    .contentWindow.document.documentElement).on('click touchend', handleEdit);
            });

            // setup CKEDITOR.htmlDataProcessor
            this.setupDataProcessor();
        },

        setupDialog: function () {
            var that = this;
            var definition = function () { return {
                'title': '',
                'minWidth': 600,
                'minHeight': 200,
                'contents': [{
                    'elements': [{ type: 'html', html: '<iframe style="position:static; width:100%; height:100%; border:none;" />' }]
                }],
                'onOk': function () {
                    var iframe = $(CKEDITOR.dialog.getCurrent().parts.contents.$).find('iframe').contents();
                        iframe.find('form').submit();

                    // catch the reload event and reattach
                    var reload = CMS.API.Helpers.reloadBrowser;

                    CMS.API.Helpers.reloadBrowser = function() {
                        CKEDITOR.dialog.getCurrent().hide();

                        that.insertPlugin(CMS.API.Helpers.dataBridge);

                        CMS.API.Helpers.reloadBrowser = reload;
                        return false;
                    };
                    return false;
                }
            }};

            // set default definition and open dialog
            CKEDITOR.dialog.add('cmspluginsDialog', definition);
        },

        setupDropdown: function () {
            var tpl = '<div class="cke_panel_block">';

            // loop through the groups
            $.each(this.options.plugins, function (i, group) {
                // add template
                tpl += '<h1 class="cke_panel_grouptitle">' + group.group + '</h1>';
                tpl += '<ul role="presentation" class="cke_panel_list">';
                // loop through the plugins
                $.each(group.items, function (ii, item) {
                    tpl += '<li class="cke_panel_listItem"><a href="#" rel="' + item.type + '">' + item.title + '</a></li>';
                });
                tpl += '</ul>';
            });

            tpl += '</div>';

            return tpl;
        },

        setupContextMenu: function () {
            this.editor.addMenuGroup('cmspluginsGroup');
            this.editor.addMenuItem('cmspluginsItem', {
                label: this.options.lang.edit,
                icon: this.path + 'icons/cmsplugins.png',
                command: 'cmspluginsEdit',
                group: 'cmspluginsGroup'
            });

            this.editor.removeMenuItem('image');

            this.editor.contextMenu.addListener(function(element) {
                if (element.$.id.indexOf('plugin_obj_') === 0) {
                    return { cmspluginsItem: CKEDITOR.TRISTATE_OFF };
                }
            });
        },

        editPlugin: function (element) {
            var id = element.getAttribute('id').replace('plugin_obj_', '');
            this.editor.openDialog('cmspluginsDialog');
            var body = CMS.$(document);

            // now tweak in dynamic stuff
            var dialog = CKEDITOR.dialog.getCurrent();
            dialog.resize(body.width() * 0.8, body.height() * 0.7);
            $(dialog.getElement().$).addClass('cms-ckeditor-dialog');
            $(dialog.parts.title.$).text(this.options.lang.edit);
            $(dialog.parts.contents.$).find('iframe').attr('src', '../' + id + '/?_popup=1&no_preview')
                .bind('load', function () {
                    $(this).contents().find('.submit-row').hide().end()
                        .find('#container').css('min-width', 0).css('padding', 0);
                });
        },

        addPlugin: function (item, panel) {
            var that = this;

            // hide the panel
            panel.hide();

            // lets figure out how to write something to the editor
            this.editor.focus();
            this.editor.fire('saveSnapshot');

            // gather data
            var data = {
                'placeholder_id': this.options.placeholder_id,
                'plugin_type': item.attr('rel'),
                'plugin_parent': this.options.plugin_id,
                'plugin_language':  this.options.plugin_language
            };

            that.addPluginDialog(item, data);
        },

        addPluginDialog: function (item, data) {
            var body = CMS.$(document);
            // open the dialog
            var selected_text = this.editor.getSelection().getSelectedText();
            this.editor.openDialog('cmspluginsDialog');

            // now tweak in dynamic stuff
            var dialog = CKEDITOR.dialog.getCurrent();
            dialog.resize(body.width() * 0.8, body.height() * 0.7);
            $(dialog.getElement().$).addClass('cms-ckeditor-dialog');
            $(dialog.parts.title.$).text(this.options.lang.add);
            $(dialog.parts.contents.$).find('iframe').attr('src', this.options.add_plugin_url + '?' + $.param(data))
                .bind('load', function () {
                    $(this).contents().find('.submit-row').hide().end()
                    .find('#container').css('min-width', 0).css('padding', 0)
                    .find('#id_name').val(selected_text);
                });
        },

        // on ajax receivement from server, build <a> or <img> tag dependig in the plugin type
        insertPlugin: function (data) {
            var that = this;
            var element, attrs = { id: 'plugin_obj_' + data.plugin_id };
            if (data.plugin_type === this.options.lang.link) {
                element = new CKEDITOR.dom.element('a', this.editor.document);
                $.extend(attrs, {
                    'href': '#',
                    'data-cmsplugin_title': data.plugin_desc,
                    'data-cmsplugin_alt': data.plugin_type,
                    'data-cmsplugin_src': data.plugin_icon
                });
                element.setText(data.plugin_name);
            } else {
                element = new CKEDITOR.dom.element('img', this.editor.document);
                $.extend(attrs, {
                    'title': data.plugin_desc,
                    'alt': data.plugin_type,
                    'src': data.plugin_icon
                });
            }
            element.setAttributes(attrs);

            // in case it's a fresh text plugin children don't have to be
            // deleted separately
            if (!this.options.delete_on_cancel) {
                this.child_plugins.push(data.plugin_id);
            }
            this.editor.insertElement(element);
        },

        /**
         * Sets up cleanup requests. If the plugin itself or child plugin was created and then
         * creation was cancelled - we need to clean up created plugins.
         *
         * @method setupCancelCleanupCallback
         * @public
         * @param {Object} data plugin data
         */
        setupCancelCleanupCallback: function setupCancelCleanupCallback (data) {
            if (!window.parent || !window.parent.CMS || !window.parent.CMS.API || !window.parent.CMS.API.Helpers) {
                return;
            }
            var that = this;
            var CMS = window.parent.CMS;
            var cancelModalCallback = function cancelModalCallback(e, opts) {
                if (!that.options.delete_on_cancel && !that.child_plugins.length) {
                    return;
                }
                e.preventDefault();
                CMS.API.Toolbar.showLoader();
                var data = {
                    token: that.options.cancel_plugin_token
                };
                if (!that.options.delete_on_cancel) {
                    data.child_plugins = that.child_plugins;
                }
                $.ajax({
                    method: 'POST',
                    url: that.options.cancel_plugin_url,
                    data: data,
                    // use 'child_plugins' instead of default 'child_plugins[]'
                    traditional: true
                }).done(function (res) {
                    CMS.API.Helpers.removeEventListener('modal-close.text-plugin-' + that.options.plugin_id);
                    opts.instance.close();
                }).fail(function (res) {
                    CMS.API.Messages.open({
                        message: res.responseText + ' | ' + res.status + ' ' + res.statusText,
                        delay: 0,
                        error: true
                    });
                });
            };
            CMS.API.Helpers.addEventListener('modal-close.text-plugin-' + that.options.plugin_id, cancelModalCallback);
        },

        setupDataProcessor: function () {
            var link_name = this.options.lang.link;
            var link_pattern = new RegExp("^"+ link_name +"\\s-\\s(.+)$");

            this.editor.dataProcessor.dataFilter.addRules({
                elements: {
                    // on load from server replace <img> tag by <a> in order to display a real link
                    img: function(element) {
                        var new_element, matches;
                        if (element.attributes.id && element.attributes.alt
                          && element.attributes.alt === link_name
                          && element.attributes.id.indexOf('plugin_obj_') === 0) {
                            matches = link_pattern.exec(element.attributes.title);
                            new_element = new CKEDITOR.htmlParser.element('a', {
                                'href': '#',
                                'id': element.attributes.id,
                                'data-cmsplugin_title': element.attributes.title,
                                'data-cmsplugin_src': element.attributes.src,
                                'data-cmsplugin_alt': element.attributes.alt
                            });
                            if (matches) {
                                new_element.add(new CKEDITOR.htmlParser.text(matches[1]));
                            }
                            return new_element;
                        }
                    }
                }
            });

            this.editor.dataProcessor.htmlFilter.addRules({
                elements: {
                    // on post to server replace <a> tag by <img> in order keep plugin format consistent
                    a: function(element) {
                        var new_element;
                        if (element.attributes.id && element.attributes.id.indexOf('plugin_obj_') === 0) {
                            new_element = new CKEDITOR.htmlParser.element('img', {
                                id: element.attributes.id,
                                src: element.attributes['data-cmsplugin_src'],
                                title: element.attributes['data-cmsplugin_title'],
                                alt: element.attributes['data-cmsplugin_alt']
                            });
                            return new_element;
                        }
                    }
                }
            });
        }

    });

});
})(CMS.$);