/**
 * @aside guide forms
 *
 * スライダーは、与えられた数値範囲から値をユーザーに選択させるために使います。パーセンテージを選択するために使用したり、そのうちの2つを組み合わせて最小値と最大値を取得したり、そのうちの3つを使って16進法で色を指定したりすることができます。各スライダーには、値を変更するためのスライダーの長さをドラッグすることができる単一の「つまみ」が含まれています。スライダーは、{@link Ext.form.Panel フォーム}内部でもそれ自身のみでも等しく使用できます。これが、フォーム内にスライダーを素早く作成する方法です。このケースでは、ユーザーにパーセンテージを選択させることができます。
 *
 *     @example
 *     Ext.create('Ext.form.Panel', {
 *         fullscreen: true,
 *         items: [
 *             {
 *                 xtype: 'sliderfield',
 *                 label: 'Percentage',
 *                 value: 50,
 *                 minValue: 0,
 *                 maxValue: 100
 *             }
 *         ]
 *     });
 *
 * このケースでは、開始時の値を50%に設定し、最小値と最大値を0~100にそれぞれ定義して、パーセンテージスライダーを付与します。これは一般的な使用例であるため、{@link #minValue}および{@link #maxValue}のデフォルトはすでに0と100に設定されていますが、上記の例は削除できます。
 *
 * フォームパネルのコンテキストの外側にスライダーを描画するのに便利です。この例では、ユーザーにジーンズのウエストの寸法を選択させるスライダーを作成しています。たとえば、今、作成中のオンラインストアでは、2インチ刻みで24インチから60インチまでのウエストサイズのジーンズを販売しています。このようにして設定します:
 *
 *     @example
 *     Ext.create('Ext.form.Panel', {
 *         fullscreen: true,
 *         items: [
 *             {
 *                 xtype: 'sliderfield',
 *                 label: 'Waist Measurement',
 *                 minValue: 24,
 *                 maxValue: 60,
 *                 increment: 2,
 *                 value: 32
 *             }
 *         ]
 *     });
 *
 * スライダーはすでにあるので、現在の値をたずねて、発火するイベントをリッスンします。たとえば、サイズに応じてさまざまな画像を表示するアプリが必要な場合、スライダーが移動するたびに知らされる{@link #change}イベントをリッスンできます。
 *
 *     slider.on('change', function(field, newValue) {
 *         if (newValue[0] > 40) {
 *             imgComponent.setSrc('large.png');
 *         } else {
 *             imgComponent.setSrc('small.png');
 *         }
 *     }, this);
 *
 * ここでは、スライダー上の{@link #change}イベントをリッスンし、ユーザーが選択したサイズに基づいて{@link Ext.Img 画像コンポーネント}の背景画像を更新しました。もちろん、イベントリスナの内側でどのようなロジックを使用してもかまいません。
 */
