import ComponentModel from './Component';
import { each, isArray, isObject, find, filter } from '../util';
import { registerComponent } from '../d3charts';
import { seriesActions } from '../action/event';

const TYPE = 'series';

/**
 * 图表Model类
 * 
 * @class SeriesModel
 * @extends {ComponentModel}
 */
class SeriesModel extends ComponentModel {

    static type = TYPE;

    type = TYPE;

    constructor() {
        super(...arguments);
        
        this.global.registerAction(this, seriesActions.unselected, () => {
            this.onUnSelected && this.onUnSelected();
        })
    }

    /**
     * 获取对应的颜色
     * 
     * @param {string} [name] 获取name对应的颜色
     * @returns {string} color
     */
    getSeriesColor(name) {
        let itemStyle, color;

        if (arguments.length && this.get('name') !== name) {
            let finded = this.findDataNamed(name);

            if (finded) {
                itemStyle = finded.itemStyle;
                color = finded.color;
            }
        } else {
            itemStyle = this.get('itemStyle');
            color = this.get('color');
        }

        if (color) {
            return color;
        } else if (itemStyle && itemStyle.normal) {
            return itemStyle.normal.stroke || itemStyle.normal.fill;
        }
    }

    /**
     * 寻找name对应的数据项
     * 
     * @param {string} name 
     * @returns {any} data
     */
    findDataNamed(name) {
        let data = this.getData();

        if (isObject(data) && !isArray(data)) {
            let _data = data.values || data.value || data.data;

            if (typeof _data !== 'undefined') {
                data = _data
            }

            !isArray(data) && (data = [data]);
        }

        return findArrayNamed(data, name);
    }

    /**
     * 获取范围内的极值
     * 
     * @param {string} type 'max' or 'min' 获取最大值、最小值还是平均值
     * @param {string} valueDim 指定维度
     * @param {number} valueIndex 指定维度是数组
     * @param {boolean} needFilter 是否根据axis进行范围外过滤,依赖于axis
     * @returns data
     */
    getDataExtent(type, valueDim = 1, valueIndex = 0, needFilter = true) {
        let data = this.getData();

        function filterData(axisModel) {
            if (axisModel) {
                let valueIndex = axisModel.get('xOrY') === 'x' ? 0 : 1;

                if (axisModel.getAxisType() === 'ordinal') {
                    let { startIndex, endIndex } = axisModel;

                    data = filter(data, function (d) {
                        return d[valueIndex] >= startIndex && d[valueIndex] <= endIndex;
                    });
                } else {
                    let domain0 = axisModel.domain[0];
                    let domain1 = axisModel.domain[1];

                    data = filter(data, function (d) {
                        return d[valueIndex] >= domain0 && d[valueIndex] <= domain1;
                    });
                }
            }
        }
        
        if (needFilter) {
            filterData(this.getAxisModel('x'));
            this.get('type') === 'scatter' && filterData(this.getAxisModel('y'));
        }

        let dataLen = data.length;

        if (type === 'average') {
            let sum = 0;

            for (let i = 0; i < dataLen; i++) {
                let d = data[i][valueDim];

                isArray(d) && (d = d[valueIndex]);
                sum += d;
            }

            return sum / dataLen;
        } else {
            let isMax = type === 'max';
            let ext = isMax ? -Infinity : Infinity;
            let extIndex;

            for (let i = 0; i < dataLen; i++) {
                let d = data[i][valueDim];

                isArray(d) && (d = d[valueIndex]);

                if (isMax) {
                    ext < d && (ext = d, extIndex = i);
                } else {
                    ext > d && (ext = d, extIndex = i);
                }
            }

            return [data[extIndex], ext];
        }
    }

}

function findArrayNamed(array, name) {
    return find(array, function (item) {
        return item.name === name;
    });
}

registerComponent(SeriesModel);

export default SeriesModel;