/**
 * Add color picker handling for each element in the set of matched elements.
 *
 * The `.uiColorpicker()` method add color picker open on click for each element in the set of matched elements.
 *
 * ### Examples
 * Apply color picker for a button.
 *
 * JavaScript:
 *
 *     ep('button')
 *         .uiColorpicker({
 *             autoOpen:       true,
 *             orientation:    'right',
 *             callback:       function( color ){
 *                 $(this).css( 'background-color', color );
 *             }
 *         });
 *
 * HTML:
 *
 *     <button>select color</button>
 *
 * Apply extended color picker for a button.
 *
 * JavaScript:
 *
 *     ep('button')
 *         .uiColorpicker({
 *             autoOpen:       true,
 *             orientation:    'right',
 *             callback:       function( color ){
 *                 $(this).css( 'background-color', color );
 *             },
 *             extended: {
 *                 userColors: {
 *                     'Color1' : '#0A528F',
 *                     'Color2' : '#EB670B',
 *                     'Color3' : '#B0BD35',
 *                     'Color4' : '#7336F0',
 *                     'Color5' : '#59506F',
 *                     'Color6' : '#D3EC5A',
 *                     'Color7' : '#6BDC5C',
 *                     'Color8' : '#1D9675',
 *                     'Color9' : '#E087C2',
 *                     'Color10': '#47B03D',
 *                     'Color11': '#8D6319',
 *                     'Color12': '#BFD33C',
 *                     'Color13': '#85EC28',
 *                     'Color14': '#5AD9E0',
 *                     'Color15': '#B27E86',
 *                     'Color16': '#420B62',
 *                     'Color17': '#F7C93F',
 *                     'Color18': '#60FBFC',
 *                     'Color19': '#85BBC6'
 *                 },
 *                 userColorsSave: function( serializedColorsArray ){
 *                 	// save action to store the colors
 *                 },
 *                 baseColors: {
 *                 	'Base1': '#12ff98',
 *                 	'Base2': '#ef9372',
 *                 	'Base3': '#093fec',
 *                 	'Base4': '#ac2983',
 *                 	'Base5': '#a57c9d'
 *                 }
 *             }
 *         });
 *
 * HTML:
 *
 *     <button>select color</button>
 *
 *
 * @class jQuery.ui.uiColorpicker
 * @extends jQuery.Widget
 *
 * @uses jQuery.tmpl
 * @uses jQuery.metaparse
 * @uses jQuery.ui.widget
 * @uses jQuery.ui.draggable
 * @uses ep
 * @uses ep.dict
 * @uses ep.color
 * @uses ep.colorpicker
 * @uses ep.fn.contextOrientation
 * @uses ep.ui.input
 * @since 6.12.0
 */

/**
 * @event close This event is triggered when the color picker close.
 * @member jQuery.ui.uiColorpicker
 * @since 6.12.0
 */

/**
 * @event colorApply This event is triggered when the selected color applies.
 * @member jQuery.ui.uiColorpicker
 * @since 6.12.0
 */

/**
 * @event colorReset This event is triggered when the selected color resets.
 * @member jQuery.ui.uiColorpicker
 * @since 6.12.0
 */

/**
 * @event colorSelect This event is triggered when a color selects.
 * @member jQuery.ui.uiColorpicker
 * @since 6.12.0
 */

/**
 * @event open This event is triggered when the color picker opens.
 * @member jQuery.ui.uiColorpicker
 * @since 6.12.0
 */

/**
 * Apply the selected color.
 *
 * @method colorApply
 * @member jQuery.ui.uiColorpicker
 *
 * @since 6.12.0
 */

/**
 * Select an additional color or refresh the state of the selected color.
 *
 * @param {String} [color] A named or hex formated color to apply.
 *
 * @method colorSelect
 * @member jQuery.ui.uiColorpicker
 *
 * @since 6.12.0
 */

/**
 * @cfg {Boolean} [autoApply] A boolean indication whether to apply the selected color instantly (apply button is hidden).
 */