Ext.define('Ext.field.Slider', {
    extend  : 'Ext.field.Field',
    xtype   : 'sliderfield',
    requires: ['Ext.slider.Slider'],
    alternateClassName: 'Ext.form.Slider',

    /**
     * @event change
     * 選択オプションが変更されたときに発火します。
     * @param {Ext.field.Slider} me
     * @param {Ext.slider.Slider} sl スライダーコンポーネント。
     * @param {Ext.slider.Thumb} thumb
     * @param {Number} newValue つまみの新しい値。
     * @param {Number} oldValue つまみの古い値。
     */

    /**
    * @event dragstart
    * スライダーのつまみがドラッグされ始めたときに発火します。
    * @param {Ext.field.Slider} this
    * @param {Ext.slider.Slider} sl スライダーコンポーネント。
    * @param {Ext.slider.Thumb} thumb ドラッグされているつまみ。
    * @param {Array} value 始めの値。
    * @param {Ext.EventObject} e
    */

    /**
    * @event drag
    * スライダーのつまみがドラッグされ始めたときに発火します。
    * @param {Ext.field.Slider} this
    * @param {Ext.slider.Slider} sl スライダーコンポーネント。
    * @param {Ext.slider.Thumb} thumb ドラッグされているつまみ。
    * @param {Ext.EventObject} e
    */

    /**
    * @event dragend
    * スライダーのつまみがドラッグを終了したときに発火します。
    * @param {Ext.field.Slider} this
    * @param {Ext.slider.Slider} sl スライダーコンポーネント。
    * @param {Ext.slider.Thumb} thumb ドラッグされているつまみ。
    * @param {Array} value ドラッグされた値。
    * @param {Ext.EventObject} e
    */

    config: {
        /**
         * @cfg
         * @inheritdoc
         */
        cls: Ext.baseCSSPrefix + 'slider-field',

        /**
         * @cfg
         * @inheritdoc
         */
        tabIndex: -1,

        /**
         * フィールドを読み取り専用にします。つまり使用するインタラクションは変更できません。
         * @cfg {Boolean} readOnly
         * @accessor
         */
        readOnly: false
    },

    proxyConfig: {

        /**
         * @inheritdoc Ext.slider.Slider#increment
         * @cfg {Number} increment
         * @accessor
         */
        increment : 1,

        /**
         * @inheritdoc Ext.slider.Slider#value
         * @cfg {Number/Number[]} value
         * @accessor
         */
        value: 0,

        /**
         * @inheritdoc Ext.slider.Slider#minValue
         * @cfg {Number} minValue
         * @accessor
         */
        minValue: 0,

        /**
         * @inheritdoc Ext.slider.Slider#maxValue
         * @cfg {Number} maxValue
         * @accessor
         */
        maxValue: 100
    },

    /**
     * @inheritdoc Ext.slider.Slider#value
     * @cfg {Number/Number[]} values
     */

    constructor: function(config) {
        config = config || {};

        if (config.hasOwnProperty('values')) {
            config.value = config.values;
        }

        this.callParent([config]);
        this.updateMultipleState();
    },

    // @private
    initialize: function() {
        this.callParent();

        this.getComponent().on({
            scope: this,

            change: 'onSliderChange',
            dragstart: 'onSliderDragStart',
            drag: 'onSliderDrag',
            dragend: 'onSliderDragEnd'
        });
    },

    // @private
    applyComponent: function(config) {
        return Ext.factory(config, Ext.slider.Slider);
    },

    // @private
    updateComponent: function(component) {
        this.callSuper(arguments);

        component.setMinValue(this.getMinValue());
        component.setMaxValue(this.getMaxValue());
    },

    onSliderChange: function() {
        this.fireEvent.apply(this, [].concat('change', this, Array.prototype.slice.call(arguments)));
    },

    onSliderDragStart: function() {
        this.fireEvent.apply(this, [].concat('dragstart', this, Array.prototype.slice.call(arguments)));
    },

    onSliderDrag: function() {
        this.fireEvent.apply(this, [].concat('drag', this, Array.prototype.slice.call(arguments)));
    },

    onSliderDragEnd: function() {
        this.fireEvent.apply(this, [].concat('dragend', this, Array.prototype.slice.call(arguments)));
    },

    /**
     * 便利なメソッドです。{@link #setValue}を呼び出します。
     * @param {Object} value
     */
    setValues: function(value) {
        this.setValue(value);
        this.updateMultipleState();
    },

    /**
     * 便利なメソッドです。{@link #getValue}を呼び出します。
     * @return {Object}

     */
    getValues: function() {
        return this.getValue();
    },

    reset: function() {
        var config = this.config,
            initialValue = (this.config.hasOwnProperty('values')) ? config.values : config.value;

        this.setValue(initialValue);
    },

    doSetDisabled: function(disabled) {
        this.callParent(arguments);

        this.getComponent().setDisabled(disabled);
    },

    updateReadOnly: function(newValue) {
        this.getComponent().setReadOnly(newValue);
    },

    isDirty : function () {
        if (this.getDisabled()) {
            return false;
        }

        return this.getValue() !== this.originalValue;
    },

    updateMultipleState: function() {
        var value = this.getValue();
        if (value && value.length > 1) {
            this.addCls(Ext.baseCSSPrefix + 'slider-multiple');
        }
    }
});