/**
 * @private
 */
Ext.define('Ext.fx.layout.card.Scroll', {
    extend: 'Ext.fx.layout.card.Abstract',

    requires: [
        'Ext.fx.easing.Linear'
    ],

    alias: 'fx.layout.card.scroll',

    config: {
        duration: 150
    },

    constructor: function(config) {
        this.initConfig(config);

        this.doAnimationFrame = Ext.Function.bind(this.doAnimationFrame, this);
    },

    getEasing: function() {
        var easing = this.easing;

        if (!easing) {
            this.easing = easing = new Ext.fx.easing.Linear();
        }

        return easing;
    },

    updateDuration: function(duration) {
        this.getEasing().setDuration(duration);
    },

    onActiveItemChange: function(cardLayout, newItem, oldItem, options, controller) {
        var direction = this.getDirection(),
            easing = this.getEasing(),
            containerElement, inElement, outElement, containerWidth, containerHeight, reverse;

        if (newItem && oldItem) {
            if (this.isAnimating) {
                this.stopAnimation();
            }

            newItem.setWidth('100%');
            newItem.setHeight('100%');

            containerElement = this.getLayout().container.innerElement;
            containerWidth = containerElement.getWidth();
            containerHeight = containerElement.getHeight();

            inElement = newItem.renderElement;
            outElement = oldItem.renderElement;

            this.oldItem = oldItem;
            this.newItem = newItem;
            this.currentEventController = controller;
            this.containerElement = containerElement;
            this.isReverse = reverse = this.getReverse();

            newItem.show();

            if (direction == 'right') {
                direction = 'left';
                this.isReverse = reverse = !reverse;
            }
            else if (direction == 'down') {
                direction = 'up';
                this.isReverse = reverse = !reverse;
            }

            if (direction == 'left') {
                if (reverse) {
                    easing.setConfig({
                        startValue: containerWidth,
                        endValue: 0
                    });

                    containerElement.dom.scrollLeft = containerWidth;
                    outElement.setLeft(containerWidth);
                }
                else {
                    easing.setConfig({
                        startValue: 0,
                        endValue: containerWidth
                    });

                    inElement.setLeft(containerWidth);
                }
            }
            else {
                if (reverse) {
                    easing.setConfig({
                        startValue: containerHeight,
                        endValue: 0
                    });

                    containerElement.dom.scrollTop = containerHeight;
                    outElement.setTop(containerHeight);
                }
                else {
                    easing.setConfig({
                        startValue: 0,
                        endValue: containerHeight
                    });

                    inElement.setTop(containerHeight);
                }
            }

            this.startAnimation();

            controller.pause();
        }
    },

    startAnimation: function() {
        this.isAnimating = true;
        this.getEasing().setStartTime(Date.now());
        this.timer = setInterval(this.doAnimationFrame, 20);
        this.doAnimationFrame();
    },

    doAnimationFrame: function() {
        var easing = this.getEasing(),
            direction = this.getDirection(),
            scroll = 'scrollTop',
            value;

        if (direction == 'left' || direction == 'right') {
            scroll = 'scrollLeft';
        }

        if (easing.isEnded) {
            this.stopAnimation();
        }
        else {
            value = easing.getValue();
            this.containerElement.dom[scroll] = value;
        }
    },

    stopAnimation: function() {
        var me = this,
            direction = me.getDirection(),
            scroll = 'setTop',
            oldItem = me.oldItem,
            newItem = me.newItem;

        if (direction == 'left' || direction == 'right') {
            scroll = 'setLeft';
        }

        me.currentEventController.resume();

        if (me.isReverse && oldItem && oldItem.renderElement && oldItem.renderElement.dom) {
            oldItem.renderElement[scroll](null);
        }
        else if (newItem && newItem.renderElement && newItem.renderElement.dom) {
            newItem.renderElement[scroll](null);
        }

        clearInterval(me.timer);
        me.isAnimating = false;
        me.fireEvent('animationend', me);
    }
});
