/**
 * echarts图表类：散点图
 *
 * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。
 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
 *
 */
define(function (require) {
    var ChartBase = require('./base');
    
    // 图形依赖
    var SymbolShape = require('../util/shape/Symbol');
    // 组件依赖
    require('../component/axis');
    require('../component/grid');
    require('../component/dataZoom');
    require('../component/dataRange');
    
    var ecConfig = require('../config');
    // 散点图默认参数
    ecConfig.scatter = {
        zlevel: 0,                  // 一级层叠
        z: 2,                       // 二级层叠
        clickable: true,
        legendHoverLink: true,
        xAxisIndex: 0,
        yAxisIndex: 0,
        // symbol: null,        // 图形类型
        symbolSize: 4,          // 图形大小，半宽（半径）参数，当图形为方向或菱形则总宽度为symbolSize * 2
        // symbolRotate: null,  // 图形旋转控制
        large: false,           // 大规模散点图
        largeThreshold: 2000,   // 大规模阀值，large为true且数据量>largeThreshold才启用大规模模式
        itemStyle: {
            normal: {
                // color: 各异,
                label: {
                    show: false
                    // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调
                    // position: 默认自适应，水平布局为'top'，垂直布局为'right'，可选为
                    //           'inside'|'left'|'right'|'top'|'bottom'
                    // textStyle: null      // 默认使用全局文本样式，详见TEXTSTYLE
                }
            },
            emphasis: {
                // color: '各异'
                label: {
                    show: false
                    // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调
                    // position: 默认自适应，水平布局为'top'，垂直布局为'right'，可选为
                    //           'inside'|'left'|'right'|'top'|'bottom'
                    // textStyle: null      // 默认使用全局文本样式，详见TEXTSTYLE
                }
            }
        }
    };

    var zrUtil = require('zrender/tool/util');
    var zrColor = require('zrender/tool/color');
    
    /**
     * 构造函数
     * @param {Object} messageCenter echart消息中心
     * @param {ZRender} zr zrender实例
     * @param {Object} series 数据
     * @param {Object} component 组件
     */
    function Scatter(ecTheme, messageCenter, zr, option, myChart){
        // 图表基类
        ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);

        this.refresh(option);
    }
    
    Scatter.prototype = {
        type: ecConfig.CHART_TYPE_SCATTER,
        /**
         * 绘制图形
         */
        _buildShape: function () {
            var series = this.series;
            this._sIndex2ColorMap = {};  // series默认颜色索引，seriesIndex索引到color
            this._symbol = this.option.symbolList;
            this._sIndex2ShapeMap = {};  // series图形类型，seriesIndex索引到_symbol
            
            this.selectedMap = {};
            this.xMarkMap = {};
            
            var legend = this.component.legend;
            var seriesArray = [];
            var serie;                              // 临时映射变量
            var serieName;                          // 临时映射变量
            var iconShape;
            var iconType;
            for (var i = 0, l = series.length; i < l; i++) {
                serie = series[i];
                serieName = serie.name;
                if (serie.type === ecConfig.CHART_TYPE_SCATTER) {
                    series[i] = this.reformOption(series[i]);
                    this.legendHoverLink = series[i].legendHoverLink || this.legendHoverLink;
                    this._sIndex2ShapeMap[i] = this.query(serie, 'symbol')
                                          || this._symbol[i % this._symbol.length];
                    if (legend){
                        this.selectedMap[serieName] = legend.isSelected(serieName);
                        this._sIndex2ColorMap[i] = zrColor.alpha(legend.getColor(serieName), 0.5);
                            
                        iconShape = legend.getItemShape(serieName);
                        if (iconShape) {
                            // 回调legend，换一个更形象的icon
                            var iconType = this._sIndex2ShapeMap[i];
                            iconShape.style.brushType = iconType.match('empty') ? 'stroke' : 'both';
                            iconType = iconType.replace('empty', '').toLowerCase();
                            
                            if (iconType.match('rectangle')) {
                                iconShape.style.x += Math.round(
                                    (iconShape.style.width - iconShape.style.height) / 2
                                );
                                iconShape.style.width = iconShape.style.height;
                            }
                            
                            if (iconType.match('star')) {
                                iconShape.style.n = (iconType.replace('star','') - 0) || 5;
                                iconType = 'star';
                            }
                            
                            if (iconType.match('image')) {
                                iconShape.style.image = iconType.replace(
                                    new RegExp('^image:\\/\\/'), ''
                                );
                                iconShape.style.x += Math.round(
                                    (iconShape.style.width - iconShape.style.height) / 2
                                );
                                iconShape.style.width = iconShape.style.height;
                                iconType = 'image';
                            }
            
                            iconShape.style.iconType = iconType;
                            legend.setItemShape(serieName, iconShape);
                        }
                    } 
                    else {
                        this.selectedMap[serieName] = true;
                        this._sIndex2ColorMap[i] = zrColor.alpha(this.zr.getColor(i), 0.5);
                    }
                      
                    if (this.selectedMap[serieName]) {
                        seriesArray.push(i);
                    }
                }
            }
            
            this._buildSeries(seriesArray);
            
            this.addShapeList();
        },

        /**
         * 构建类目轴为水平方向的散点图系列
         */
        _buildSeries: function (seriesArray) {
            if (seriesArray.length === 0) {
                return;
            }
            var series = this.series;
            var seriesIndex;
            var serie;
            var data;
            var value;
            var xAxis;
            var yAxis; 

            var pointList = {};
            var x;
            var y;
            for (var j = 0, k = seriesArray.length; j < k; j++) {
                seriesIndex = seriesArray[j];
                serie = series[seriesIndex];
                if (serie.data.length === 0) {
                    continue;
                }
                
                xAxis = this.component.xAxis.getAxis(serie.xAxisIndex || 0);
                yAxis = this.component.yAxis.getAxis(serie.yAxisIndex || 0);
                
                pointList[seriesIndex] = [];
                for (var i = 0, l = serie.data.length; i < l; i++) {
                    data = serie.data[i];
                    value = this.getDataFromOption(data, '-');
                    if (value === '-' || value.length < 2) {
                        // 数据格式不符
                        continue;
                    }
                    x = xAxis.getCoord(value[0]);
                    y = yAxis.getCoord(value[1]);
                    pointList[seriesIndex].push([
                        x,                  // 横坐标
                        y,                  // 纵坐标
                        i,                  // 数据index
                        data.name || ''     // 名称
                    ]);
                    
                }
                this.xMarkMap[seriesIndex] = this._markMap(
                    xAxis, yAxis, serie.data, pointList[seriesIndex]
                ); 
                this.buildMark(seriesIndex);
            }
            
            // console.log(pointList)
            this._buildPointList(pointList);
        },
        
        _markMap: function (xAxis, yAxis, data, pointList) {
            var xMarkMap = {
                min0: Number.POSITIVE_INFINITY,
                max0: Number.NEGATIVE_INFINITY,
                sum0: 0,
                counter0: 0,
                average0: 0,
                min1: Number.POSITIVE_INFINITY,
                max1: Number.NEGATIVE_INFINITY,
                sum1: 0,
                counter1: 0,
                average1: 0
            };
            var value;
            for (var i = 0, l = pointList.length; i < l; i++) {
                /**
                x,                  // 横坐标
                y,                  // 纵坐标
                i,                  // 数据index
                data.name || ''     // 名称 
                 */
                value = data[pointList[i][2]].value || data[pointList[i][2]];
                // 横轴
                if (xMarkMap.min0 > value[0]) {
                    xMarkMap.min0 = value[0];
                    xMarkMap.minY0 = pointList[i][1];
                    xMarkMap.minX0 = pointList[i][0];
                }
                if (xMarkMap.max0 < value[0]) {
                    xMarkMap.max0 = value[0];
                    xMarkMap.maxY0 = pointList[i][1];
                    xMarkMap.maxX0 = pointList[i][0];
                }
                xMarkMap.sum0 += value[0];
                xMarkMap.counter0++;
                
                // 纵轴
                if (xMarkMap.min1 > value[1]) {
                    xMarkMap.min1 = value[1];
                    xMarkMap.minY1 = pointList[i][1];
                    xMarkMap.minX1 = pointList[i][0];
                }
                if (xMarkMap.max1 < value[1]) {
                    xMarkMap.max1 = value[1];
                    xMarkMap.maxY1 = pointList[i][1];
                    xMarkMap.maxX1 = pointList[i][0];
                }
                xMarkMap.sum1 += value[1];
                xMarkMap.counter1++;
            }
            
            var gridX = this.component.grid.getX();
            var gridXend = this.component.grid.getXend();
            var gridY = this.component.grid.getY();
            var gridYend = this.component.grid.getYend();
            
            xMarkMap.average0 = xMarkMap.sum0 / xMarkMap.counter0;
            var x = xAxis.getCoord(xMarkMap.average0); 
            // 横轴平均纵向
            xMarkMap.averageLine0 = [
                [x, gridYend],
                [x, gridY]
            ];
            xMarkMap.minLine0 = [
                [xMarkMap.minX0, gridYend],
                [xMarkMap.minX0, gridY]
            ];
            xMarkMap.maxLine0 = [
                [xMarkMap.maxX0, gridYend],
                [xMarkMap.maxX0, gridY]
            ];
            
            xMarkMap.average1 = xMarkMap.sum1 / xMarkMap.counter1;
            var y = yAxis.getCoord(xMarkMap.average1);
            // 纵轴平均横向
            xMarkMap.averageLine1 = [
                [gridX, y],
                [gridXend, y]
            ];
            xMarkMap.minLine1 = [
                [gridX, xMarkMap.minY1],
                [gridXend, xMarkMap.minY1]
            ];
            xMarkMap.maxLine1 = [
                [gridX, xMarkMap.maxY1],
                [gridXend, xMarkMap.maxY1]
            ];
            
            return xMarkMap;
        },
        
        /**
         * 生成折线和折线上的拐点
         */
        _buildPointList: function (pointList) {
            var series = this.series;
            var serie;
            var seriesPL;
            var singlePoint;
            var shape;
            for (var seriesIndex in pointList) {
                serie = series[seriesIndex];
                seriesPL = pointList[seriesIndex];                
                if (serie.large && serie.data.length > serie.largeThreshold) {
                    this.shapeList.push(this._getLargeSymbol(
                        serie,
                        seriesPL, 
                        this.getItemStyleColor(
                            this.query(
                                serie, 'itemStyle.normal.color'
                            ),
                            seriesIndex,
                            -1
                        ) || this._sIndex2ColorMap[seriesIndex]
                    ));
                    continue;
                }

                /*
                 * pointlist=[
                 *      0  x,
                 *      1  y, 
                 *      2  数据index
                 *      3  名称
                 * ]
                 */
                
                for (var i = 0, l = seriesPL.length; i < l; i++) {
                    singlePoint = seriesPL[i];
                    shape = this._getSymbol(
                        seriesIndex,    // seriesIndex
                        singlePoint[2], // dataIndex
                        singlePoint[3], // name
                        singlePoint[0], // x
                        singlePoint[1]  // y
                    );
                    shape && this.shapeList.push(shape);
                }
            }
            // console.log(this.shapeList)
        },

        /**
         * 生成折线图上的拐点图形
         */
        _getSymbol: function (seriesIndex, dataIndex, name, x, y) {
            var series = this.series;
            var serie = series[seriesIndex];
            var data = serie.data[dataIndex];
            
            var dataRange = this.component.dataRange;
            var rangColor;
            if (dataRange) {
                rangColor = isNaN(data[2]) 
                            ? this._sIndex2ColorMap[seriesIndex]
                            : dataRange.getColor(data[2]);
                if (!rangColor) {
                    return null;
                }
            }
            else {
                rangColor = this._sIndex2ColorMap[seriesIndex];
            }
            
            var itemShape = this.getSymbolShape(
                serie, seriesIndex, data, dataIndex, name, 
                x, y,
                this._sIndex2ShapeMap[seriesIndex], 
                rangColor,
                'rgba(0,0,0,0)',
                'vertical'
            );
            itemShape.zlevel = serie.zlevel;
            itemShape.z = serie.z;
            
            itemShape._main = true;
            return itemShape;
        },
        
        _getLargeSymbol: function (serie, pointList, nColor) {
            return new SymbolShape({
                zlevel: serie.zlevel,
                z: serie.z,
                _main: true,
                hoverable: false,
                style: {
                    pointList: pointList,
                    color: nColor,
                    strokeColor: nColor
                },
                highlightStyle: {
                    pointList: []
                }
            });
        },
        
        // 位置转换
        getMarkCoord: function (seriesIndex, mpData) {
            var serie = this.series[seriesIndex];
            var xMarkMap = this.xMarkMap[seriesIndex];
            var xAxis = this.component.xAxis.getAxis(serie.xAxisIndex);
            var yAxis = this.component.yAxis.getAxis(serie.yAxisIndex);
            var pos;
            
            if (mpData.type
                && (mpData.type === 'max' || mpData.type === 'min' || mpData.type === 'average')
            ) {
                // 特殊值内置支持
                // 默认取纵值
                var valueIndex = mpData.valueIndex != null ? mpData.valueIndex : 1;
                pos = [
                    xMarkMap[mpData.type + 'X' + valueIndex],
                    xMarkMap[mpData.type + 'Y' + valueIndex],
                    xMarkMap[mpData.type + 'Line' + valueIndex],
                    xMarkMap[mpData.type + valueIndex]
                ];
            }
            else {
                pos = [
                    typeof mpData.xAxis != 'string' && xAxis.getCoordByIndex
                        ? xAxis.getCoordByIndex(mpData.xAxis || 0)
                        : xAxis.getCoord(mpData.xAxis || 0),
                    
                    typeof mpData.yAxis != 'string' && yAxis.getCoordByIndex
                        ? yAxis.getCoordByIndex(mpData.yAxis || 0)
                        : yAxis.getCoord(mpData.yAxis || 0)
                ];
            }
            
            return pos;
        },

        /**
         * 刷新
         */
        refresh: function (newOption) {
            if (newOption) {
                this.option = newOption;
                this.series = newOption.series;
            }
            
            this.backupShapeList();
            this._buildShape();
        },
        
        /**
         * 值域响应
         * @param {Object} param
         * @param {Object} status
         */
        ondataRange: function (param, status) {
            if (this.component.dataRange) {
                this.refresh();
                status.needRefresh = true;
            }
            return;
        }
    };
    
    zrUtil.inherits(Scatter, ChartBase);
    
    // 图表注册
    require('../chart').define('scatter', Scatter);
    
    return Scatter;
});