/**
 * タッチスクローラを使ったスクロールの際に、スクロール位置を示す視覚的なインジケータを提供します
 *
 * @private
 */
Ext.define('Ext.scroll.Indicator', {

    config: {
        /**
         * @cfg {String} axis ('x' or 'y')
         */
        axis: null,

        /**
         * @cfg {Ext.dom.Element} containerEl インジケータを中に描画する要素。
         */
        containerEl: null,

        /**
         * @cfg {Ext.scroll.Scroller} scroller スクローラインスタンス
         */
        scroller: null,

        /**
         * @cfg {Number} minLength インジケータの最小の長さ。デフォルトは、インジケータの「サイズ」(垂直インジケータなら幅、水平インジケータなら高さ)になります。
         */
        minLength: null,

        /**
         * @cfg {Number} scrollSize 設定された{@link #axis}上のスクローラのサイズ。
         */
        scrollSize: null,

        /**
         * @cfg {Number} maxScrollPosition 設定された{@link #axis}上のスクローラの最大スクロール位置。
         */
        maxScrollPosition: null,

        /**
         * @cfg {Boolean} hasOpposite インジケータが反対の軸上に第二のインジケータの場所を残す必要がある場合には`true`
         */
        hasOpposite: null
    },

    hideAnimConfig: {
        to: {
            opacity: 0
        },
        duration: 300
    },

    names: {
        x: {
            side: 'l',
            getSize: 'getHeight',
            clientSize: 'clientWidth',
            setLength: 'setWidth',
            setPosition: 'setLocalX'
        },
        y: {
            side: 't',
            getSize: 'getWidth',
            clientSize: 'clientHeight',
            setLength: 'setHeight',
            setPosition: 'setLocalY'
        }
    },

    cls: Ext.baseCSSPrefix + 'scroll-indicator',

    constructor: function(config) {
        var me = this,
            minLength, size, axis;

        me.initConfig(config);

        axis = me.getAxis();

        me.names = me.names[axis];

        me.el = me.getContainerEl().createChild({
            cls: me.cls + ' ' + me.cls + '-' + axis
        });

        if (!me.size) {
            me.cacheStyles();
        }

        minLength = me.getMinLength();
        size = me.size;

        if (!minLength || minLength < size) {
            me.setMinLength(size);
        }
    },

    cacheStyles: function() {
        var me = this,
            proto = me.self.prototype,
            el = me.el,
            axis = me.getAxis(),
            names = me.names;

        /**
         * @property {Number} size
         * インジケータのサイズ(垂直なら幅、水平なら高さ)
         */
        proto.size = el[names.getSize]();

        /**
         * @property {Number} margin
         * インジケータのマージン(インジケータの端とコンテナの端の間の余白)
         */
        proto.margin = el.getMargin(names.side);
    },

    hide: function() {
        this.el.animate(this.hideAnimConfig);
    },

    refreshLength: function() {
        var me = this,
            names = me.names,
            scrollSize = me.getScrollSize(),
            containerSize = me.getContainerEl().dom[names.clientSize],
            ratio = containerSize / scrollSize,
            hasOpposite = me.getHasOpposite(),
            baseSizeAdjust = me.margin * 2,
            sizeAdjust = hasOpposite ? (baseSizeAdjust + me.size) : baseSizeAdjust,
            length = Math.max(Math.round((containerSize - sizeAdjust) * ratio), me.getMinLength());

        me.sizeAdjust = sizeAdjust;

        /**
         * @property {Number} length
         * インジケータの「長さ」(垂直インジケータなら高さ、水平インジケータなら幅)
         */
        me.length = length;
        me.el[names.setLength](length);
    },

    /**
     * このスクロールインジケータの値を設定します。
     * @param {Number} value 設定された{@link #axis}上のスクロール位置。
     */
    setValue: function(value) {
        var me = this,
            el = me.el,
            names = me.names,
            maxScrollPosition = me.getMaxScrollPosition(),
            containerSize = me.getContainerEl().dom[names.clientSize],
            baseLength = me.length,
            minLength = me.getMinLength(),
            length = baseLength,
            maxPosition = containerSize - baseLength - me.sizeAdjust,
            round = Math.round,
            max = Math.max,
            position;

        if (value < 0) {
            length = round(max(
                baseLength + (baseLength * value / containerSize),
                minLength
            ));
            position = 0;
        } else if (value > maxScrollPosition) {
            length = round(max(
                baseLength - (baseLength *
                    (value - maxScrollPosition) / containerSize),
                minLength
            ));
            position = maxPosition + baseLength - length;
        } else {
            position = round(value / maxScrollPosition * maxPosition);
        }

        el[names.setPosition](position);
        el[names.setLength](length);
    },

    show: function() {
        var me = this,
            el = me.el,
            anim = el.getActiveAnimation();

        if (anim) {
            anim.end();
        }

        me.refreshLength();
        el.setStyle('opacity', '');
    },

    destroy: function() {
        this.el.destroy();
    }

});