/**
 * @cfg {Boolean} [autoOpen] A boolean indication whether to open the color picker on startup.
 */

/**
 * @cfg {Function} [callback] A function to be called on apply the selected color. Receives the selected color as argument: `callback( color )`.
 */

/**
 * @cfg {String} [color] A named or hex formated startup color.
 */

/**
 * @cfg {Boolean} [transparent] A boolean indication whether to allow transparent.
 */

/**
 * @cfg {String} [orientation] A vertical and/or horizontal position relative to the matched element: middle, bottom, right, center or left.
 */

/**
 * @cfg {Array} [orientationAdjust] An array of numbers to adjust the positioning [0: adjust x, 1: adjust y].
 */

/**
 * @cfg {Object} [extended] Set this option to display the extended mode with predefined colors. See the example...
 */

/**
 * See `jQuery.ui.uiColorpicker` for details.
 *
 * @param {Object} [options] A map of additional options pass to the method.
 * @param {Boolean} [autoApply] A boolean indication whether to apply the selected color instantly (apply button is hidden).
 * @param {Boolean} [autoOpen] A boolean indication whether to open the color picker on startup.
 * @param {Function} [callback] A function to be called on apply the selected color. Receives the selected color as argument: `callback( color )`.
 * @param {String} [color] A named or hex formated startup color.
 * @param {Boolean} [transparent] A boolean indication whether to allow transparent.
 * @param {String} [orientation] A vertical and/or horizontal position relative to the matched element: middle, bottom, right, center or left.
 * @param {Array} [orientationAdjust] An array of numbers to adjust the positioning [0: adjust x, 1: adjust y].
 * @param {Object} [extended] Set this option to display the extended mode with predefined colors. See the example...
 *
 * @fires close
 * @fires colorApply
 * @fires colorReset
 * @fires colorSelect
 * @fires open
 *
 * @method uiColorpicker
 * @member jQuery
 *
 * @since 6.12.0
 */

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

/*
 * @copyright      © Copyright 2006-2011, epages GmbH, All Rights Reserved.
 *
 * @module         ep.ui.colorpicker
 *
 * @revision       $Revision: 1.15 $
 */

