/**
 * @class de_epages.design.inc.customizeButtonStyle
 *
 */

/*
 * @copyright       © Copyright 2006-2012, epages GmbH, All Rights Reserved.
 *
 * @module          de_epages/design/inc/customizebuttonstyle
 */
/*jslint nomen:true*/
/*global define*/
define("de_epages/design/inc/customizebuttonstyle", [
    "jquery",
    "ep",
    "util/json",
    "$tmpl!de_epages/design/inc/customizebuttonstyle",
    "de_epages/mediagallery/ui/filemanagerdialog",

    "ep/ui/dialog",
    "ep/ui/slider",
    "ep/ui/colorpicker"
], function ($, ep, json, tmplButtonStyle, de_epages) {

    'use strict';

    // Context for the plugin:
    var constraints = {
        border: {
            radius: {
                min: 0,
                max: 40
            }
        },
        padding: {
            width: {
                min: 5,
                max: 25
            },
            height: {
                min: 0,
                max: 20
            }
        },
        font: {
            size: {
                min: 10,
                max: 20
            }
        }
    },
        // See *constant CUSTOMIZABLE_BUTTONS* in /API/Constants.pm in Design and Order Cartridge.
        i = 0,
        // We will reuse this in a couple of *for*-loops.
        dialogNode,
        // After *customizeButtonStyle.buildDialog()* the *dialog*'s DOM node is to be found here.
        contentNode,
        // Content DOM node for *dialogNode*.
        callback = null,
        // Function to be executed on apply.
        userData = {},
        // At any point after *customizeButtonStyle.buildDialog()* the user's input is stored here.
        // *saveUserData()* will make use of this.
        startData = null,
        // This is where we store the initial data set for *customizeButtonStyle.buildDialog()*.
        // This is especially, if the user "applies" changes and then reopens the dialog. (No page reload needed.)
        saveDataNames = [],
        // Names of properties of the data object which are to be send to the server.
        saveUserData = function () {
            var _saveDataName, data = $.extend({
                ViewAction: 'JSONViewResponse',
                ChangeAction: 'JSONSaveCustomizableButtons'
            }, userData);
            // Default *ViewAction* and *ChangeAction* can be overridden by passing respective properties
            // within the *data* argument of *customizeButtonStyle.buildDialog()*.
            for (i = 0; i < saveDataNames.length; i = i + 1) {
                _saveDataName = saveDataNames[i];
                data[_saveDataName] = json.stringify(userData[_saveDataName]);
                // The server needs *JSON* attributes to be passed as a string.
            }
            // Let us ajax the *data* over to the server.
            $.ajax({
                url: '?',
                dataType: 'json',
                type: 'POST',
                data: data
            }).done(function (data) {
                // The server passes us back the updated data set.
                for (i = 0; i < saveDataNames.length; i = i + 1) {
                    _saveDataName = saveDataNames[i];
                    startData[_saveDataName] = $.extend(true, {}, data[_saveDataName]);
                }
                dialogNode.uiDialog('close');
                if ($.isFunction(callback)) {
                    callback();
                }
            });
        };

    // The actual plugin:
    return {
        /**
         * Initialize and open dialog to configure buttons on the SF.
         *
         * The `de_epages.design.inc.customizeButtonStyle.init()` creates dialog to configure buttons (e.g. the basket button). After calling `de_epages.design.inc.customizeButtonStyle.init()`,
         * you should call `de_epages.design.inc.customizeButtonStyle.openDialog()` to actually open the dialog. (See example.)
         *
         * ### Examples
         * Init dialog on hover and open dialog on click.
         *
         * JavaScript:
         *
         *     var customizeButtonsLink = $('#ep-CustomizeButtonStyle');
         *     // The dialog is built on *mouseenter* and opened on *click*.
         *     customizeButtonsLink
         *     .on('mouseenter', function (event) {
         *     $.ready('de_epages.design.inc.customizeButtonStyle', function ($) {
         *     de_epages.design.inc.customizeButtonStyle.init(
         *     {
         *     CustomizableBasketButton : '<button name="AddToBasket" type="submit"><span class="ep-sprite ep-sprite-s" style="background-image: url(/WebRoot/StoreTypes/6.15.0/Store/SF/Icon/WireframeBlack/ico_s_basket.png)"></span>Add to basket</button>',
         *     BubbleHelpSource : '/WebRoot/StoreTypes/6.15.0/Store/BO/icons/ico_s_bubblehelp.png'
         *     },
         *     {
         *     title : 'AdjustAddToBasketButton',
         *     restoreDefaults : 'RevertToDefault',
         *     replaceButtonWithCustomImage : 'UploadOwnImage',
         *     restoreDefaultImage : 'RemoveImage',
         *     borderColor : 'BorderColor',
         *     borderRadius : 'BorderRadius',
         *     backgroundGradient : 'ColorGradient',
         *     fontColor : 'FontColor',
         *     fontSize : 'FontSize',
         *     infoWarning : 'OptionNotAvailableInAllBrowsers',
         *     apply : 'Apply',
         *     cancel : 'Cancel',
         *     width : 'Width',
         *     height : 'Height'
         *     },
         *     {
         *     ChangeAction: 'JSONSaveCustomizableBasketButton',
         *     ObjectID : epConfig.siteId,
         *
         *
         *     CustomizableBasketButton : {
         *      Font : {
         *        Size : 13,
         *        Color : '#000'
         *      },
         *      Padding : {
         *        Height : 1,
         *        Width : 10,
         *      },
         *      Gradient : {
         *        Color1 : '#F9F9F9',
         *        Color2 : '#E2E2E2'
         *      },
         *      Border : {
         *        Radius : 3,
         *        Color : '#AAA'
         *      },
         *      Image : {
         *        Path :  null,
         *        Height :  null,
         *        Width :  null
         *      }
         *     },
         *
         *     },
         *     ['CustomizableBasketButton'],
         *     {
         *     ChangeAction: 'JSONSaveCustomizableBasketButton',
         *     ObjectID : epConfig.siteId,
         *      CustomizableBasketButton :  {
         *
         *     Font : {
         *      Size : 13,
         *      Color : '#000'
         *     },
         *     Padding : {
         *      Height : 1,
         *      Width : 10,
         *     },
         *     Gradient : {
         *      Color1 : '#F9F9F9',
         *      Color2 : '#E2E2E2'
         *     },
         *     Border : {
         *      Radius : 3,
         *      Color : '#AAA'
         *     },
         *     Image : {
         *      Path : null,
         *      Height : null,
         *      Width : null
         *     }
         *
         *     }
         *     }
         *     );
         *     });
         *     })
         *     .on('click', function (event) {
         *     $.ready({script : 'builtCustomizeButtonsDialog'}, function ($) {
         *     de_epages.design.inc.customizeButtonStyle.openDialog();
         *     })
         *     });
         *
         * HTML:
         *
         *     <button id="ep-CustomizeButtonStyle">Open Dialog</button>
         *
         *
         * ### Dependencies
         *
         *  + `jQuery.json`
         *  + `jQuery.tmpl`
         *  + `de_epages`
         *  + `ep`
         *  + `ep.ui.dialog`
         *  + `ep.ui.slider`
         *  + `ep.ui.colorpicker`
         *  + `de_epages.mediagallery.ui.filemanagerdialog`
         *
         * @param {Object} [options] A map of additional options pass to the function.
         * @param {Object} options.defaults A map with keys defining the default buttons as html strings.
         * @param {Object} options.wording A map with keys defining the wording. (See example for possible keys.)
         * @param {Object} options.data Button data for init.
         * @param {Array} options.dataNames Array of names of data properties to pass to the server on apply. (E.g. &quot;CustomizableBasketButton&quot;)
         * @param {Object} options.defaultValues Default button data. Used for restoring defaults in the dialog.
         *
         * @method init
         * @static
         * @member de_epages.design.inc.customizeButtonStyle
         *
         * @since 6.15.0
         */
        init: function (defaults, wording, data, dataNames, defaultValues, _callback) {
            callback = _callback;
            // If the *dialogNode* already exists, we do not have to to anything.
            if (dialogNode) {
                return;
            }
            this.buildContent(defaults, wording, data, dataNames, defaultValues);
            this.buildDialog(defaults, wording, data, dataNames, defaultValues);
        },
        // Function to "build" the *dialogNode*, which will later be "opened" by *customizeButtonStyle.openDialog()*.
        buildContent: function (defaults, wording, data, dataNames, defaultValues) {
            var templateData = [],
                // Each array entry represents the template data for one tab.
                renderedTemplate,
                // Stores the rendered template for *contentNode*.
                _dataName = '',
                // Stores the "current" value of *dataNames[i]* inside of a *for*-loop.
                _tab,
                // Stores the DOM elements (see template) of "current" tab inside of a *for*-loop.
                i = 0,
                imageSrc;
            // We will reuse this in a couple of *for*-loops.
            // Set up *startData*, *userData*, *data* and *saveDataNames*.
            if (startData === null) {
                startData = $.extend(true, {}, data);
            } else {
                data = startData;
            }
            userData = $.extend(true, {}, data);
            saveDataNames = dataNames;

            // Add *tabId*s for jQuery *tabs*, if needed. (See template.)
            for (i = 0; i < dataNames.length; i = i + 1) {
                _dataName = dataNames[i];
                templateData[i] = $.extend(data[_dataName], {
                    'tabId': 'ep-' + _dataName + '-tab'
                });
            }

            // Render template.
            renderedTemplate = tmplButtonStyle(templateData, {
                'wording': wording,
                'constraints': constraints,
                'bubbleHelpSource': defaults.BubbleHelpSource
            });

/* At this point we do not use tabs. could be used for further implementation, later on.
                // Make *tabs* if needed.
                if (renderedTemplate.length > 1) {
                  var $div = $('<div>'),
                      $ul = $('<ul>');
                  // TODO
                  // Weird work-around, because templating with jQuery('<a href="${blabla}">') did not work in firefox.
                  // Firefox html encoded the curly brackets inside the double quotes, so the templating engine did not recognize the insertion of a value.
                  $.each(dataNames, function (index, value) {
                    $ul.append(
                      $('<li>').append(
                        $('<a>').attr('href', '#ep-'+dataNames[index]+'-tab').text(dataNames[index] === 'CustomizableBasketButton' ? wording.basketButton : wording.otherButtons)));
                  });
                   contentNode = ep('<div>').append($ul, renderedTemplate).tabs({selected : 0}); // My chrome otherwise opens on the second tab first.
                }
                else {
                */
            contentNode = ep('<div>').append(renderedTemplate);
            //}
            // Now let us finish every single tab.
            for (i = 0; i < dataNames.length; i = i + 1) {

                // Init *_dataName* and *_tab*.
                _dataName = dataNames[i];
                _tab = $.extend({}, $(renderedTemplate[i]).tmplItem('elements'), {
                    defaultButton: $(defaults[_dataName]),
                    customImage: $('<img>')
                });

                // Add and customize preview.
                _tab.buttonPreview.append(_tab.defaultButton.css({
                    'padding': data[_dataName].Padding.Height + 'px ' + data[_dataName].Padding.Width + 'px',
                    'border-radius': data[_dataName].Border.Radius + 'px',
                    'border-color': data[_dataName].Border.Color,
                    'font-size': data[_dataName].Font.Size + 'px',
                    'color': data[_dataName].Font.Color,
                    'text-shadow': '0 0 0 transparent',
                    'line-height': '140%'
                }).css('background', '-webkit-gradient(linear, 0% 0%, 0% 100%, from(' + data[_dataName].Gradient.Color1 + '), to(' + data[_dataName].Gradient.Color2 + '))').css('background', '-moz-linear-gradient(center top, ' + data[_dataName].Gradient.Color1 + ' 10%, ' + data[_dataName].Gradient.Color2 + ' 90%)'));

                // Create *slider*(s).
                _tab.borderRadiusSlider = ep(_tab.borderRadiusSlider).uiSlider({
                    slide: $.proxy(function (event, ui) {
                        userData[this.dataName].Border.Radius = ui.value;
                        this.defaultButton.css('border-radius', ui.value + 'px');
                    }, {
                        defaultButton: _tab.defaultButton,
                        dataName: _dataName
                    })
                });
                _tab.widthSlider = ep(_tab.widthSlider).uiSlider({
                    slide: $.proxy(function (event, ui) {
                        userData[this.dataName].Padding.Width = ui.value;
                        this.defaultButton.css({
                            'padding-left': ui.value + 'px',
                            'padding-right': ui.value + 'px'
                        });
                    }, {
                        defaultButton: _tab.defaultButton,
                        dataName: _dataName
                    })
                });
                _tab.heightSlider = ep(_tab.heightSlider).uiSlider({
                    slide: $.proxy(function (event, ui) {
                        userData[this.dataName].Padding.Height = ui.value;
                        this.defaultButton.css({
                            'padding-top': ui.value + 'px',
                            'padding-bottom': ui.value + 'px'
                        });
                    }, {
                        defaultButton: _tab.defaultButton,
                        dataName: _dataName
                    })
                });
                _tab.fontSizeSlider = ep(_tab.fontSizeSlider).uiSlider({
                    slide: $.proxy(function (event, ui) {
                        userData[this.dataName].Font.Size = ui.value;
                        this.defaultButton.css('font-size', ui.value);
                    }, {
                        defaultButton: _tab.defaultButton,
                        dataName: _dataName
                    })
                });

                // Create *colorpicker*(s).
                _tab.borderColorpicker = ep(_tab.borderColorpicker).on('colorSelect', function (event, color) {
                    $(this).css('background', color);
                }).on('colorSelect', $.proxy(function (event, color) {
                    userData[this.dataName].Border.Color = color;
                    this.defaultButton.css('border-color', color);
                }, {
                    defaultButton: _tab.defaultButton,
                    dataName: _dataName
                })).uiColorpicker({
                    color: data[_dataName].Border.Color
                });
                _tab.gradientColorpicker1 = ep(_tab.gradientColorpicker1).on('colorSelect', function (event, color) {
                    $(this).css('background', color);
                }).on('colorSelect', $.proxy(function (event, color) {
                    userData[this.dataName].Gradient.Color1 = color;
                    this.gradientCheckbox.trigger('change');
                }, {
                    defaultButton: _tab.defaultButton,
                    dataName: _dataName,
                    gradientCheckbox: _tab.gradientCheckbox
                })).uiColorpicker({
                    color: data[_dataName].Gradient.Color1
                });
                _tab.gradientCheckbox = ep(_tab.gradientCheckbox).uiInput().on('change', $.proxy(function (event) {
                    var color1 = userData[this.dataName].Gradient.Color1,
                        color2,
                        hsb;
                    if (this.gradientCheckbox.is(':checked')) {
                        // Calculate second gradient color.
                        hsb = ep.color.stringToHsb(color1);
                        hsb.b = Math.max(0, hsb.b - 9);
                        color2 = '#' + ep.color.hsbToHex(hsb);
                        userData[this.dataName].Gradient.Color2 = color2;
                    } else {
                        // No gradient, i.e. Color1 = Color2.
                        color2 = userData[this.dataName].Gradient.Color2 = userData[this.dataName].Gradient.Color1;
                    }
                    this.defaultButton.css('background', '-webkit-gradient(linear, 0% 0%, 0% 100%, from(' + color1 + '), to(' + color2 + '))');
                    this.defaultButton.css('background', '-moz-linear-gradient(center top, ' + color1 + ' 10%, ' + color2 + ' 90%)');
                }, {
                    defaultButton: _tab.defaultButton,
                    dataName: _dataName,
                    gradientCheckbox: _tab.gradientCheckbox
                })).prop('checked', userData[_dataName].Gradient.Color1 !== userData[_dataName].Gradient.Color2);
                _tab.fontColorpicker = ep(_tab.fontColorpicker).on('colorSelect', function (event, color) {
                    $(this).css('background', color);
                }).on('colorSelect', $.proxy(function (event, color) {
                    userData[this.dataName].Font.Color = color;
                    this.defaultButton.css('color', color);
                }, {
                    defaultButton: _tab.defaultButton,
                    dataName: _dataName
                })).uiColorpicker({
                    color: data[_dataName].Font.Color,
                    transparent: false
                });

                // Create *tooltip*(s).
                _tab.tooltip = ep(_tab.tooltip).uiTooltip();

                // Create image upload and image removal options.
                if (data[_dataName].hasOwnProperty('Image')) {
                    imageSrc = data[_dataName].Image.Path;
                    _tab.customImage.appendTo(_tab.buttonPreview).hide();
                    if (imageSrc) {
                        _tab.customImage.attr('src', imageSrc).attr('alt', imageSrc).show();
                        _tab.defaultButton.hide();
                        _tab.bottom.addClass('Disabled');
                        _tab.bottom.find('.ep-uiSlider-wrap').each(function () {
                            ep(this).uiSlider('option', 'disabled', true);
                        });
                        _tab.bottom.find('button').each(function () {
                            $(this).attr('disabled', true);
                        });
                        _tab.gradientCheckbox.attr('disabled', true);
                    } else {
                        _tab.restoreDefaultImage.addClass('Disabled');
                    }
                    _tab.restoreDefaultImage.on('click', $.proxy(function () {
                        if (!this.tab.restoreDefaultImage.hasClass('Disabled')) {
                            userData[this.dataName].Image.Path = '';
                            this.tab.customImage.hide();
                            this.tab.defaultButton.show();
                            this.tab.bottom.removeClass('Disabled');
                            this.tab.bottom.find('.ep-uiSlider-wrap').each(function () {
                                ep(this).uiSlider('option', 'disabled', false);
                            });
                            this.tab.bottom.find('button').each(function () {
                                $(this).attr('disabled', false);
                            });
                            this.tab.bottom.find('input[type="checkbox"]').each(function () {
                                $(this).attr('disabled', false);
                            });
                            this.tab.gradientCheckbox.attr('disabled', false);
                            this.tab.restoreDefaultImage.addClass('Disabled');
                        }
                    }, {
                        dataName: _dataName,
                        tab: _tab
                    }));

                    // Init filemanagerdialog.
                    de_epages(_tab.uploadCustomImage).mediagalleryUiFilemanagerdialog({
                        filemanager: {
                            selectable: 'image/'
                        },
                        dialog: {
                            buttons: [{
                                text: wording.apply,
                                click: $.proxy(function () {
                                    var imageSrc = de_epages(this.tab.uploadCustomImage).mediagalleryUiFilemanagerdialog('getSelectedElements')[0].get('fullpath');
                                    de_epages(this.tab.uploadCustomImage).mediagalleryUiFilemanagerdialog('close');
                                    this.tab.customImage.attr('src', imageSrc).attr('alt', imageSrc).show();
                                    this.tab.defaultButton.hide();
                                    userData[this.dataName].Image.Path = imageSrc;
                                    this.tab.bottom.addClass('Disabled');
                                    this.tab.bottom.find('.ep-uiSlider-wrap').each(function () {
                                        ep(this).uiSlider('option', 'disabled', true);
                                    });
                                    this.tab.bottom.find('button').each(function () {
                                        $(this).attr('disabled', true);
                                    });
                                    this.tab.gradientCheckbox.attr('disabled', true);
                                    this.tab.restoreDefaultImage.removeClass('Disabled');
                                    this.tab.restoreDefaultImage.addClass('CursorPointer');
                                }, {
                                    dataName: _dataName,
                                    tab: _tab
                                })
                            }]
                        }
                    });
                }
            }
        },

        // Init *dialogNode*.
        buildDialog: function (defaults, wording, data, dataNames, defaultValues) {
            var self = this;

            dialogNode = ep('<div>').append(contentNode).uiDialog({
                width: '640',
                title: wording.title,
                buttons: [{
                    text: wording.restoreDefaults,
                    click: function () {
                        startData = null;
                        contentNode.remove();
                        self.buildContent(defaults, wording, defaultValues, dataNames, defaultValues);
                        dialogNode.append(contentNode);
                    }
                }, {
                    text: wording.cancel,
                    click: function () {
                        dialogNode.uiDialog('close');
                    }
                }, {
                    text: wording.apply,
                    click: saveUserData
                }],
                modal: true,
                autoOpen: false,
                close: function (event) {
                    dialogNode.uiDialog('destroy');
                    dialogNode.remove();
                    dialogNode = null;
                }
            });
            // Position buttons.
            dialogNode.parent().find('div.ui-dialog-buttonset').css('float', 'none').find('button').each(function (index) {
                if (index > 0) {
                    $(this).css('float', 'right');
                }
            });
            $.provide('builtCustomizeButtonsDialog', function () {});
        },

        // Function to "open" the *dialogNode*, which was "built" by *customizeButtonStyle.buildDialog()*.
        openDialog: function () {
            dialogNode.uiDialog('open');
        }
    };
});