/**
 * @fileOverview Default animation funciton
 * @author sima.zhang
 */
var Util = require('../util');

var G = require('../renderer');

var PathUtil = Util.PathUtil;

function getClip(coord) {
  var start = coord.start;
  var end = coord.end;
  var width = coord.getWidth();
  var height = coord.getHeight();
  var margin = 200;
  var startAngle;
  var endAngle;
  var center;
  var radius;
  var clip;

  if (coord.isPolar) {
    radius = coord.getRadius();
    center = coord.getCenter();
    startAngle = coord.startAngle;
    endAngle = coord.endAngle;
    clip = new G.Fan({
      attrs: {
        x: center.x,
        y: center.y,
        rs: 0,
        re: radius + margin,
        startAngle: startAngle,
        endAngle: startAngle
      }
    });
    clip.endState = {
      endAngle: endAngle
    };
  } else {
    clip = new G.Rect({
      attrs: {
        x: start.x - margin,
        y: end.y - margin,
        width: coord.isTransposed ? width + margin * 2 : 0,
        height: coord.isTransposed ? 0 : height + margin * 2
      }
    });

    if (coord.isTransposed) {
      clip.endState = {
        height: height + margin * 2
      };
    } else {
      clip.endState = {
        width: width + margin * 2
      };
    }
  }

  clip.isClip = true;
  return clip;
} // 获取图形的包围盒


function getPointsBox(points) {
  if (Util.isEmpty(points)) {
    return null;
  }

  var minX = points[0].x;
  var maxX = points[0].x;
  var minY = points[0].y;
  var maxY = points[0].y;
  Util.each(points, function (point) {
    minX = minX > point.x ? point.x : minX;
    maxX = maxX < point.x ? point.x : maxX;
    minY = minY > point.y ? point.y : minY;
    maxY = maxY < point.y ? point.y : maxY;
  });
  return {
    minX: minX,
    maxX: maxX,
    minY: minY,
    maxY: maxY,
    centerX: (minX + maxX) / 2,
    centerY: (minY + maxY) / 2
  };
}

function getAngle(shape, coord) {
  var points = shape.points || shape.get('origin').points;
  var box = getPointsBox(points);
  var endAngle;
  var startAngle;
  var coordStartAngle = coord.startAngle;
  var coordEndAngle = coord.endAngle;
  var diffAngle = coordEndAngle - coordStartAngle;

  if (coord.isTransposed) {
    endAngle = box.maxY * diffAngle;
    startAngle = box.minY * diffAngle;
  } else {
    endAngle = box.maxX * diffAngle;
    startAngle = box.minX * diffAngle;
  }

  endAngle += coordStartAngle;
  startAngle += coordStartAngle;
  return {
    startAngle: startAngle,
    endAngle: endAngle
  };
}

function getAnimateParam(animateCfg, index, id) {
  var result = {};

  if (animateCfg.delay) {
    result.delay = Util.isFunction(animateCfg.delay) ? animateCfg.delay(index, id) : animateCfg.delay;
  }

  result.easing = Util.isFunction(animateCfg.easing) ? animateCfg.easing(index, id) : animateCfg.easing;
  result.duration = Util.isFunction(animateCfg.duration) ? animateCfg.duration(index, id) : animateCfg.duration;
  result.callback = animateCfg.callback;
  return result;
}

function scaleInY(shape, animateCfg) {
  var id = shape._id;
  var index = shape.get('index');
  var box = shape.getBBox();
  var points = shape.get('origin').points;
  var x = (box.minX + box.maxX) / 2;
  var y;

  if (points[0].y - points[1].y <= 0) {
    // 当顶点在零点之下
    y = box.maxY;
  } else {
    y = box.minY;
  }

  var v = [x, y, 1];
  shape.apply(v);
  shape.attr('transform', [['t', -x, -y], ['s', 1, 0.01], ['t', x, y]]);
  var endState = {
    transform: [['t', -x, -y], ['s', 1, 100], ['t', x, y]]
  };
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, animateParam.callback, animateParam.delay);
}

function scaleInX(shape, animateCfg) {
  var id = shape._id;
  var index = shape.get('index');
  var box = shape.getBBox();
  var points = shape.get('origin').points;
  var x;
  var y = (box.minY + box.maxY) / 2;

  if (points[0].y - points[1].y > 0) {
    // 当顶点在零点之下
    x = box.maxX;
  } else {
    x = box.minX;
  }

  var v = [x, y, 1];
  shape.apply(v);
  shape.attr({
    transform: [['t', -x, -y], ['s', 0.01, 1], ['t', x, y]]
  });
  var endState = {
    transform: [['t', -x, -y], ['s', 100, 1], ['t', x, y]]
  };
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, animateParam.callback, animateParam.delay);
}

