/**

 * echarts图表动画基类

 *

 * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。

 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)

 *

 */

define(function (require) {

    var zrUtil = require('zrender/tool/util');

    var curveTool = require('zrender/tool/curve');

    

    /**

     * 折线型动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function pointList(zr, oldShape, newShape, duration, easing) {

        var newPointList = newShape.style.pointList;

        var newPointListLen = newPointList.length;

        var oldPointList;



        if (!oldShape) {        // add

            oldPointList = [];

            if (newShape._orient != 'vertical') {

                var y = newPointList[0][1];

                for (var i = 0; i < newPointListLen; i++) {

                    oldPointList[i] = [newPointList[i][0], y];

                }

            }

            else {

                var x = newPointList[0][0];

                for (var i = 0; i < newPointListLen; i++) {

                    oldPointList[i] = [x, newPointList[i][1]];

                }

            }



            if (newShape.type == 'half-smooth-polygon') {

                oldPointList[newPointListLen - 1] = zrUtil.clone(newPointList[newPointListLen - 1]);

                oldPointList[newPointListLen - 2] = zrUtil.clone(newPointList[newPointListLen - 2]);

            }

            oldShape = {style : {pointList : oldPointList}};

        }

        

        oldPointList = oldShape.style.pointList;

        var oldPointListLen = oldPointList.length;

        if (oldPointListLen == newPointListLen) {

            newShape.style.pointList = oldPointList;

        }

        else if (oldPointListLen < newPointListLen) {

            // 原来短，新的长，补全

            newShape.style.pointList = oldPointList.concat(newPointList.slice(oldPointListLen));

        }

        else {

            // 原来长，新的短，截断

            newShape.style.pointList = oldPointList.slice(0, newPointListLen);

        }



        zr.addShape(newShape);

        newShape.__animating = true;

        zr.animate(newShape.id, 'style')

            .when(

                duration,

                { pointList: newPointList }

            )

            .during(function () {

                // Updating bezier points

                if (newShape.updateControlPoints) {

                    newShape.updateControlPoints(newShape.style);

                }

            })

            .done(function() {

                newShape.__animating = false;

            })

            .start(easing);

    }

    

    /**

     * 复制样式

     * 

     * @inner

     * @param {Object} target 目标对象

     * @param {Object} source 源对象

     * @param {...string} props 复制的属性列表

     */

    function cloneStyle(target, source) {

        var len = arguments.length;

        for (var i = 2; i < len; i++) {

            var prop = arguments[i];

            target.style[prop] = source.style[prop];

        }

    }



    /**

     * 方型动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function rectangle(zr, oldShape, newShape, duration, easing) {

        var newShapeStyle = newShape.style;

        if (!oldShape) {        // add

            oldShape = {

                position : newShape.position,

                style : {

                    x : newShapeStyle.x,

                    y : newShape._orient == 'vertical'

                        ? newShapeStyle.y + newShapeStyle.height

                        : newShapeStyle.y,

                    width: newShape._orient == 'vertical' 

                           ? newShapeStyle.width : 0,

                    height: newShape._orient != 'vertical' 

                           ? newShapeStyle.height : 0

                }

            };

        }

        

        var newX = newShapeStyle.x;

        var newY = newShapeStyle.y;

        var newWidth = newShapeStyle.width;

        var newHeight = newShapeStyle.height;

        var newPosition = [newShape.position[0], newShape.position[1]];

        cloneStyle(

            newShape, oldShape,

            'x', 'y', 'width', 'height'

        );

        newShape.position = oldShape.position;



        zr.addShape(newShape);

        if (newPosition[0] != oldShape.position[0] || newPosition[1] != oldShape.position[1]) {

            zr.animate(newShape.id, '')

                .when(

                    duration,

                    {

                        position: newPosition

                    }

                )

                .start(easing);

        }

        

        newShape.__animating = true;

        zr.animate(newShape.id, 'style')

            .when(

                duration,

                {

                    x: newX,

                    y: newY,

                    width: newWidth,

                    height: newHeight

                }

            )

            .done(function() {

                newShape.__animating = false;

            })

            .start(easing);

    }

    

    /**

     * 蜡烛动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function candle(zr, oldShape, newShape, duration, easing) {

        if (!oldShape) {        // add

            var y = newShape.style.y;

            oldShape = {style : {y : [y[0], y[0], y[0], y[0]]}};

        }

        

        var newY = newShape.style.y;

        newShape.style.y = oldShape.style.y;

        zr.addShape(newShape);

        newShape.__animating = true;

        zr.animate(newShape.id, 'style')

            .when(

                duration,

                { y: newY }

            )

            .done(function() {

                newShape.__animating = false;

            })

            .start(easing);

    }



    /**

     * 环型动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function ring(zr, oldShape, newShape, duration, easing) {

        var x = newShape.style.x;

        var y = newShape.style.y;

        var r0 = newShape.style.r0;

        var r = newShape.style.r;

        

        newShape.__animating = true;



        if (newShape._animationAdd != 'r') {

            newShape.style.r0 = 0;

            newShape.style.r = 0;

            newShape.rotation = [Math.PI*2, x, y];

            

            zr.addShape(newShape);

            zr.animate(newShape.id, 'style')

                .when(

                    duration,

                    {

                        r0 : r0,

                        r : r

                    }

                )

                .done(function() {

                    newShape.__animating = false;

                })

                .start(easing);

            zr.animate(newShape.id, '')

                .when(

                    duration,

                    { rotation : [0, x, y] }

                )

                .start(easing);

        }

        else {

            newShape.style.r0 = newShape.style.r;

            

            zr.addShape(newShape);

            zr.animate(newShape.id, 'style')

                .when(

                    duration,

                    {

                        r0 : r0

                    }

                )

                .done(function() {

                    newShape.__animating = false;

                })

                .start(easing);

        }

    }

    

    /**

     * 扇形动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function sector(zr, oldShape, newShape, duration, easing) {

        if (!oldShape) {        // add

            if (newShape._animationAdd != 'r') {

                oldShape = {

                    style : {

                        startAngle : newShape.style.startAngle,

                        endAngle : newShape.style.startAngle

                    }

                };

            }

            else {

                oldShape = {style : {r0 : newShape.style.r}};

            }

        }

        

        var startAngle = newShape.style.startAngle;

        var endAngle = newShape.style.endAngle;

        

        cloneStyle(

            newShape, oldShape,

            'startAngle', 'endAngle'

        );

        

        zr.addShape(newShape);

        newShape.__animating = true;

        zr.animate(newShape.id, 'style')

            .when(

                duration,

                {

                    startAngle : startAngle,

                    endAngle : endAngle

                }

            )

            .done(function() {

                newShape.__animating = false;

            })

            .start(easing);

    }

    

    /**

     * 文本动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function text(zr, oldShape, newShape, duration, easing) {

        if (!oldShape) {        // add

            oldShape = {

                style : {

                    x : newShape.style.textAlign == 'left' 

                        ? newShape.style.x + 100

                        : newShape.style.x - 100,

                    y : newShape.style.y

                }

            };

        }

        

        var x = newShape.style.x;

        var y = newShape.style.y;

        

        cloneStyle(

            newShape, oldShape,

            'x', 'y'

        );

        

        zr.addShape(newShape);

        newShape.__animating = true;

        zr.animate(newShape.id, 'style')

            .when(

                duration,

                {

                    x : x,

                    y : y

                }

            )

            .done(function() {

                newShape.__animating = false;

            })

            .start(easing);

    }

    

    /**

     * 多边形动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function polygon(zr, oldShape, newShape, duration, easing) {

        var rect = require('zrender/shape/Polygon').prototype.getRect(newShape.style);

        var x = rect.x + rect.width / 2;

        var y = rect.y + rect.height / 2;

        

        newShape.scale = [0.1, 0.1, x, y];

        zr.addShape(newShape);

        newShape.__animating = true;

        zr.animate(newShape.id, '')

            .when(

                duration,

                {

                    scale : [1, 1, x, y]

                }

            )

            .done(function() {

                newShape.__animating = false;

            })

            .start(easing);

    }

    

    /**

     * 和弦动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function ribbon(zr, oldShape, newShape, duration, easing) {

        if (!oldShape) {        // add

            oldShape = {

                style : {

                    source0 : 0,

                    source1 : newShape.style.source1 > 0 ? 360 : -360,

                    target0 : 0,

                    target1 : newShape.style.target1 > 0 ? 360 : -360

                }

            };

        }

        

        var source0 = newShape.style.source0;

        var source1 = newShape.style.source1;

        var target0 = newShape.style.target0;

        var target1 = newShape.style.target1;

        

        if (oldShape.style) {

            cloneStyle(

                newShape, oldShape,

                'source0', 'source1', 'target0', 'target1'

            );

        }

        

        zr.addShape(newShape);

        newShape.__animating = true;

        zr.animate(newShape.id, 'style')

            .when(

                duration,

                {

                    source0 : source0,

                    source1 : source1,

                    target0 : target0,

                    target1 : target1

                }

            )

            .done(function() {

                newShape.__animating = false;

            })

            .start(easing);

    }

    

    /**

     * gaugePointer动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function gaugePointer(zr, oldShape, newShape, duration, easing) {

        if (!oldShape) {        // add

            oldShape = {

                style : {

                    angle : newShape.style.startAngle

                }

            };

        }

        

        var angle = newShape.style.angle;

        newShape.style.angle = oldShape.style.angle;

        zr.addShape(newShape);

        newShape.__animating = true;

        zr.animate(newShape.id, 'style')

            .when(

                duration,

                {

                    angle : angle

                }

            )

            .done(function() {

                newShape.__animating = false;

            })

            .start(easing);

    }

    

    /**

     * icon动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function icon(zr, oldShape, newShape, duration, easing, delay) {

        // 避免markPoint特效取值在动画帧上

        newShape.style._x = newShape.style.x;

        newShape.style._y = newShape.style.y;

        newShape.style._width = newShape.style.width;

        newShape.style._height = newShape.style.height;



        if (!oldShape) {    // add

            var x = newShape._x || 0;

            var y = newShape._y || 0;

            newShape.scale = [0.01, 0.01, x, y];

            zr.addShape(newShape);

            newShape.__animating = true;

            zr.animate(newShape.id, '')

                .delay(delay)

                .when(

                    duration,

                    {scale : [1, 1, x, y]}

                )

                .done(function() {

                    newShape.__animating = false;

                })

                .start(easing || 'QuinticOut');

        }

        else {              // mod

            rectangle(zr, oldShape, newShape, duration, easing);

        }

    }

    

    /**

     * line动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function line(zr, oldShape, newShape, duration, easing) {

        if (!oldShape) {

            oldShape = {

                style : {

                    xStart : newShape.style.xStart,

                    yStart : newShape.style.yStart,

                    xEnd : newShape.style.xStart,

                    yEnd : newShape.style.yStart

                }

            };

        }

        

        var xStart = newShape.style.xStart;

        var xEnd = newShape.style.xEnd;

        var yStart = newShape.style.yStart;

        var yEnd = newShape.style.yEnd;



        cloneStyle(

            newShape, oldShape,

            'xStart', 'xEnd', 'yStart', 'yEnd'

        );



        zr.addShape(newShape);

        newShape.__animating = true;

        zr.animate(newShape.id, 'style')

            .when(

                duration,

                {

                    xStart: xStart,

                    xEnd: xEnd,

                    yStart: yStart,

                    yEnd: yEnd

                }

            )

            .done(function() {

                newShape.__animating = false;

            })

            .start(easing);

    }

    

    /**

     * markline动画

     * 

     * @param {ZRender} zr

     * @param {shape} oldShape

     * @param {shape} newShape

     * @param {number} duration

     * @param {tring} easing

     */

    function markline(zr, oldShape, newShape, duration, easing) {

        easing = easing || 'QuinticOut';

        newShape.__animating = true;

        zr.addShape(newShape);

        var newShapeStyle = newShape.style;



        var animationDone = function () {

            newShape.__animating = false;

        };

        var x0 = newShapeStyle.xStart;

        var y0 = newShapeStyle.yStart;

        var x2 = newShapeStyle.xEnd;

        var y2 = newShapeStyle.yEnd;

        if (newShapeStyle.curveness > 0) {

            newShape.updatePoints(newShapeStyle);

            var obj = { p: 0 };

            var x1 = newShapeStyle.cpX1;

            var y1 = newShapeStyle.cpY1;

            var newXArr = [];

            var newYArr = [];

            var subdivide = curveTool.quadraticSubdivide;

            zr.animation.animate(obj)

                .when(duration, { p: 1 })

                .during(function () {

                    // Calculate subdivided curve

                    subdivide(x0, x1, x2, obj.p, newXArr);

                    subdivide(y0, y1, y2, obj.p, newYArr);

                    newShapeStyle.cpX1 = newXArr[1];

                    newShapeStyle.cpY1 = newYArr[1];

                    newShapeStyle.xEnd = newXArr[2];

                    newShapeStyle.yEnd = newYArr[2];

                    zr.modShape(newShape);

                })

                .done(animationDone)

                .start(easing);

        }

        else {

            zr.animate(newShape.id, 'style')

                .when(0, {

                    xEnd: x0,

                    yEnd: y0

                })

                .when(duration, {

                    xEnd: x2,

                    yEnd: y2

                })

                .done(animationDone)

                .start(easing);

        }

    }



    return {

        pointList : pointList,

        rectangle : rectangle,

        candle : candle,

        ring : ring,

        sector : sector,

        text : text,

        polygon : polygon,

        ribbon : ribbon,

        gaugePointer : gaugePointer,

        icon : icon,

        line : line,

        markline : markline

    };

});

