/**
 * Sencha Pro Services presents xtype "colorselector".
 * API has been kept as close to the regular colorpicker as possible. The Selector can be
 * rendered to any container.
 *
 * The defaul selected color is configurable via {@link #value} config. Usually used in
 * forms via {@link Ext.ux.colorpick.Button} or {@link Ext.ux.colorpick.Field}.
 *
 * Typically you will need to listen for the change event to be notified when the user
 * chooses a color. Alternatively, you can bind to the "value" config
 *
 *     @example
 *     Ext.create('Ext.ux.colorpick.Selector', {
 *         value     : '993300',  // initial selected color
 *         renderTo  : Ext.getBody(),
 *         listeners: {
 *             change: function (colorselector, color) {
 *                 console.log('New color: ' + color);
 *             }
 *         }
 *     });
 */
Ext.define('Ext.ux.colorpick.Selector', {
    extend: 'Ext.container.Container',
    xtype: 'colorselector',
 
    mixins: [
        'Ext.ux.colorpick.Selection'
    ],
 
    controller : 'colorpick-selectorcontroller',
 
    requires: [
        'Ext.layout.container.HBox',
        'Ext.form.field.Text',
        'Ext.form.field.Number',
        'Ext.ux.colorpick.ColorMap',
        'Ext.ux.colorpick.SelectorModel',
        'Ext.ux.colorpick.SelectorController',
        'Ext.ux.colorpick.ColorPreview',
        'Ext.ux.colorpick.Slider',
        'Ext.ux.colorpick.SliderAlpha',
        'Ext.ux.colorpick.SliderSaturation',
        'Ext.ux.colorpick.SliderValue',
        'Ext.ux.colorpick.SliderHue'
    ],
    
    config: {
        hexReadOnly: true
    },
 
    width: 580, // default width and height gives 255x255 color map in Crisp 
    height: 337,
 
    cls: Ext.baseCSSPrefix + 'colorpicker',
    padding: 10,
 
    layout: {
        type: 'hbox',
        align: 'stretch'
    },
 
    defaultBindProperty: 'value',
    twoWayBindable: [
        'value'
    ],
 
    /**
     * @cfg fieldWidth {Number} Width of the text fields on the container (excluding HEX);
     * since the width of the slider containers is the same as the text field under it 
     * (it's the same vbox column), changing this value will also affect the spacing between
     * the sliders.
     */
    fieldWidth: 50,
 
    /**
     * @cfg fieldPad {Number} padding between the sliders and HEX/R/G/B fields.
     */    
    fieldPad: 5,
 
    /**
     * @cfg {Boolean} [showPreviousColor]
     * Whether "previous color" region (in upper right, below the selected color preview) should be shown;
     * these are relied upon by the {@link Ext.ux.colorpick.Button} and the {@link Ext.ux.colorpick.Field}.
     */
    showPreviousColor: false,
 
    /**
     * @cfg {Boolean} [showOkCancelButtons]
     * Whether Ok and Cancel buttons (in upper right, below the selected color preview) should be shown;
     * these are relied upon by the {@link Ext.ux.colorpick.Button} and the {@link Ext.ux.colorpick.Field}.
     */
    showOkCancelButtons: false,
 
    /**
     * @event change
     * Fires when a color is selected. Simply dragging sliders around will trigger this.
     * @param {Ext.ux.colorpick.Selector} this
     * @param {String} color The value of the selected color as per specified {@link #format}.
     * @param {String} previousColor The previous color value.
     */
 
    /**
     * @event ok
     * Fires when OK button is clicked (see {@link #showOkCancelButtons}).
     * @param {Ext.ux.colorpick.Selector} this
     * @param {String} color The value of the selected color as per specified {@link #format}.
     */
 
    /**
     * @event cancel
     * Fires when Cancel button is clicked (see {@link #showOkCancelButtons}).
     * @param {Ext.ux.colorpick.Selector} this
     */
 
    listeners: {
        resize: 'onResize'
    },
 
    constructor: function (config) {
        var me             = this,
            childViewModel = Ext.Factory.viewModel('colorpick-selectormodel');
 
        // Since this component needs to present its value as a thing to which users can 
        // bind, we create an internal VM for our purposes. 
        me.childViewModel = childViewModel;
        me.items = [
            me.getMapAndHexRGBFields(childViewModel),
            me.getSliderAndHField(childViewModel),
            me.getSliderAndSField(childViewModel),
            me.getSliderAndVField(childViewModel),
            me.getSliderAndAField(childViewModel),
            me.getPreviewAndButtons(childViewModel, config)
        ];
 
        me.childViewModel.bind('{selectedColor}', function (color) {
            me.setColor(color);
        });
 
        me.callParent([config]);
    },
 
    updateColor: function (color) {
        var me = this;
 
        me.mixins.colorselection.updateColor.call(me, color);
 
        me.childViewModel.set('selectedColor', color);
    },
 
    updatePreviousColor: function (color) {
        this.childViewModel.set('previousColor', color);
    },
 
    // Splits up view declaration for readability 
    // "Map" and HEX/R/G/B fields 
    getMapAndHexRGBFields: function (childViewModel) {
        var me = this,
            fieldMargin = { top: 0, right: me.fieldPad, bottom: 0, left: 0 },
            fieldWidth = me.fieldWidth;
 
        return {
            xtype     : 'container',
            viewModel : childViewModel,
            cls       : Ext.baseCSSPrefix + 'colorpicker-escape-overflow',
            flex      : 1,
            layout    : {
                type  : 'vbox',
                align : 'stretch'
            },
            margin : '0 10 0 0',
            items  : [
                // "MAP" 
                {
                    xtype : 'colorpickercolormap',
                    reference: 'colorMap',
                    flex  : 1,
                    bind  : {
                        position: {
                            bindTo : '{selectedColor}',
                            deep   : true
                        },
                        hue: '{selectedColor.h}'
                    },
                    listeners : {
                        handledrag: 'onColorMapHandleDrag'
                    }
                },
                // HEX/R/G/B FIELDS 
                {
                    xtype    : 'container',
                    layout   : 'hbox',
 
                    defaults : {
                        labelAlign: 'top',
                        labelSeparator: '',
                        allowBlank: false,
 
                        onChange: function () {
                            // prevent data binding propagation if bad value 
                            if (this.isValid()) {
                                // this is kind of dirty and ideally we would extend these fields 
                                // and override the method, but works for now 
                                Ext.form.field.Base.prototype.onChange.apply(this, arguments);
                            }
                        }
                    },
 
                    items: [{
                        xtype      : 'textfield',
                        fieldLabel : 'HEX',
                        flex       : 1,
                        bind       : '{hex}',
                        margin     : fieldMargin,
                        regex      : /^#[0-9a-f]{6}$/i,
                        readonly   : me.getHexReadOnly()
                    }, {
                        xtype       : 'numberfield',
                        fieldLabel  : 'R',
                        bind        : '{red}',
                        width       : fieldWidth,
                        hideTrigger : true,
                        maxValue    : 255,
                        minValue    : 0,
                        margin      : fieldMargin
                    }, {
                        xtype       : 'numberfield',
                        fieldLabel  : 'G',
                        bind        : '{green}',
                        width       : fieldWidth,
                        hideTrigger : true,
                        maxValue    : 255,
                        minValue    : 0,
                        margin      : fieldMargin
                    }, {
                        xtype       : 'numberfield',
                        fieldLabel  : 'B',
                        bind        : '{blue}',
                        width       : fieldWidth,
                        hideTrigger : true,
                        maxValue    : 255,
                        minValue    : 0,
                        margin      : 0
                    }]
                }
            ]
        };
    },
 
    // Splits up view declaration for readability 
    // Slider and H field  
    getSliderAndHField: function (childViewModel) {
        var me = this,
            fieldWidth = me.fieldWidth;
 
        return {
            xtype     : 'container',
            viewModel : childViewModel,
            cls       : Ext.baseCSSPrefix + 'colorpicker-escape-overflow',
            width     : fieldWidth,
            layout    : {
                type  : 'vbox',
                align : 'stretch'
            },
            items  : [
                {
                    xtype: 'colorpickersliderhue',
                    reference: 'hueSlider',
                    flex  : 1,
                    bind: {
                        hue: '{selectedColor.h}'
                    },
                    width: fieldWidth,
                    listeners: {
                        handledrag: 'onHueSliderHandleDrag'
                    }
                },
                {
                    xtype          : 'numberfield',
                    fieldLabel     : 'H',
                    labelAlign     : 'top',
                    labelSeparator : '',
                    bind           : '{hue}',
                    hideTrigger    : true,
                    maxValue       : 360,
                    minValue       : 0,
                    allowBlank     : false,
                    margin         : 0
                }
            ]
        };
    },
 
    // Splits up view declaration for readability 
    // Slider and S field  
    getSliderAndSField: function (childViewModel) {
        var me = this,
            fieldWidth = me.fieldWidth;
 
        return {
            xtype     : 'container',
            viewModel : childViewModel,
            cls       : Ext.baseCSSPrefix + 'colorpicker-escape-overflow',
            width     : fieldWidth,
            layout    : {
                type  : 'vbox',
                align : 'stretch'
            },
            margin: {
                right  : me.fieldPad,
                left   : me.fieldPad
            },
            items: [
                {
                    xtype : 'colorpickerslidersaturation',
                    reference: 'satSlider',
                    flex  : 1,
                    bind  : {
                        saturation : '{saturation}',
                        hue        : '{selectedColor.h}'
                    },
                    width: fieldWidth,
                    listeners : {
                        handledrag: 'onSaturationSliderHandleDrag'
                    }
                },
                {
                    xtype          : 'numberfield',
                    fieldLabel     : 'S',
                    labelAlign     : 'top',
                    labelSeparator : '',
                    bind           : '{saturation}',
                    hideTrigger    : true,
                    maxValue       : 100,
                    minValue       : 0,
                    allowBlank     : false,
                    margin         : 0
                }
            ]
        };
    },
 
    // Splits up view declaration for readability 
    // Slider and V field  
    getSliderAndVField: function (childViewModel) {
        var me = this,
            fieldWidth = me.fieldWidth;
 
        return {
            xtype     : 'container',
            viewModel : childViewModel,
            cls       : Ext.baseCSSPrefix + 'colorpicker-escape-overflow',
            width     : fieldWidth,
            layout    : {
                type  : 'vbox',
                align : 'stretch'
            },
            items: [
                {
                    xtype : 'colorpickerslidervalue',
                    reference: 'valueSlider',
                    flex  : 1,
                    bind  : {
                        value : '{value}',
                        hue   : '{selectedColor.h}'
                    },
                    width: fieldWidth,
                    listeners : {
                        handledrag: 'onValueSliderHandleDrag'
                    }
                },
                {
                    xtype          : 'numberfield',
                    fieldLabel     : 'V',
                    labelAlign     : 'top',
                    labelSeparator : '',
                    bind           : '{value}',
                    hideTrigger    : true,
                    maxValue       : 100,
                    minValue       : 0,
                    allowBlank     : false,
                    margin         : 0
                }
            ]
        };
    },
 
    // Splits up view declaration for readability 
    // Slider and A field  
    getSliderAndAField: function (childViewModel) {
        var me = this,
            fieldWidth = me.fieldWidth;
 
        return {
            xtype     : 'container',
            viewModel : childViewModel,
            cls       : Ext.baseCSSPrefix + 'colorpicker-escape-overflow',
            width     : fieldWidth,
            layout    : {
                type  : 'vbox',
                align : 'stretch'
            },
            margin: {
                left: me.fieldPad
            },
            items: [
                {
                    xtype : 'colorpickerslideralpha',
                    reference: 'alphaSlider',
                    flex  : 1,
                    bind  : {
                        alpha : '{alpha}',
                        color : {
                            bindTo: '{selectedColor}',
                            deep: true
                        }
                    },
                    width: fieldWidth,
                    listeners : {
                        handledrag: 'onAlphaSliderHandleDrag'
                    }
                },
                {
                    xtype          : 'numberfield',
                    fieldLabel     : 'A',
                    labelAlign     : 'top',
                    labelSeparator : '',
                    bind           : '{alpha}',
                    hideTrigger    : true,
                    maxValue       : 100,
                    minValue       : 0,
                    allowBlank     : false,
                    margin         : 0
                }
            ]
        };
    },
 
    // Splits up view declaration for readability 
    // Preview current/previous color squares and OK and Cancel buttons 
    getPreviewAndButtons: function (childViewModel, config) {
        // selected color preview is always shown 
        var items = [{
            xtype : 'colorpickercolorpreview',
            flex  : 1,
            bind  : {
                color: {
                    bindTo : '{selectedColor}',
                    deep   : true
                }
            }
        }];
 
        // previous color preview is optional 
        if (config.showPreviousColor) {
            items.push({
                xtype  : 'colorpickercolorpreview',
                flex   : 1,
                bind   : {
                    color: {
                        bindTo : '{previousColor}',
                        deep   : true
                    }
                },
                listeners: {
                    click: 'onPreviousColorSelected'
                }
            });
        }
 
        // Ok/Cancel buttons are optional 
        if (config.showOkCancelButtons) {
            items.push({
                xtype   : 'button',
                text    : 'OK',
                margin  : '10 0 0 0',
                padding : '10 0 10 0',
                handler : 'onOK'
            },
            {
                xtype   : 'button',
                text    : 'Cancel',
                margin  : '10 0 0 0',
                padding : '10 0 10 0',
                handler : 'onCancel'
            });
        }
 
        return {
            xtype     : 'container',
            viewModel : childViewModel,
            width     : 70,
            margin    : '0 0 0 10',
            items     : items,
            layout    : {
                type  : 'vbox',
                align : 'stretch'
            }
        };
    }
});