/*global define*/
define('de_epages/presentation/tray/setup', [
    'jquery',
    'ep',
    '$dict!ep/dict',

    'ep/ui/smartsearch',
    'ep/ui/input'
], function ($, ep, dict) {

    'use strict';

    var addToRequestData, addTabDataToRequestData, addToRequestDataBatch;

    addToRequestData = function (requestData, name, value) {
        requestData.push({
            name: name,
            value: value
        });
    };

    addToRequestDataBatch = function (requestData, data) {
        var dataKey;

        for (dataKey in data) {
            if (data.hasOwnProperty(dataKey)) {
                addToRequestData(requestData, dataKey, data[dataKey]);
            }
        }
    };

    addTabDataToRequestData = function (requestData, objectName, tabData, parser) {
        tabData.data.forEach(function (v) {
            addToRequestData(requestData, objectName, v);
        });

        if (parser) {
            addToRequestDataBatch(requestData, parser(tabData.options));
        }
    };

    /**
     * Creates a new object tray using a commonly used setup.
     *
     * ### Example
     *
     * This creates an object tray with one tab (`products`).
     *
     * HTML:
     *
     *     <input type="text" id="NewQuanitity" />
     *     <input type="text" class="ep-tray" />
     *
     * JavaScript:
     *
     *     setup({
     *         node: $('input.ep-tray'),
     *         smartSearch: {
     *             source: 'JSONSmartSearchProductAlias',
     *             placeholder: 'Product number',
     *             name: 'NewProduct'
     *         },
     *         dialogTitle: dict.translate('AssignProductsToOrder'),
     *         pageId: #ID,
     *         changeAction: 'JSONInsertProducts',
     *         tabs: {
     *             products: {
     *                 id: #Shop.Child.Products.ID,
     *                 action: 'JSONSearchProductsToInsert',
     *                 objectName: 'ProductIDs'
     *             }
     *         },
     *         postHook: function () {
     *             // This adds the `NewQuantity` parameter to the request, taking the value from the input with the id
     *             // `#NewQuanitity`.
     *             return { 'NewQuantity': $('#NewQuantity').val() };
     *         }
     *     });
     *
     * @param {Object}   options                            The configuration of the object tray.
     * @param {Object}   options.node                       The jQuery node this tray will be applied to.
     * @param {Object}   options.smartsearch                Configuration options for the smartsearch
     * @param {String}   options.smartSearch.source         The `ViewAction` to use for the smart search, e.g.
     *                                                      `JSONSmartSearchProductAlias`.
     * @param {String}   options.smartSearch.placeholder    Placeholder text for the created input element
     * @param {String}   options.smartSearch.name           Name attribute for the created input element
     * @param {String}   options.dialogTitle                The title of the opened dialog.
     * @param {Integer}  options.pageId                     The id of the currently openend object (#ID).
     * @param {String}   options.changeAction               The `ChangeAction` for the AJAX request, e.g. `JSONInsertCustomers`.
     * @param {Object}   options.tabs                       An object containing the tabs to display. Every tab needs the properties
     *                                                      `id`, `action` and `objectName`. A tab may have the `additionalContent`
     *                                                      and `parseAdditionalContent` property. `parseAdditionalContent` is a
     *                                                      functions which evaluates the additional content.
     * @param {Function} [options.postHook]                 A function which is executed immediately before the AJAX request is
     *                                                      sent.
     */
    return function (options) {
        options.done = options.done || function (data) {
            // reload page to display new data
            options.node.closest('form').trigger('submit');
        };

        options.fail = options.fail || function (data) {
            // reload page to display new data
            options.node.closest('form').trigger('submit');
        };


        // We're creating the smartsearch here to reduce waiting time generated by loading all the tray thingies
        if (options.smartSearch) {
            var smartSearch = $('<input />')
                .attr('type', 'text')
                .attr('placeholder', options.smartSearch.placeholder)
                .attr('name', options.smartSearch.name)
                .addClass('ep-tray-input')
                .uiInput()
                .uiSmartsearch({
                    source: options.smartSearch.source,
                    searchOptions: options.smartSearch.searchOptions
                });

            if (options.node.hasClass('Disabled')) {
                options.node.attr('disabled', 'disabled');
                smartSearch
                    .attr('disabled', 'disabled')
                    .addClass('Disabled');
            }

            smartSearch.insertBefore(options.node);
            smartSearch.on('keypress', function (e) {
                if (e.keyCode === 13) {
                    // We want to handle the "pressed enter" event ourselves: The default
                    // handling includes triggering a click on the the closest button, which is
                    // clearly not what we want: The closest button opens the tray and nothing
                    // else.
                    e.preventDefault();
                    if (options.preSmartSearchSubmitHook) {
                        options.preSmartSearchSubmitHook();
                    }

                    smartSearch.closest('form').submit();
                }
            });
        }

        // We're ready to go: Curtains up!
        options.node.css('display', 'inline-block');

        require(['de_epages/presentation/ui/tray'], function () {
            options.node.presentationUiTray({
                tabs: options.tabs,
                smartSearch: smartSearch,
                afterRender: options.afterRender,
                // <LEGACY>
                trayAction: options.trayAction,
                // </LEGACY>
                dialog: options.dialog,
                callback: function (data) {

                    var atLeastOneItemSelected = false,
                        requestData = [],
                        tabName;

                    if (!data) {
                        return;
                    }
                    // <LEGACY>
                    if (options.trayAction) {
                        addToRequestData(requestData, 'ChangeAction', options.trayAction);
                        addToRequestData(requestData, 'ObjectID', options.pageId);
                    }
                    // </LEGACY>

                    for (tabName in options.tabs) {
                        if (options.tabs.hasOwnProperty(tabName) && data[tabName]) {
                            atLeastOneItemSelected = true;
                        }
                    }

                    // Nothing selected and nothing from tray? Quit!
                    if (atLeastOneItemSelected) {
                        addToRequestData(requestData, 'ChangeAction', options.changeAction);
                        addToRequestData(requestData, 'ViewAction', 'JSONViewResponse');
                        addToRequestData(requestData, 'ObjectID', options.pageId);

                        for (tabName in options.tabs) {
                            if (options.tabs.hasOwnProperty(tabName) && data[tabName]) {
                                addTabDataToRequestData(
                                    requestData,
                                    options.tabs[tabName].objectName,
                                    data[tabName],
                                    options.tabs[tabName].parseAdditionalContent
                                );
                            }
                        }

                        if (options.postHook) {
                            addToRequestDataBatch(requestData, options.postHook());
                        }
                    } else if (Boolean(requestData.length) !== Boolean([])) {
                        return;
                    }

                    ep.ajax({
                        type: 'POST',
                        dataType: 'json',
                        data: requestData
                    })
                        .done(options.done)
                        .fail(options.fail);
                }
            });
        });
    };
});