/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/**
 * Single coordinates system.
 */

import SingleAxis from './SingleAxis';
import * as axisHelper from '../axisHelper';
import {getLayoutRect} from '../../util/layout';
import {each} from 'zrender/src/core/util';
import { CoordinateSystem, CoordinateSystemMaster } from '../CoordinateSystem';
import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../core/ExtensionAPI';
import BoundingRect from 'zrender/src/core/BoundingRect';
import SingleAxisModel from './AxisModel';
import { ParsedModelFinder, ParsedModelFinderKnown } from '../../util/model';
import { ScaleDataValue } from '../../util/types';
import { AxisBaseModel } from '../AxisBaseModel';
import { CategoryAxisBaseOption } from '../axisCommonTypes';

export const singleDimensions = ['single'];
/**
 * Create a single coordinates system.
 */
class Single implements CoordinateSystem, CoordinateSystemMaster {

    readonly type = 'single';

    readonly dimension = 'single';
    /**
     * Add it just for draw tooltip.
     */
    readonly dimensions = singleDimensions;

    name: string;

    axisPointerEnabled: boolean = true;

    model: SingleAxisModel;

    private _axis: SingleAxis;

    private _rect: BoundingRect;

    constructor(axisModel: SingleAxisModel, ecModel: GlobalModel, api: ExtensionAPI) {

        this.model = axisModel;

        this._init(axisModel, ecModel, api);
    }

    /**
     * Initialize single coordinate system.
     */
    _init(axisModel: SingleAxisModel, ecModel: GlobalModel, api: ExtensionAPI) {

        const dim = this.dimension;

        const axis = new SingleAxis(
            dim,
            axisHelper.createScaleByModel(axisModel),
            [0, 0],
            axisModel.get('type'),
            axisModel.get('position')
        );

        const isCategory = axis.type === 'category';
        axis.onBand = isCategory && (axisModel as AxisBaseModel<CategoryAxisBaseOption>).get('boundaryGap');
        axis.inverse = axisModel.get('inverse');
        axis.orient = axisModel.get('orient');

        axisModel.axis = axis;
        axis.model = axisModel;
        axis.coordinateSystem = this;
        this._axis = axis;
    }

    /**
     * Update axis scale after data processed
     */
    update(ecModel: GlobalModel, api: ExtensionAPI) {
        ecModel.eachSeries(function (seriesModel) {
            if (seriesModel.coordinateSystem === this) {
                const data = seriesModel.getData();
                each(data.mapDimensionsAll(this.dimension), function (dim) {
                    this._axis.scale.unionExtentFromData(data, dim);
                }, this);
                axisHelper.niceScaleExtent(this._axis.scale, this._axis.model);
            }
        }, this);
    }

    /**
     * Resize the single coordinate system.
     */
    resize(axisModel: SingleAxisModel, api: ExtensionAPI) {
        this._rect = getLayoutRect(
            {
                left: axisModel.get('left'),
                top: axisModel.get('top'),
                right: axisModel.get('right'),
                bottom: axisModel.get('bottom'),
                width: axisModel.get('width'),
                height: axisModel.get('height')
            },
            {
                width: api.getWidth(),
                height: api.getHeight()
            }
        );

        this._adjustAxis();
    }

    getRect() {
        return this._rect;
    }

    private _adjustAxis() {

        const rect = this._rect;
        const axis = this._axis;

        const isHorizontal = axis.isHorizontal();
        const extent = isHorizontal ? [0, rect.width] : [0, rect.height];
        const idx = axis.inverse ? 1 : 0;

        axis.setExtent(extent[idx], extent[1 - idx]);

        this._updateAxisTransform(axis, isHorizontal ? rect.x : rect.y);

    }


    private _updateAxisTransform(axis: SingleAxis, coordBase: number) {

        const axisExtent = axis.getExtent();
        const extentSum = axisExtent[0] + axisExtent[1];
        const isHorizontal = axis.isHorizontal();

        axis.toGlobalCoord = isHorizontal
            ? function (coord) {
                return coord + coordBase;
            }
            : function (coord) {
                return extentSum - coord + coordBase;
            };

        axis.toLocalCoord = isHorizontal
            ? function (coord) {
                return coord - coordBase;
            }
            : function (coord) {
                return extentSum - coord + coordBase;
            };
    }

    /**
     * Get axis.
     */
    getAxis() {
        return this._axis;
    }

    /**
     * Get axis, add it just for draw tooltip.
     */
    getBaseAxis() {
        return this._axis;
    }

    getAxes() {
        return [this._axis];
    }

    getTooltipAxes() {
        return {
            baseAxes: [this.getAxis()],
            // Empty otherAxes
            otherAxes: [] as SingleAxis[]
        };
    }

    /**
     * If contain point.
     */
    containPoint(point: number[]) {
        const rect = this.getRect();
        const axis = this.getAxis();
        const orient = axis.orient;
        if (orient === 'horizontal') {
            return axis.contain(axis.toLocalCoord(point[0]))
            && (point[1] >= rect.y && point[1] <= (rect.y + rect.height));
        }
        else {
            return axis.contain(axis.toLocalCoord(point[1]))
            && (point[0] >= rect.y && point[0] <= (rect.y + rect.height));
        }
    }

    pointToData(point: number[]) {
        const axis = this.getAxis();
        return [axis.coordToData(axis.toLocalCoord(
            point[axis.orient === 'horizontal' ? 0 : 1]
        ))];
    }

    /**
     * Convert the series data to concrete point.
     * Can be [val] | val
     */
    dataToPoint(val: ScaleDataValue | ScaleDataValue[]) {
        const axis = this.getAxis();
        const rect = this.getRect();
        const pt = [];
        const idx = axis.orient === 'horizontal' ? 0 : 1;

        if (val instanceof Array) {
            val = val[0];
        }

        pt[idx] = axis.toGlobalCoord(axis.dataToCoord(+val));
        pt[1 - idx] = idx === 0 ? (rect.y + rect.height / 2) : (rect.x + rect.width / 2);
        return pt;
    }

    convertToPixel(ecModel: GlobalModel, finder: ParsedModelFinder, value: ScaleDataValue[]) {
        const coordSys = getCoordSys(finder);
        return coordSys === this ? this.dataToPoint(value) : null;
    }

    convertFromPixel(ecModel: GlobalModel, finder: ParsedModelFinder, pixel: number[]) {
        const coordSys = getCoordSys(finder);
        return coordSys === this ? this.pointToData(pixel) : null;
    }
}

function getCoordSys(finder: ParsedModelFinderKnown): Single {
    const seriesModel = finder.seriesModel;
    const singleModel = finder.singleAxisModel as SingleAxisModel;
    return singleModel && singleModel.coordinateSystem
        || seriesModel && seriesModel.coordinateSystem as Single;
}

export default Single;
