/*globals define*/
/*jslint nomen: true, regexp: true*/

define('de_epages/shop/linkpicker', [
    'jquery',
    'backbone',
    'ep',
    'util/storage',
    'de_epages/shop/linkpicker/linktextview',
    'de_epages/shop/linkpicker/pagetreeview',
    'de_epages/shop/linkpicker/filemanagerview',
    'de_epages/shop/linkpicker/additionalpagesview',
    'de_epages/shop/linkpicker/externalurlview',
    'de_epages/shop/linkpicker/anchorview',
    '$tmpl!de_epages/shop/linkpicker',
    '$dict!./dictionary',
    'jquery/ui/tabs',
    'ep/ui/dialog'
], function ($, Backbone, ep, storage, LinktextView, PagetreeView, FilemanagerView, AdditionalpagesView, ExternalView, AnchorView, template, dict) {
    'use strict';

    var View = Backbone.View.extend({

        tagName: 'div',
        template: template({}).dictParse(dict, true),
        callback: $.noop,
        activeTab: 0,

        /*
         * Initialize child views and set listeners
         */
        initialize: function () {

            // creating subview instances
            this.linkTextView = new LinktextView();
            this.filemanagerView = new FilemanagerView();
            this.additionalPagesView = new AdditionalpagesView();
            this.externalUrlView = new ExternalView();
            this.pageTreeView = new PagetreeView();
            this.anchorView = new AnchorView();

            // listen to events the subviews are publishing and call appropriate functions
            this.listenTo(this.linkTextView, 'linktextchanged', function (_text) {
                this.is_linkTextChanged = true;
                this._setLinkText(_text);
            });
            this.listenTo(this.linkTextView, 'targetoptionchanged', this._setLinkTarget);

            this.listenTo(this.anchorView, 'anchorselected', function (_url) {
                this._setLinkUrl(_url);
                this.linkType = 'anchor';
                this._clearViewDataExceptFor(this.linkType);
            });

            this.listenTo(this.additionalPagesView, 'linkpicked', function (_text, _url) {
                this._setLinkText(_text);
                this._setLinkUrl(this._getCorrectUrl(_url));
                this.linkType = 'additional';
                this._clearViewDataExceptFor(this.linkType);
            });

            this.listenTo(this.pageTreeView, 'linkpicked', function (_text, _url) {
                this._setLinkText(_text);
                this._setLinkUrl(this._getCorrectUrl(_url));
                this.linkType = 'tree';
                this._clearViewDataExceptFor(this.linkType);
            });

            this.listenTo(this.filemanagerView, 'linkpicked', function (_text, _url, _preview) {
                this._setLinkText(_text);
                this._setLinkUrl(this._getCorrectUrl(_url));
                this.linkType = 'filemanager';
                this._clearViewDataExceptFor(this.linkType);
            });

            this.listenTo(this.externalUrlView, 'linkurlchanged', function (_url) {
                this._setLinkUrl(this._getCorrectUrl(_url));
                this.linkType = 'external';
                this._clearViewDataExceptFor(this.linkType);
            });

            // render the view for additional pages (radios) as soon as the ajax request is done (datafetched triggered)
            this.listenTo(this.additionalPagesView, 'datafetched', function () {
                this.additionalPagesView.render(this.linkUrl.replace(/.*\?/g,'?'));
            });
        },

        /**
         * Opening the linkpicker dialog or creating one if it doesn't exist
         * Can be called right from the required linkpicker instance
         *
         * @param {object}  _options
         * @param {Boolean} _options.use_absolute        Initialize linkpicker to return absolute urls
         * @param {Boolean} _options.use_ssl             Initialize linkpicker to return https urls
         * @param {String}  _options.linkText            Text that is displayed as the link's text
         * @param {String}  _options.linkUrl             Url the link refers to,
         * @param {Boolean} _options.is_linkTargetBlank  Whether link should be opened in new window or not
         * @param {String}  _options.linkType            Type of the link. Can either be 'tree', 'additional', 'filemanager' or 'external'
         *                                               should be read from data-link-type attribute
         */
        open: function (_options) {

            // initializing linkpicker options
            this.use_absoluteUrl = _options.use_absolute;
            this.use_ssl = _options.use_ssl;
            this.anchors = _options.anchors || [];

            // getting elements out of the template for further access (e.g. 'dialog')
            $.extend(this, $.tmplItem(this.template).elements);

            var linkpicker = this,
                callback = _options.callback || $.noop,

                // initializing dialog options
                dialogOptions = _options.dialog || {

                    title: dict.translate('EditLink'),
                    width: 920,
                    height: 563,
                    draggable: false,
                    modal: true,
                    autoOpen: false,
                    buttons: [{
                        text: dict.translate('Apply'),
                        click: function () {
                            $(this).uiDialog('close');
                            $(this).uiDialog('destroy');
                            storage.localStorage('linkpickerLastActiveTab', linkpicker._getActiveTabAndSetOptions(linkpicker.linkType));
                            callback(linkpicker.linkText, linkpicker.linkUrl, linkpicker.is_linkTargetBlank, linkpicker.linkType, linkpicker.pageTreeId);
                        }
                    }, {
                        text: dict.translate('Cancel'),
                        click: function () {
                            $(this).uiDialog('close');
                        }
                    }]
                },

                dialog = this.dialog;


            // Setting anchors, link text and url
            this.linkText = _options.linkText;
            this.linkUrl = _options.linkUrl;
            this.anchorView.setAnchors(this.linkUrl, this.anchors);

            // (Re-)creating the dialog
            this.dialog.uiDialog(dialogOptions);
            // omitting template's and backbone's div and appending straight to the dialog
            this.render().$el.children().children().appendTo(this.dialog);
            this.dialog.uiDialog('open');

            // setting link target
            this._setLinkTarget(_options.is_linkTargetBlank);

            //setting members and view options (in case the picker is opened with predefined values)
            if (_options.linkText) {
                this.linkTextView.setLinkText(_options.linkText);
                this._setLinkUrl(_options.linkUrl);
                this.is_linkTextChanged = true;
                this.linkType = _options.linkType;
            } else {
                this.is_linkTextChanged = false;
                this._setLinkText('');
                this._setLinkUrl('');
                // clear all view specific data
                this.pageTreeView.clearLinkData();
                this.additionalPagesView.clearLinkData();
                this.externalUrlView.clearLinkData();
                this.anchorView.clearLinkData();
            }

            // clear all other tabs
            this._clearViewDataExceptFor(this.linkType);

            // converting template node to tabs and selecting last open tab
            this.tabpanel.tabs({
                active: this._getActiveTabAndSetOptions(this.linkType)
            });

            return this;
        },

        /**
         * Closing the dialog
         */
        close: function () {
            if (this.dialog.data('uiUiDialog')) {
                this.dialog.uiDialog('close');
            }
        },

        /**
         * Renders the main view
         * @return {Object} Backbone view
         */
        render: function () {
            // appending main template
            this.$el.append(this.template);

            // rendering view for linktext
            // nice to know: when omitting backbone's root div, all events regegistered are also omitted!
            this.linktext.append(this.linkTextView.render().$el);
            this.anchor.append(this.anchorView.render(this.linkUrl).$el);

            this.pagetree.append(this.pageTreeView.render().el);
            this.filemanager.append(this.filemanagerView.render().el);
            // the view is rendered as soon as getAdditionalPages() has returned data
            this.additionalPagesView.getAdditionalPages();
            this.additionalpages.append(this.additionalPagesView.el);

            this.externalurl.append(this.externalUrlView.render().el);

            return this;
        },

        /*
         * Determine whether the given protocol is correct depending on the initialization options (use_ssl)
         * @param   {String} _protocol Protocol to be checked
         * @return  {String}           Correct protocol based on initialization options (ssl)
         * @private
         */
        _getCorrectProtocol: function (_protocol) {

            // correct the protocol if we have an internal link, ignore for externals
            if (_protocol && this.linkType !== 'external') {
                if (this.use_ssl && _protocol === 'http') {
                    _protocol = 'https';
                } else if (!this.use_ssl && _protocol === 'https') {
                    _protocol = 'http';
                } else {
                    // everything is fine, return the absolute url
                    return _protocol;
                }
            }

            // url is relative, no need to touch the protocol (whyever someone called for getting the correct protocol on a realtive url)
            return _protocol;

        },

        /*
         * Returns absolute or relative url depending on given url and initialization options of the linkpicker (use_absoluteUrl)
         * @param   {String} _url Url to be checked
         * @return  {String}      link url based on initialization options (absoluteUrl)
         * @private
         */
        _getCorrectUrl: function (_url) {

            var relativeUrlExpr = /^(\/|\?[\w\W]*)/i,
                absoluteUrlExpr = /^(http|https):\/\/([\w\W]*)/i,
                splitUrl = absoluteUrlExpr.exec(_url),
                sfUrl = ep.config.storeFrontUrl,
                url = _url,
                protocol;

            if (_url) {
                if (splitUrl) {
                    protocol = splitUrl[1];
                    url = splitUrl[2];
                }

                if (this.use_absoluteUrl) {
                    if (protocol) {
                        // we got an absolute url, return url with correct protocol
                        url = (this._getCorrectProtocol(protocol) + '://' + url);
                    } else if (this.linkType !== 'external' || (this.linkType === 'external' && _url.match(relativeUrlExpr))) {
                        // we got back a relative url or user entered correct relative url, convert to absolute and return url with correct protocol
                        if (_url.indexOf('/') === 0) {
                            // looks like we have a file
                            url = ep.config.protocolAndServer.replace(/^(http|https)/i, this.use_ssl ? 'https' : 'http') + _url;
                        } else {
                            url = sfUrl.replace(/^(http|https)/i, this.use_ssl ? 'https' : 'http') + _url;
                        }
                    } else {
                        // user probably forgot to specify the protocol but entered absolute url, add protocol (assume http)
                        url = 'http://' + _url;
                    }
                } else {
                    if (protocol && this.linkType !== 'external') {
                        // we got back an absolute link, convert to relative
                        url = _url.replace(/^.+\?/, '?');
                    } else if (!protocol && _url.indexOf('/') !== 0 && !_url.match(relativeUrlExpr)) {
                        // no file and no relative url, probably user input without protocol, assume http
                        url = 'http://' + _url;
                    } else {
                        url = _url;
                    }
                }
            }
            return url;
        },

        /*
         * Gets the active tab for rendering and sets options options based on link type
         * @param   {String} _linkType Type of the link that is currently edited.
         *                             Can be either 'filemanager', 'additional', 'external' or 'tree'
         * @return  {Integer}          active index
         * @private
         */
        _getActiveTabAndSetOptions: function (_linkType) {

            switch (_linkType) {
            case 'filemanager':
                this.filemanagerView.setPreviewImage(this.linkUrl);
                return 1;
            case 'additional':
                this.additionalPagesView.setCheckedRadio(this.linkUrl);
                return 2;
            case 'external':
                this.externalUrlView.setUrl(this.linkUrl);
                return 3;
            case 'anchor':
                return 4;
            case 'tree':
                return 0;
            default:
                // if link was created before new linkpicker implementation (url is given), return external tab to show url
                var tab;
                if (this.linkUrl) {
                    tab = 3;
                    this.externalUrlView.setUrl(this.linkUrl);
                } else {
                    // return last active tab
                    tab = storage.localStorage('linkpickerLastActiveTab') || 0;
                }

                return tab;
            }
        },

        /*
         * Clearing all view specific data like filemanager preview, selected radio options or entered text
         * except for the specified view/link type (used when making changes to other tabs)
         * @param  {String} _givenLinkType [LinkType whose view data should NOT be cleared Can be either 'filemanager', 'additional', 'external', 'anchor' or 'tree']
         * @private
         */
        _clearViewDataExceptFor: function (_givenLinkType) {

            switch (_givenLinkType) {
            case 'filemanager':
                this.pageTreeView.clearLinkData();
                this.additionalPagesView.clearLinkData();
                this.externalUrlView.clearLinkData();
                this.anchorView.clearLinkData();
                break;
            case 'additional':
                this.filemanagerView.clearLinkData();
                this.pageTreeView.clearLinkData();
                this.externalUrlView.clearLinkData();
                this.anchorView.clearLinkData();
                break;
            case 'external':
                this.filemanagerView.clearLinkData();
                this.additionalPagesView.clearLinkData();
                this.pageTreeView.clearLinkData();
                this.anchorView.clearLinkData();
                break;
            case 'anchor':
                this.filemanagerView.clearLinkData();
                this.additionalPagesView.clearLinkData();
                this.pageTreeView.clearLinkData();
                this.externalUrlView.clearLinkData();
                break;
            default:
                //tree
                this.filemanagerView.clearLinkData();
                this.additionalPagesView.clearLinkData();
                this.externalUrlView.clearLinkData();
                this.anchorView.clearLinkData();
            }
        },

        /*
         * Sets the text of the chosen link
         * @param {String} _text title to be set
         * @private
         */
        _setLinkText: function (_text) {

            var text = this.linkTextView.getLinkText();

            // input is considered not changed when its value is empty
            if (this.is_linkTextChanged && text !== '') {
                this.linkText = text;
            } else {
                this.linkTextView.setLinkText(_text);
                this.linkText = _text;
                this.is_linkTextChanged = false;
            }
        },

        /*
         * Sets the url and title attribute of the chosen link
         * @param {String} _url url to be set
         */
        _setLinkUrl: function (_url) {
            this.linkUrl = _url;
            this.linkTextView.setLinkUrl(_url);
        },

        /*
         * Sets the target of the link (open in new or same window)
         * @param   {Boolean} _is_targetBlank Whether link should be opened in new window
         * @private
         */
        _setLinkTarget: function (_is_targetBlank) {
            this.is_linkTargetBlank = _is_targetBlank;
            this.linkTextView.setLinkTarget(_is_targetBlank);
        }
    });

    return new View();
});