/**
 * Symbol with ripple effect
 * @module echarts/chart/helper/EffectSymbol
 */
define(function (require) {

    var zrUtil = require('zrender/core/util');
    var symbolUtil = require('../../util/symbol');
    var graphic = require('../../util/graphic');
    var numberUtil = require('../../util/number');
    var Symbol = require('./Symbol');
    var Group = graphic.Group;

    var EFFECT_RIPPLE_NUMBER = 3;

    function normalizeSymbolSize(symbolSize) {
        if (!zrUtil.isArray(symbolSize)) {
            symbolSize = [+symbolSize, +symbolSize];
        }
        return symbolSize;
    }
    /**
     * @constructor
     * @param {module:echarts/data/List} data
     * @param {number} idx
     * @extends {module:zrender/graphic/Group}
     */
    function EffectSymbol(data, idx) {
        Group.call(this);

        var symbol = new Symbol(data, idx);
        var rippleGroup = new Group();
        this.add(symbol);
        this.add(rippleGroup);

        rippleGroup.beforeUpdate = function () {
            this.attr(symbol.getScale());
        };
        this.updateData(data, idx);
    }

    var effectSymbolProto = EffectSymbol.prototype;

    effectSymbolProto.stopEffectAnimation = function () {
        this.childAt(1).removeAll();
    };

    effectSymbolProto.startEffectAnimation = function (
        period, brushType, rippleScale, effectOffset, z, zlevel
    ) {
        var symbolType = this._symbolType;
        var color = this._color;

        var rippleGroup = this.childAt(1);

        for (var i = 0; i < EFFECT_RIPPLE_NUMBER; i++) {
            var ripplePath = symbolUtil.createSymbol(
                symbolType, -0.5, -0.5, 1, 1, color
            );
            ripplePath.attr({
                style: {
                    stroke: brushType === 'stroke' ? color : null,
                    fill: brushType === 'fill' ? color : null,
                    strokeNoScale: true
                },
                z2: 99,
                silent: true,
                scale: [1, 1],
                z: z,
                zlevel: zlevel
            });

            var delay = -i / EFFECT_RIPPLE_NUMBER * period + effectOffset;
            // TODO Configurable period
            ripplePath.animate('', true)
                .when(period, {
                    scale: [rippleScale, rippleScale]
                })
                .delay(delay)
                .start();
            ripplePath.animateStyle(true)
                .when(period, {
                    opacity: 0
                })
                .delay(delay)
                .start();

            rippleGroup.add(ripplePath);
        }
    };

    /**
     * Highlight symbol
     */
    effectSymbolProto.highlight = function () {
        this.trigger('emphasis');
    };

    /**
     * Downplay symbol
     */
    effectSymbolProto.downplay = function () {
        this.trigger('normal');
    };

    /**
     * Update symbol properties
     * @param  {module:echarts/data/List} data
     * @param  {number} idx
     */
    effectSymbolProto.updateData = function (data, idx) {
        var seriesModel = data.hostModel;

        this.childAt(0).updateData(data, idx);

        var rippleGroup = this.childAt(1);
        var itemModel = data.getItemModel(idx);
        var symbolType = data.getItemVisual(idx, 'symbol');
        var symbolSize = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize'));
        var color = data.getItemVisual(idx, 'color');

        rippleGroup.attr('scale', symbolSize);

        rippleGroup.traverse(function (ripplePath) {
            ripplePath.attr({
                fill: color
            });
        });

        var symbolOffset = itemModel.getShallow('symbolOffset');
        if (symbolOffset) {
            var pos = rippleGroup.position;
            pos[0] = numberUtil.parsePercent(symbolOffset[0], symbolSize[0]);
            pos[1] = numberUtil.parsePercent(symbolOffset[1], symbolSize[1]);
        }
        rippleGroup.rotation = (itemModel.getShallow('symbolRotate') || 0) * Math.PI / 180 || 0;

        this._symbolType = symbolType;
        this._color = color;

        var showEffectOn = seriesModel.get('showEffectOn');
        var rippleScale = itemModel.get('rippleEffect.scale');
        var brushType = itemModel.get('rippleEffect.brushType');
        var effectPeriod = itemModel.get('rippleEffect.period') * 1000;
        var effectOffset = idx / data.count();
        var z = itemModel.getShallow('z') || 0;
        var zlevel = itemModel.getShallow('zlevel') || 0;

        this.stopEffectAnimation();
        if (showEffectOn === 'render') {
            this.startEffectAnimation(
                effectPeriod, brushType, rippleScale, effectOffset, z, zlevel
            );
        }
        var symbol = this.childAt(0);
        function onEmphasis() {
            symbol.trigger('emphasis');
            if (showEffectOn !== 'render') {
                this.startEffectAnimation(
                    effectPeriod, brushType, rippleScale, effectOffset, z, zlevel
                );
            }
        }
        function onNormal() {
            symbol.trigger('normal');
            if (showEffectOn !== 'render') {
                this.stopEffectAnimation();
            }
        }
        this.on('mouseover', onEmphasis, this)
            .on('mouseout', onNormal, this)
            .on('emphasis', onEmphasis, this)
            .on('normal', onNormal, this);
    };

    effectSymbolProto.fadeOut = function (cb) {
        this.off('mouseover').off('mouseout').off('emphasis').off('normal');
        cb && cb();
    };

    zrUtil.inherits(EffectSymbol, Group);

    return EffectSymbol;
});