function lineWidthOut(shape, animateCfg) {
  var endState = {
    lineWidth: 0,
    opacity: 0
  };
  var id = shape._id;
  var index = shape.get('index');
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, function () {
    shape.remove();
  }, animateParam.delay);
}

function zoomIn(shape, animateCfg, coord) {
  var id = shape._id;
  var index = shape.get('index');
  var x;
  var y;

  if (coord.isPolar && shape.name !== 'point') {
    x = coord.getCenter().x;
    y = coord.getCenter().y;
  } else {
    var box = shape.getBBox();
    x = (box.minX + box.maxX) / 2;
    y = (box.minY + box.maxY) / 2;
  }

  var v = [x, y, 1];
  shape.apply(v);
  shape.attr({
    transform: [['t', -x, -y], ['s', 0.01, 0.01], ['t', x, y]]
  });
  var endState = {
    transform: [['t', -x, -y], ['s', 100, 100], ['t', x, y]]
  };
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, animateParam.callback, animateParam.delay);
}

function zoomOut(shape, animateCfg, coord) {
  var id = shape._id;
  var index = shape.get('index');
  var x;
  var y;

  if (coord.isPolar && shape.name !== 'point') {
    x = coord.getCenter().x;
    y = coord.getCenter().y;
  } else {
    var box = shape.getBBox();
    x = (box.minX + box.maxX) / 2;
    y = (box.minY + box.maxY) / 2;
  }

  var v = [x, y, 1];
  shape.apply(v);
  var endState = {
    transform: [['t', -x, -y], ['s', 0.01, 0.01], ['t', x, y]]
  };
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, function () {
    shape.remove();
  }, animateParam.delay);
}

function pathIn(shape, animateCfg) {
  if (shape.get('type') !== 'path') return;
  var id = shape._id;
  var index = shape.get('index');
  var path = PathUtil.pathToAbsolute(shape.attr('path'));
  shape.attr('path', [path[0]]);
  var endState = {
    path: path
  };
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, animateParam.callback, animateParam.delay);
}

function pathOut(shape, animateCfg) {
  if (shape.get('type') !== 'path') return;
  var id = shape._id;
  var index = shape.get('index');
  var path = PathUtil.pathToAbsolute(shape.attr('path'));
  var endState = {
    path: [path[0]]
  };
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, function () {
    shape.remove();
  }, animateParam.delay);
}

function clipIn(shape, animateCfg, coord, startAngle, endAngle) {
  var clip = getClip(coord);
  var canvas = shape.get('canvas');
  var id = shape._id;
  var index = shape.get('index');
  var endState;

  if (startAngle) {
    clip.attr('startAngle', startAngle);
    clip.attr('endAngle', startAngle);
    endState = {
      endAngle: endAngle
    };
  } else {
    endState = clip.endState;
  }

  clip.set('canvas', canvas);
  shape.attr('clip', clip);
  shape.setSilent('animating', true);
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  clip.animate(endState, animateParam.duration, animateParam.easing, function () {
    if (shape && !shape.get('destroyed')) {
      shape.attr('clip', null);
      shape.setSilent('cacheShape', null);
      shape.setSilent('animating', false);
      clip.remove();
    }
  }, animateParam.delay);
}

function fadeIn(shape, animateCfg) {
  var id = shape._id;
  var index = shape.get('index');
  var fillOpacity = Util.isNil(shape.attr('fillOpacity')) ? 1 : shape.attr('fillOpacity');
  var strokeOpacity = Util.isNil(shape.attr('strokeOpacity')) ? 1 : shape.attr('strokeOpacity');
  shape.attr('fillOpacity', 0);
  shape.attr('strokeOpacity', 0);
  var endState = {
    fillOpacity: fillOpacity,
    strokeOpacity: strokeOpacity
  };
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, animateParam.callback, animateParam.delay);
}

function fadeOut(shape, animateCfg) {
  var id = shape._id;
  var index = shape.get('index');
  var endState = {
    fillOpacity: 0,
    strokeOpacity: 0
  };
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, function () {
    shape.remove();
  }, animateParam.delay);
}