define("ep/ui/colorpicker", [
    "jquery",
    "ep",
    "$dict!ep/dict",
    "$tmpl!ep/ui/colorpicker",

    "jquery/tmpl",
    "jquery/metaparse",
    "jquery/ui/widget",
    "jquery/ui/draggable",
    "ep/dict",
    "ep/color",
    "ep/colorpicker",
    "ep/fn/contextorientation",
    "ep/ui/input",
    "ep/ui/simpledialog"

    /**
     * ep/ui/colopicker
     * @param  {Object} $               JQuery
     * @param  {Object} ep              ep object
     * @param  {Object} epDict          dictionary
     * @param  {Object} tmplColorpicker colorpicker template
     * @return {Object}                 ep
     */
], function ($, ep, epDict, tmplColorpicker) {
    'use strict';

    /*
     * @dictionary      ep.dict
     *
     * @translation     {ColorCode}
     *                  {Transparent}
     *                  {Restore}
     *                  {UserColors}
     *                  {MatchingColors}
     */

    var html = $('html'),

        epColor = ep.color,

        combinedColors = function (color) {
            var hsb = epColor.stringToHsb(color),
                hsb1 = {},
                hsb2 = {},
                hsb3 = {},
                hsb4 = {},
                dialog;

            // set hue
            hsb1.h = hsb.h < 340 ? hsb.h + 20 : (hsb.h + 20) - 360;
            hsb2.h = hsb1.h;
            hsb3.h = hsb.h < 240 ? hsb.h + 120 : (hsb.h + 120) - 360;
            hsb4.h = hsb.h < 260 ? hsb.h + 100 : (hsb.h + 100) - 360;

            // set saturation
            hsb1.s = hsb.s > 50 ? hsb.s - 40 : hsb.s + 40;
            hsb2.s = hsb.s > 90 ? hsb.s - 10 : hsb.s + 10;
            hsb3.s = hsb.s > 35 ? hsb.s - 25 : hsb.s + 25;
            hsb4.s = hsb2.s;

            // set brightness
            hsb1.b = hsb.b > 60 ? hsb.b - 40 : hsb.b + 40;
            hsb2.b = hsb.b > 80 ? hsb.b - 20 : hsb.b + 20;
            hsb3.b = 100;
            hsb4.b = hsb2.b;

            return {
                baseColor0: '#' + epColor.stringToHex(color),
                baseColor1: '#' + epColor.hsbToHex(hsb1),
                baseColor2: '#' + epColor.hsbToHex(hsb2),
                baseColor3: '#' + epColor.hsbToHex(hsb3),
                baseColor4: '#' + epColor.hsbToHex(hsb4)
            };
        };

    $.widget('ui.uiColorpicker', {

        options: {
            autoOpen: false,
            orientation: 'right',
            orientationAdjust: [0, 0],
            color: '#fff',
            autoApply: false,
            callback: $.noop,
            transparent: true
        },

        _create: function () {
            var self = this,
                o = self.options;

            self.elem = self.element
                .on('click', $.proxy(self, 'open'));

            self.activeCallback = $.noop;

            self.originalColor = o.color;
        },

        _init: function () {
            var self = this,
                o = self.options;

            if (o.autoOpen) {
                self.open();
            }

            if (o.extended && typeof o.extended.baseColors === 'string') {
                o.extended.baseColors = combinedColors(o.extended.baseColors);
            }

            if (self.dialog) {
                if (o.autoApply) {
                    self.applyButton.hide();
                }

                self.transparentInput
                    .attr("disabled", !o.transparent)
                    .parent()
                    .css("visibility", o.transparent ? "visible" : "hidden");

                self._colorSelect(o.color, true);
            }
        },

        _build: function (remove) {
            if (!this.dialog) {
                var self = this,
                    o = self.options,
                    colorpicker,
                    renderedTemplate = tmplColorpicker([o.extended || {}])
                        .dictParse(epDict, true)
                        .find('.ep-js').metaparse();

                // load template and push named tmpl elements to current instance
                $.extend(self, renderedTemplate.tmplItem('elements'));

                self.element.uiSimpledialog({
                    content: self.pickerContent,
                    autoOpen: false,
                    orientation: o.orientation,
                    orientationAdjust: o.orientationAdjust
                });

                self.dialog = self.element.uiSimpledialog('Instance');
                colorpicker = self.colorpicker = new ep.Colorpicker({
                    margin: 10,
                    size: 210,
                    //#JSCOVERAGE_IF false
                    callback: function (hex) {
                        self._colorSelect(hex, "colorpicker");
                    }
                    //#JSCOVERAGE_ENDIF
                });

                self.pickerBox.on('mousedown', function (event) {
                    if ($(event.target).is('canvas.ep-colorpicker')) {
                        self.transparentInput
                            .prop('checked', false);
                    }
                }).append(colorpicker.elem);

                self.active = self.previewBox.on('click', function () {
                    self._setActive();
                });

                self.hexInput.on('change', function () {
                    self._colorSelect(self.hexInput.val(), "hexInput");
                });

                self.transparentInput.on('change', function () {
                    self._colorSelect(self.transparentInput.is(":checked") ? "transparent" : "#ffffff", "transparentInput");
                });

                self.applyButton.on('click', function () {
                    self._colorApply();
                    self.close();
                });

                if (self.userColors) {
                    self.userColors.children('li').on('click', function () {
                        var elem = $(this),
                            input = elem.children('input');

                        self._setActive(elem, function (color) {
                            elem.css('background-color', color);
                            input.val(color);
                        });

                        self._colorSelect(input.val(), true);
                    }).on('dblclick', function () {
                        self.previewBox.triggerHandler('click');
                    });
                }

                if (self.baseColors) {
                    self.baseColors.children('li').on('click', function () {
                        var elem = $(this),
                            input = elem.children('input'),
                            val = input.val();

                        self._colorSelect(val);
                    });
                }

                if (self.originalBox) {
                    self.originalBox.on('click', function () {
                        var elem = $(this),
                            color = '#' + ep.color.stringToHex(elem.css('background-color'));

                        self._colorSelect(color);
                    });
                }

                // set default active state
                self.previewBox.triggerHandler('click');

                self._init();
            }
        },

        _setOption: function (name, value) {
            this._superApply(arguments);
            this._init();
        },

        _setActive: function (elem, callback) {
            elem = elem || this.previewBox;
            if (elem) {
                this.active.removeClass('active');
                this.active = elem.addClass('active');
                this.activeCallback = callback || $.noop;
            }
        },

        _colorSelect: function (color, context) {
            var self = this,
                o = self.options,
                isTransparent = (color = color || o.color) === "transparent",
                hex = isTransparent ? "ffffff" : epColor.stringToHex(color),
                name = isTransparent ? "transparent" : epColor.stringToName(color),
                string,
                restore = context === true; // no context but set also restorable color in original box

            // check whether transparent is allowed
            if (isTransparent && !o.transparent) {
                hex = "ffffff";
                name = "white";
                context = "";
            }

            if (hex || name) {
                hex = "#" + hex;
                string = name || hex;

                if (context !== "hexInput") {
                    self.hexInput.val(string);
                }
                if (context !== "transparentInput") {
                    self.transparentInput.prop("checked", name === "transparent");
                }
                if (context !== "colorpicker") {
                    self.colorpicker.setHex(hex || "ffffff", true);
                }

                o.color = string;

                self.elem.trigger('colorSelect', [string]);

                if (self.previewBox) {
                    self.previewBox.css('background', hex);
                }

                if (restore && self.originalBox) {
                    self.originalBox.css('background-color', string);
                }

                self.activeCallback(string);

                if (o.autoApply) {
                    self._colorApply(string);
                }
            }
        },

        _colorApply: function () {
            var self = this,
                color = self.options.color;

            self.originalColor = color;
            self.options.callback(color);
            self.elem.trigger('colorApply', [color]);
        },

        colorSelect: function (color, original) {
            this._build();
            this._setActive();
            this._colorSelect(color, Boolean(original));
        },

        colorApply: function () {
            this._build();
            this._setActive();
            this._colorSelect(undefined, true);
            this._colorApply();
        },

        /**
         * Reset the selected color to the previous selected / startup color.
         *
         * @method colorReset
         * @member jQuery.ui.uiColorpicker
         *
         * @since 6.12.0
         */
        colorReset: function () {
            this._build();
            this.elem.trigger('colorReset', [this.originalColor]);
            this._colorSelect(this.originalColor);
        },

        /**
         * Call up a previously attached color picker.
         *
         * @method open
         * @member jQuery.ui.uiColorpicker
         *
         * @since 6.12.0
         */
        open: function () {
            var self = this,
                o = self.options;

            // close other colorpicker
            if ($('.ep-uiSimpledialog .ep-uiColorpicker-box').filter(':visible')) {
                $('.ep-uiSimpledialog').hide();
            }

            self._build();
            self.dialog.open(self.element);
            self.elem.trigger('open');
        },

        cancel: function () {
            this.elem.trigger('cancel');
            this.close();
        },

        /**
         * Close a previously opened color picker.
         *
         * @method close
         * @member jQuery.ui.uiColorpicker
         *
         * @since 6.12.0
         */
        close: function () {
            var self = this,
                extended = self.options.extended;

            if (self.dialog) {
                self.dialog.close();
                if (extended && extended.userColorsSave) {
                    extended.userColorsSave(self.userColorsForm.serializeArray(), self);
                }

                self.elem.trigger('close');
            }
        },

        destroy: function () {
            if (this.dialog) {
                this.dialog.destroy();
            }
            this._superApply(arguments);
        }

    });

    return ep;

});