import { degreeToRadian, isNil, isValidNumber, merge } from "@visactor/vutils";

import { LineAxis } from "./../../vrender";

import { getAxisAttributes, getCommonAxis } from "./get-axis-attributes";

import { isXAxis, isYAxis } from "../util/orient";

import { BandAxisScale } from "./band-scale";

import { registerDataSetInstanceParser, registerDataSetInstanceTransform } from "../util/register";

import { DataSet, DataView } from "@visactor/vdataset";

import { ticks } from "./../../vrender";

import { LinearAxisScale } from "./linear-scale";

import { doOverlap } from "./label-overlap";

const DEFAULT_BAND_INNER_PADDING = .1, DEFAULT_BAND_OUTER_PADDING = .3, scaleParser = scale => scale;

export class CartesianAxis {
    constructor(option, width, height, bodyChartCellPadding, table) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j;
        if (this.x = 0, this.y = 0, this.bodyChartCellPadding = bodyChartCellPadding, this.table = table, 
        this.orient = null !== (_a = option.orient) && void 0 !== _a ? _a : "left", this.type = null !== (_b = option.type) && void 0 !== _b ? _b : "band", 
        this.option = merge({}, getCommonAxis(option.__vtableChartTheme), getTableAxisTheme(this.orient, table.theme), getChartSpecAxisTheme(this.orient, this.type, option.__vtableChartTheme), option), 
        "left" === this.orient || "right" === this.orient) {
            const innerOffsetTop = 0, innerOffsetBottom = 0;
            "left" === this.orient && (this.x = null !== (_c = this.option.cellPaddingLeft) && void 0 !== _c ? _c : 0, 
            this.width = width - (null !== (_d = this.option.cellPaddingLeft) && void 0 !== _d ? _d : 0)), 
            "right" === this.orient && (this.x = 0, this.width = width - (null !== (_e = this.option.cellPaddingRight) && void 0 !== _e ? _e : 0)), 
            this.height = height - bodyChartCellPadding[0] - bodyChartCellPadding[2] - innerOffsetBottom, 
            this.y = bodyChartCellPadding[0] + innerOffsetTop;
        } else if ("top" === this.orient || "bottom" === this.orient) {
            const innerOffsetLeft = 0, innerOffsetRight = 0;
            this.width = width - bodyChartCellPadding[1] - bodyChartCellPadding[3] - innerOffsetRight, 
            this.x = bodyChartCellPadding[3] + innerOffsetLeft, "top" === this.orient && (this.y = null !== (_f = this.option.cellPaddingTop) && void 0 !== _f ? _f : 0, 
            this.height = height - (null !== (_g = this.option.cellPaddingTop) && void 0 !== _g ? _g : 0)), 
            "bottom" === this.orient && (this.y = 0, this.height = height - (null !== (_h = this.option.cellPaddingBottom) && void 0 !== _h ? _h : 0));
        }
        this.visible = null === (_j = option.visible) || void 0 === _j || _j, this.inverse = "inverse" in option && !!option.inverse, 
        "band" === option.type && (this.data = option.domain), this.initScale(), this.initData(), 
        this.createComponent(), this.initEvent();
    }
    initScale() {
        const option = this.option;
        "band" === this.type || "point" === this.type ? (this.scale = new BandAxisScale, 
        this.scale.bandPadding = option.bandPadding, this.scale.paddingInner = option.paddingInner, 
        this.scale.paddingOuter = option.paddingOuter, this.scale.calcScales(.1, .3), this.scale.updateScaleDomain(this.data), 
        this.updateScaleRange()) : "linear" !== this.type && "time" !== this.type && "log" !== this.type && "symlog" !== this.type || (this.scale = new LinearAxisScale(this.type), 
        this.scale.setExtraAttrFromSpec(option.nice, option.zero, option.range, option.expand, option.base, option.constant), 
        this.scale.transformScaleDomain(), this.scale.updateScaleDomain(), this.updateScaleRange());
    }
    initData() {
        this.table._vDataSet || (this.table._vDataSet = new DataSet), registerDataSetInstanceParser(this.table._vDataSet, "scale", scaleParser), 
        registerDataSetInstanceTransform(this.table._vDataSet, "ticks", ticks);
        const label = this.option.label || {}, tick = this.option.tick || {}, tickData = new DataView(this.table._vDataSet).parse(this.scale._scale, {
            type: "scale"
        }).transform({
            type: "ticks",
            options: {
                sampling: !1 !== this.option.sampling,
                tickCount: tick.tickCount,
                forceTickCount: tick.forceTickCount,
                tickStep: tick.tickStep,
                tickMode: tick.tickMode,
                noDecimals: tick.noDecimals,
                axisOrientType: this.orient,
                coordinateType: "cartesian",
                labelStyle: label.style,
                labelFormatter: label.formatMethod,
                labelGap: label.minGap,
                labelLastVisible: label.lastVisible,
                labelFlush: label.flush
            }
        }, !1);
        this.tickData = tickData, this.computeData();
    }
    computeData() {
        this.tickData.reRunAllTransform();
    }
    initEvent() {}
    createComponent() {
        const axisStylrAttrs = getAxisAttributes(this.option), attrs = this.getUpdateAttribute();
        attrs.verticalFactor = "top" === this.orient || "right" === this.orient ? -1 : 1, 
        this.component = new LineAxis(merge({
            disableTriggerEvent: this.table.options.disableInteraction
        }, axisStylrAttrs, attrs)), this.component.setAttributes(this.setLayoutStartPosition({
            x: this.x,
            y: this.y
        })), this.component.originAxis = this;
    }
    resize(width, height) {
        var _a, _b, _c, _d;
        "left" === this.orient ? this.width = width - (null !== (_a = this.option.cellPaddingLeft) && void 0 !== _a ? _a : 0) : "right" === this.orient ? this.width = width - (null !== (_b = this.option.cellPaddingRight) && void 0 !== _b ? _b : 0) : "top" !== this.orient && "bottom" !== this.orient || (this.width = width - (this.bodyChartCellPadding[1] + this.bodyChartCellPadding[3])), 
        "top" === this.orient ? this.height = height - (null !== (_c = this.option.cellPaddingTop) && void 0 !== _c ? _c : 0) : "bottom" === this.orient ? this.height = height - (null !== (_d = this.option.cellPaddingBottom) && void 0 !== _d ? _d : 0) : "left" !== this.orient && "right" !== this.orient || (this.height = height - (this.bodyChartCellPadding[2] + this.bodyChartCellPadding[0])), 
        this.updateScaleRange(), this.computeData();
        const axisStylrAttrs = getAxisAttributes(this.option), attrs = this.getUpdateAttribute();
        attrs.verticalFactor = "top" === this.orient || "right" === this.orient ? -1 : 1, 
        this.component.setAttributes(merge({}, axisStylrAttrs, attrs)), this.component.setAttributes(this.setLayoutStartPosition({
            x: this.x,
            y: this.y
        })), this.overlap();
    }
    overlap() {
        doOverlap(this.component, this);
    }
    getLayoutRect() {
        return {
            width: this.width,
            height: this.height
        };
    }
    getUpdateAttribute() {
        const regionHeight = this.table.tableNoFrameHeight, regionWidth = this.table.tableNoFrameWidth, {width: width, height: height} = this.getLayoutRect(), isX = isXAxis(this.orient), isY = isYAxis(this.orient);
        let end = {
            x: 0,
            y: 0
        }, gridLength = 0, axisLength = 0;
        isX ? (end = {
            x: width,
            y: 0
        }, gridLength = regionHeight, axisLength = width) : isY && (end = {
            x: 0,
            y: height
        }, gridLength = regionWidth, axisLength = height);
        const size = "top" === this.orient || "bottom" === this.orient ? height : width;
        return {
            start: {
                x: 0,
                y: 0
            },
            end: end,
            title: {
                text: this.option.title.text,
                maxWidth: this._getTitleLimit(isX)
            },
            items: this.getLabelItems(axisLength),
            verticalLimitSize: size,
            verticalMinSize: size
        };
    }
    getLabelItems(length) {
        return [ this.tickData.latestData.map((obj => ({
            id: obj.value,
            label: obj.value,
            value: 0 === length ? 0 : this.scale.dataToPosition([ obj.value ]) / length,
            rawValue: obj.value
        }))).filter((entry => entry.value >= 0 && entry.value <= 1)) ];
    }
    updateScaleRange() {
        var _a, _b, _c, _d, _e, _f, _g, _h;
        const right = null !== (_b = null === (_a = this.option.innerOffset) || void 0 === _a ? void 0 : _a.right) && void 0 !== _b ? _b : 0, left = null !== (_d = null === (_c = this.option.innerOffset) || void 0 === _c ? void 0 : _c.left) && void 0 !== _d ? _d : 0, top = null !== (_f = null === (_e = this.option.innerOffset) || void 0 === _e ? void 0 : _e.top) && void 0 !== _f ? _f : 0, bottom = null !== (_h = null === (_g = this.option.innerOffset) || void 0 === _g ? void 0 : _g.bottom) && void 0 !== _h ? _h : 0, {width: width, height: height} = this.getLayoutRect(), inverse = this.option.inverse || !1;
        let newRange = [ 0, 0 ];
        isXAxis(this.orient) ? isValidNumber(width) && (newRange = inverse ? [ width - right, left ] : [ left, width - right ]) : isValidNumber(height) && (newRange = inverse ? [ top, height - bottom ] : [ height - bottom, top ]), 
        this.scale.updateRange(newRange);
    }
    setLayoutStartPosition(pos) {
        let {x: x, y: y} = pos;
        return isValidNumber(x) && (x += Number("left" === this.orient) * this.getLayoutRect().width), 
        isValidNumber(y) && (y += Number("top" === this.orient) * this.getLayoutRect().height), 
        {
            x: x,
            y: y
        };
    }
    _getTitleLimit(isX) {
        var _a, _b, _c;
        if (this.option.title.visible && isNil(null === (_a = this.option.title.style) || void 0 === _a ? void 0 : _a.maxLineWidth)) {
            let angle = (null === (_b = this.option.title.style) || void 0 === _b ? void 0 : _b.angle) || 0;
            if ((null === (_c = this.option.title) || void 0 === _c ? void 0 : _c.autoRotate) && isNil(this.option.title.angle) && (angle = "left" === this.option.orient ? -90 : 90), 
            isX) {
                const width = this.getLayoutRect().width, cosValue = Math.abs(Math.cos(degreeToRadian(angle)));
                return cosValue < 1e-6 ? 1 / 0 : width / cosValue;
            }
            const height = this.getLayoutRect().height, sinValue = Math.abs(Math.sin(degreeToRadian(angle)));
            return sinValue < 1e-6 ? 1 / 0 : height / sinValue;
        }
        return null;
    }
    getScale() {
        return this.scale._scale;
    }
    getDomainSpec() {
        return this.scale.domain;
    }
}

export function getTableAxisTheme(orient, theme) {
    let directionStyle;
    return "left" === orient ? directionStyle = theme.axisStyle.leftAxisStyle : "right" === orient ? directionStyle = theme.axisStyle.rightAxisStyle : "top" === orient ? directionStyle = theme.axisStyle.topAxisStyle : "bottom" === orient && (directionStyle = theme.axisStyle.bottomAxisStyle), 
    merge({}, theme.axisStyle.defaultAxisStyle, directionStyle);
}

function getChartSpecAxisTheme(orient, type, chartSpecTheme) {
    if (!chartSpecTheme) return {};
    const axisTheme = chartSpecTheme.axis;
    let axisTypeTheme, axisOrientTheme;
    return "linear" === type || "log" === type || "symlog" === type ? axisTypeTheme = chartSpecTheme.axisLinear : "band" === type && (axisTypeTheme = chartSpecTheme.axisBand), 
    "top" === orient || "bottom" === orient ? axisOrientTheme = chartSpecTheme.axisX : "left" !== orient && "right" !== orient || (axisOrientTheme = chartSpecTheme.axisY), 
    merge({}, axisTheme, axisTypeTheme, axisOrientTheme);
}
//# sourceMappingURL=axis.js.map