function fanIn(shape, animateCfg, coord) {
  var angle = getAngle(shape, coord);
  var endAngle = angle.endAngle;
  var startAngle = angle.startAngle;
  clipIn(shape, animateCfg, coord, startAngle, endAngle);
}

function lineSlideLeft(shape, animateCfg, coord) {
  if (shape.name !== 'line') {
    return;
  }

  var canvas = shape.get('canvas');
  var cache = shape.get('cacheShape');
  var id = shape._id;
  var index = shape.get('index');
  var clip = new G.Rect({
    attrs: {
      x: coord.start.x,
      y: coord.end.y,
      width: coord.getWidth(),
      height: coord.getHeight()
    }
  });
  clip.isClip = true;
  clip.set('canvas', canvas);
  var lastPath = PathUtil.pathToAbsolute(cache.attrs.path);
  var updatePath = PathUtil.pathToAbsolute(shape.attr('path'));
  var gap = lastPath[1][1] - lastPath[0][1]; // 生成过渡Path

  var pathPatchPosX = lastPath[lastPath.length - 1][1] + gap;
  var pathPatchPosY = updatePath[updatePath.length - 1][2];
  var transitionPath = lastPath.concat([['L', pathPatchPosX, pathPatchPosY]]);
  var v = [0, 0, 1];
  shape.apply(v);
  shape.attr('clip', clip);
  shape.attr('path', transitionPath);
  var endState = {
    transform: [['t', -gap, 0]]
  };
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, function () {
    if (shape && !shape.get('destroyed')) {
      shape.attr('path', updatePath);
      shape.attr({
        transform: [['t', gap, 0]]
      });
      shape.attr('clip', null);
      shape.setSilent('cacheShape', null);
      clip.remove();
    }
  }, animateParam.delay);
}

function areaSlideLeft(shape, animateCfg, coord) {
  if (shape.name !== 'area') {
    return;
  }

  var canvas = shape.get('canvas');
  var cache = shape.get('cacheShape');
  var id = shape._id;
  var index = shape.get('index');
  var clip = new G.Rect({
    attrs: {
      x: coord.start.x,
      y: coord.end.y,
      width: coord.getWidth(),
      height: coord.getHeight()
    }
  });
  clip.isClip = true;
  clip.set('canvas', canvas);
  var lastPath = PathUtil.pathToAbsolute(cache.attrs.path);
  var updatePath = PathUtil.pathToAbsolute(shape.attr('path'));
  var gap = lastPath[1][1] - lastPath[0][1]; // 生成过渡Path

  var middleIndex = Math.floor(lastPath.length / 2);
  var pathPatchPosX = lastPath[middleIndex - 1][1] + gap;
  var pathPatchPosY = updatePath[middleIndex - 1][2];
  var transitionPath = [].concat(lastPath.slice(0, middleIndex), [['L', pathPatchPosX, pathPatchPosY], ['L', pathPatchPosX, updatePath[middleIndex][2]]], lastPath.slice(middleIndex));
  var v = [0, 0, 1];
  shape.apply(v);
  shape.attr('clip', clip);
  shape.attr('path', transitionPath);
  var endState = {
    transform: [['t', -gap, 0]]
  };
  var animateParam = getAnimateParam(animateCfg, index, id, endState);
  shape.animate(endState, animateParam.duration, animateParam.easing, function () {
    if (shape && !shape.get('destroyed')) {
      shape.attr('path', updatePath);
      shape.attr({
        transform: [['t', gap, 0]]
      });
      shape.attr('clip', null);
      shape.setSilent('cacheShape', null);
      clip.remove();
    }
  }, animateParam.delay);
} // 默认动画库


module.exports = {
  enter: {
    clipIn: clipIn,
    zoomIn: zoomIn,
    pathIn: pathIn,
    scaleInY: scaleInY,
    scaleInX: scaleInX,
    fanIn: fanIn,
    fadeIn: fadeIn
  },
  leave: {
    lineWidthOut: lineWidthOut,
    zoomOut: zoomOut,
    pathOut: pathOut,
    fadeOut: fadeOut
  },
  appear: {
    clipIn: clipIn,
    zoomIn: zoomIn,
    pathIn: pathIn,
    scaleInY: scaleInY,
    scaleInX: scaleInX,
    fanIn: fanIn,
    fadeIn: fadeIn
  },
  update: {
    fadeIn: fadeIn,
    fanIn: fanIn,
    lineSlideLeft: lineSlideLeft,
    areaSlideLeft: areaSlideLeft
  }
};