/*globals define, require*/
/*jslint indent:4, nomen:true*/

/**
 * @class de_epages.presentation.tray.mainview
 * @author Copyright 2006-2013, epages GmbH, All Rights Reserved
 *
 * The tray's main view for use without a dialog
 *
 * ### Example
 *
 *     $('.ep-tray').uiTray({
 *         label: 'Add Products',
 *         smartsearch: 'JSONSmartSearchProductAlias',
 *         tabs: {
 *             products: {
 *                 id: #Shop.ProductFolder.ID
 *                 action: 'JSONSearchProductsToInsert',
 *                 additionalContent: '<a href="#">Additional content</a>'
 *             }
 *         }
 *     });
 *
 * @uses jQuery
 * @uses jQuery.ui.tabs
 * @uses Backbone
 *
 * @return {Object} Mainview
 */

define('de_epages/presentation/tray/main-view', [
    'jquery',
    'backbone',
    'util/storage',
    './tray-collection',
    './content-view',
    './selected-view',
    './tray-view',
    '$tmpl!./main-view',
    '$dict!../dictionary',

    'jquery/ui/tabs'
], function ($, Backbone, storage, TrayCollection, ContentView, SelectedView, TrayView, template, dict) {
    'use strict';

    /**
     * Options to pass to the main view
     *
     * @method constructor
     * @param {Object}    options
     * @param {Boolean}   [options.useTray=false] Whether an explicit tray tab should be displayed or not
     * @param {Object}    [options.tabs=undefined] Key-value-pairs of tab name and corresponding view action
     */
    var translationMap = {
        'products': 'Products',
        'categories': 'Categories',
        'shippingMethods': 'ShippingMethods',
        'paymentMethods': 'PaymentMethods',
        'customers': 'Customers',
        'users': 'Users',
        'tray': 'Tray'
    },
        viewOptions = {
            useTray: false,
            tabs: undefined
        };


    return Backbone.View.extend({
        tagname: 'div',
        template: template,
        collection: new TrayCollection(),
        rememberSelection: false,
        storageData: [],

        /**
         * Initialize options and prepare data to render tabs afterwards
         *
         * @since 6.17.0
         */
        initialize: function (options) {
            this.options = options;

            var self = this,
                o = $.extend(true, {}, viewOptions, self.options),
                assignedCategories = [];

            // we have do define them here otherwise it will be on the prototype
            // and we get a problem with different instances of the view
            self.tabData = [];
            self.views = {};
            self.activeView = {};
            self.activeAlias = undefined;
            self.additionalContent = {};

            $.each(o.tabs, function (key, value) {
                self.tabData.push({
                    alias: key,
                    id: value.id,
                    name: dict.translate(translationMap[key])
                });

                // if preassigned categories exist from setup.js format them to get them pushed into the collection to show them as selected
                if (options.savedCategoriesExist) {
                    assignedCategories.length = 0;

                    options.assignedCategories.forEach(function (elem, index) {
                        assignedCategories.push($.extend(elem, {
                            "ObjectID": parseInt(elem.CategoryID),
                            "NameOrAlias": elem.CategoryName,
                            "isHighlighted": 1,
                            "type": key,
                            "Alias": ""
                        }));
                    });
                    self.collection.add(assignedCategories);
                } else {
                    // loop through lS objects and try to find at least one saved selection (saved key is defined by searchActions)
                    self.collection.add(storage.localStorage('epObjectFinder.' + key + 'Selection'));
                }
            });

            self.tabData.hideTabBar = options.hideTabBar ? true : false;
            self.tabData.unity = options.unity ? true : false;

            // Found something? Then check the box!
            if (self.collection.length > 0 && options.savedCategoriesExist === undefined) {
                self.rememberSelection = true;
            }

            // <LEGACY>
//#JSCOVERAGE_IF false
            // tray tab - marked for removal
            // Kill this push to stop the tray from appearing
            if (o.trayAction) {
                self.tabData.push({
                    alias: 'tray',
                    name: dict.translate('Tray')
                });
            }
//#JSCOVERAGE_ENDIF
            // </LEGACY>
            if (o.savedCategoriesExist === undefined) {
                self.tabData.push({
                    alias: 'selected',
                    name: dict.translate('SelectedElements')
                });
            }

            self.collection.on('add remove', $.proxy(self.updateSelectedElements, self));
        },

        /**
         * Render tabs according to set options
         *
         * @since 6.17.0
         * @chainable
         * @return {Object} Backbone.View
         */
        render: function () {
            var self = this,
                o = self.options,
                renderedTemplate = self.template({
                    data: self.tabData,
                    cid: self.cid,
                    initialNumberOfElements: self.collection.length
                }),
                alias = self.tabData[0].alias,
                id = self.tabData[0].id;

            self.$el.append(renderedTemplate);
            $.extend(self, $.tmplItem(renderedTemplate).elements);

            self.tabNode.tabs({
                beforeActivate: function (event, ui) {
                    var tab = ui.newTab.children(':first'),
                        id = tab.data('id');

                    self.activeAlias = tab.data('alias');

                    if (self.activeAlias === 'selected') {
                        self.views.selected = {
                            type: 'rootview',
                            instance: new SelectedView({
                                collection: self.collection
                            })
                        };

                        // update flag if someone hits the checkbox
                        self.listenTo(self.views.selected.instance, 'rememberSelectionChanged', function (_rememberSelection) {
                            self.rememberSelection = _rememberSelection;
                        });

                        self.selected.empty().html(self.views.selected.instance.render().el);

                        if (self.rememberSelection && self.collection.length > 0) {
                            self.views.selected.instance.rememberSelection.prop('checked', true);
                        }

                    } else if (self.activeAlias === 'tray') {
                        // <LEGACY>
//#JSCOVERAGE_IF false
                        // tray tab - marked for removal
                        self.views.tray = {
                            type: 'rootview',
                            instance: new TrayView()
                        };

                        // already rendered the view?
                        if (!self.tray.html()) {
                            self.tray.html(self.views.tray.instance.render().el);
                        }
//#JSCOVERAGE_ENDIF
                        // </LEGACY>
                    } else {
                        self.setTabContent(id, self.activeAlias);
                    }
                }
            });

            self.activeAlias = alias;
            self.setTabContent(id, alias, 'rootview');

            if (o.afterRender) {
                o.afterRender(this);
            }

            return self;
        },

        /**
         * Create an instance of a subview if none exists and render it into the corresponding tab content area or get a chached one
         *
         * @since  6.17.0
         * @param  {String} alias The alias of the tab which should be rendered
         * @return {Object} Backbone.View
         */
        setTabContent: function (identifier, context) {
            var self = this,
                o = self.options;

            if (identifier && context && !self.views[identifier]) {
                // hide scrollbars in tab content
                self[context].css('overflow', 'hidden');

                self.createContent(identifier, context, 'rootview', o.searchString, o.tabs[context].additionalContent);
                self.collection.each(function (item) {
                    self.$('input[value=' + item.get('ObjectID') + ']').prop('checked', true);
                });

                self[context].html(self.views[identifier].instance.render().el);
                self.activeView[context] = self.views[identifier];
            }

            return self;
        },

        /**
         * Sets the content of the specified tab
         *
         * @since 6.17.0
         * @param  {mixed} identifier String or id that identifies the view
         */
        setSubContent: function (_identifier, _context) {
            var self = this,
                o = self.options,
                context = self.activeView[self.activeAlias].instance.options.context;

            self.activeView[self.activeAlias].instance.$el.detach();

            if (!self.views[_identifier]) {
                // create new view and render it to the DOM
                self.createContent(_identifier, context, 'subview', o.searchString, self.activeView[self.activeAlias].instance.options.additionalContent);
                self[context].html(self.views[_identifier].instance.render().el);
            } else {
                // take the already rendered view, mount it and clear the search field
                self[context].html(self.views[_identifier].instance.el);
                self.views[_identifier].instance.resetSearchField();
            }

            if (self.additionalContent[context]) {
                $.each(self.additionalContent[context], function (key, val) {
                    var node = self.views[_identifier].instance.$('input[name=' + key + ']');
                    if (val) {
                        node
                            .prop('checked', true)
                            .addClass('ui-changed');
                    } else {
                        node
                            .removeAttr('checked')
                            .removeClass('ui-changed');
                    }
                });
            }

            self.activeView[context] = self.views[_identifier];
        },

        /**
         * Creates a new view with given name and context
         *
         * @since 6.17.0
         * @param  {String} identifier  String or id that identifies the view
         * @param  {String} context     Context that binds the view to a specific tab
         */
        createContent: function (identifier, context, viewType, filter, additionalContent) {
            var self = this,
                o = self.options;

            self.views[identifier] = {
                type: viewType,
                instance: new ContentView({
                    context: context,
                    collection: self.collection,
                    parentObjectId: viewType === 'subview' ? identifier : undefined,
                    searchAction: o.tabs[context].action,
                    searchOptions: o.tabs[context].searchOptions,
                    searchString: filter,
                    additionalContent: additionalContent,
                    exclude: o.tabs[context].exclude,
                    isUnity: (self.options.isUnity !== undefined && self.options.isUnity) ? self.options.isUnity : undefined
                })
            };

            self.listenTo(self.views[identifier].instance, 'setAdditionalContentOptions', function (additionalContent) {
                self.additionalContent[self.views[identifier].instance.context] = additionalContent;
            });
            self.listenTo(self.views[identifier].instance, 'changecontent', self.setSubContent);
            self.listenTo(self.views[identifier].instance, 'search', self.showSearchResults);
            self.listenTo(self.views[identifier].instance, 'change:requiredHeight', function (h) {
                self.trigger('change:requiredHeight', h);
            });
        },

        /**
         * Show results of a search in an extra view that cannot be cached
         *
         * @since 6.17.0
         * @param  {String} searchString String by which the results are filtered
         */
        showSearchResults: function (searchString) {
            this.createContent(
                'search',
                this.activeAlias,
                'searchview',
                searchString,
                this.options.tabs[this.activeAlias].additionalContent
            );

            this.activeView[this.activeAlias].instance.$el.detach();
            this[this.activeAlias].html(this.views.search.instance.render().el);
        },

        /**
         * Update elements number on the 'selected' tab
         *
         * @since 6.17.0
         */
        updateSelectedElements: function () {
            // leave method if Unity category handling is needed
            if (this.options.savedCategoriesExist !== undefined) {
                return;
            }

            if (this.collection.length > 0) {
                this.numberOfElements.html(' (' + this.collection.length + ')');
            } else {
                this.numberOfElements.html('');
            }
        },

        /**
         * Fetches all currently selected items from the tray grouped by type
         *
         * @since 6.17.0
         * @return {Array} Array of objects that were selected. Divided into items and corresponding options
         */
        getSelectedElements: function () {
            var self = this,
                items = {};

            this.collection.each(function (item) {
                var type = item.get('type');

                if (!items[type]) {
                    items[type] = {
                        data: [],
                        options: self.additionalContent[type] || {}
                    };
                }
                    items[type].data.push(item.get('ObjectID'));
            });

            // <LEGACY>
//#JSCOVERAGE_IF false
            // tray tab - marked for removal
            if (self.tray && self.tray.find('.ep-tray-useTray').prop('checked')) {
                items.insertFromTray = true;
            }
//#JSCOVERAGE_ENDIF
            // </LEGACY>
            // time to get our tab's selection data into lS (or remove it) - omitting selected tab itself
            $.each(self.tabData, function () {
                if (this.alias !== 'selected') {
                    if (self.rememberSelection) {
                        if (self.collection.length > 0) {
                            storage.localStorage('epObjectFinder.' + this.alias + 'Selection', self.collection.where({
                                type: this.alias
                            }));
                        }
                    } else {
                        storage.localStorage('epObjectFinder.' + this.alias + 'Selection', null);
                    }
                }
            });

            return items;
        },

        // create possibility to pass widget collection to the outside
        getCollection: function () {
            return this.collection;
        }
    });
});