/*
 * Very simple jQuery Color Picker
 * https://github.com/tkrotoff/jquery-simplecolorpicker
 *
 * Copyright (C) 2012-2013 Tanguy Krotoff <tkrotoff@gmail.com>
 *
 * Licensed under the MIT license
 */

(function($) {
    'use strict';

    /**
     * Constructor.
     */
    var SimpleColorPicker = function(select, options) {
        this.init('simplecolorpicker', select, options);
    };

    /**
     * SimpleColorPicker class.
     */
    SimpleColorPicker.prototype = {
        constructor: SimpleColorPicker,

        init: function(type, select, options) {
            var self = this;

            self.type = type;

            self.$select = $(select);
            self.$select.hide();

            self.options = $.extend({}, $.fn.simplecolorpicker.defaults, options);

            self.$colorList = null;

            if (self.options.picker === true) {
                var selectText = self.$select.find('> option:selected').text();
                self.$icon = $('<span class="simplecolorpicker icon"'
                + ' title="' + selectText + '"'
                + ' style="background-color: ' + self.$select.val() + ';"'
                + ' role="button" tabindex="0">'
                + '</span>').insertAfter(self.$select);
                self.$icon.on('click.' + self.type, $.proxy(self.showPicker, self));

                self.$picker = $('<span class="simplecolorpicker picker ' + self.options.theme + '"></span>').appendTo(document.body);
                self.$colorList = self.$picker;

                // Hide picker when clicking outside
                $(document).on('mousedown.' + self.type, $.proxy(self.hidePicker, self));
                self.$picker.on('mousedown.' + self.type, $.proxy(self.mousedown, self));
            } else {
                self.$inline = $('<span class="simplecolorpicker inline ' + self.options.theme + '"></span>').insertAfter(self.$select);
                self.$colorList = self.$inline;
            }

            // Build the list of colors
            // <span class="color selected" title="Green" style="background-color: #7bd148;" role="button"></span>
            self.$select.find('> option').each(function() {
                var $option = $(this);
                var color = $option.val();

                var isSelected = $option.is(':selected');
                var isDisabled = $option.is(':disabled');

                var selected = '';
                if (isSelected === true) {
                    selected = ' data-selected';
                }

                var disabled = '';
                if (isDisabled === true) {
                    disabled = ' data-disabled';
                }

                var title = '';
                if (isDisabled === false) {
                    title = ' title="' + $option.text() + '"';
                }

                var role = '';
                if (isDisabled === false) {
                    role = ' role="button" tabindex="0"';
                }

                var $colorSpan = $('<span class="color"'
                + title
                + ' style="background-color: ' + color + ';"'
                + ' data-color="' + color + '"'
                + selected
                + disabled
                + role + '>'
                + '</span>');

                self.$colorList.append($colorSpan);
                $colorSpan.on('click.' + self.type, $.proxy(self.colorSpanClicked, self));

                var $next = $option.next();
                if ($next.is('optgroup') === true) {
                    // Vertical break, like hr
                    self.$colorList.append('<span class="vr"></span>');
                }
            });
        },

        /**
         * Changes the selected color.
         *
         * @param color the hexadecimal color to select, ex: '#fbd75b'
         */
        selectColor: function(color) {
            var self = this;

            var $colorSpan = self.$colorList.find('> span.color').filter(function() {
                return $(this).data('color').toLowerCase() === color.toLowerCase();
            });

            if ($colorSpan.length > 0) {
                self.selectColorSpan($colorSpan);
            } else {
                console.error("The given color '" + color + "' could not be found");
            }
        },

        showPicker: function() {
            var pos = this.$icon.offset();
            this.$picker.css({
                // Remove some pixels to align the picker icon with the icons inside the dropdown
                left: pos.left - 6,
                top: pos.top + this.$icon.outerHeight()
            });

            this.$picker.show(this.options.pickerDelay);
        },

        hidePicker: function() {
            this.$picker.hide(this.options.pickerDelay);
        },

        /**
         * Selects the given span inside $colorList.
         *
         * The given span becomes the selected one.
         * It also changes the HTML select value, this will emit the 'change' event.
         */
        selectColorSpan: function($colorSpan) {
            var color = $colorSpan.data('color');
            var title = $colorSpan.prop('title');

            // Mark this span as the selected one
            $colorSpan.siblings().removeAttr('data-selected');
            $colorSpan.attr('data-selected', '');

            if (this.options.picker === true) {
                this.$icon.css('background-color', color);
                this.$icon.prop('title', title);
                this.hidePicker();
            }

            // Change HTML select value
            this.$select.val(color);
        },

        /**
         * The user clicked on a color inside $colorList.
         */
        colorSpanClicked: function(e) {
            // When a color is clicked, make it the new selected one (unless disabled)
            if ($(e.target).is('[data-disabled]') === false) {
                this.selectColorSpan($(e.target));
                this.$select.trigger('change');
            }
        },

        /**
         * Prevents the mousedown event from "eating" the click event.
         */
        mousedown: function(e) {
            e.stopPropagation();
            e.preventDefault();
        },

        destroy: function() {
            if (this.options.picker === true) {
                this.$icon.off('.' + this.type);
                this.$icon.remove();
                $(document).off('.' + this.type);
            }

            this.$colorList.off('.' + this.type);
            this.$colorList.remove();

            this.$select.removeData(this.type);
            this.$select.show();
        }
    };

    /**
     * Plugin definition.
     * How to use: $('#id').simplecolorpicker()
     */
    $.fn.simplecolorpicker = function(option) {
        var args = $.makeArray(arguments);
        args.shift();

        // For HTML element passed to the plugin
        return this.each(function() {
            var $this = $(this),
                data = $this.data('simplecolorpicker'),
                options = typeof option === 'object' && option;
            if (data === undefined) {
                $this.data('simplecolorpicker', (data = new SimpleColorPicker(this, options)));
            }
            if (typeof option === 'string') {
                data[option].apply(data, args);
            }
        });
    };

    /**
     * Default options.
     */
    $.fn.simplecolorpicker.defaults = {
        // No theme by default
        theme: '',

        // Show the picker or make it inline
        picker: false,

        // Animation delay in milliseconds
        pickerDelay: 0
    };

})(jQuery);