import { path } from 'd3-path';
import { ReadableElement } from '../base/readable-element';
import { RotationDirectionType } from '../../model/shared/rotation/rotation-direction-type';
import { calculatePercent, degreesToRadians } from '../shared/math-utils';
import { VariableUtil } from '../../utils/variable-util';
import { VariableDefinition } from '../../communication/variable/variable-definition';
import { forEach } from 'lodash';
import { VariableState } from '../../communication';
import { VariableValueType } from '../../model/shared/condition/variable-value-type';
export class RingGraphElement extends ReadableElement {
    constructor(element, permissionChecker, variableCommunicator, variableStore, localization, signalRAppId) {
        super(element, permissionChecker, variableCommunicator, variableStore, localization, signalRAppId);
        this.valueObj = {};
        this.isNeedUpdateScale = false;
        this.initTransform = false;
        this.needAddNumber = 0;
        if ((this.model.minValueType === VariableValueType.Constant && this.model.maxValueType === VariableValueType.Variable)
            || this.model.maxValueType === VariableValueType.Constant && this.model.minValueType === VariableValueType.Variable) {
            this.isNeedUpdateScale = true;
            this.updateScale();
            this.isNeedUpdateScale = false;
        }
        const el$ = $(element);
        this._barElement$ = el$.find('path[data-id="barArc"]');
        this._textElement$ = el$.find('text[data-id="pText"]');
        setTimeout(() => {
            if (this.model.minValueType !== VariableValueType.Variable) {
                this.initFrameNode();
            }
            this.changeStates();
        });
    }
    get readVariableName() {
        if (!this.model.variableId) {
            return '';
        }
        if (!this.model.variableId.variableName || !this.model.variableId.variableName.name) {
            return undefined;
        }
        const variable = new VariableDefinition(this.model.variableId.variableName.name, this.model.variableId.variableName.groupName, this.model.variableId.dataSourceCode, this.model.variableId.variableName.variableVersion);
        return VariableUtil.getConvertedVariableName(this.variableStore, variable);
    }
    get minVariableName() {
        if (!this.model.minValueType) {
            return undefined;
        }
        if (!this.model.minVariable || !this.model.minVariable.name) {
            return undefined;
        }
        const variable = new VariableDefinition(this.model.minVariable.name, this.model.minVariable.groupName, this.model.minVariable.dataSourceCode, this.model.minVariable.variableVersion);
        return VariableUtil.getConvertedVariableName(this.variableStore, variable);
    }
    get maxVariableName() {
        if (!this.model.maxValueType) {
            return undefined;
        }
        if (!this.model.maxVariable || !this.model.maxVariable.name) {
            return undefined;
        }
        const variable = new VariableDefinition(this.model.maxVariable.name, this.model.maxVariable.groupName, this.model.maxVariable.dataSourceCode, this.model.maxVariable.variableVersion);
        return VariableUtil.getConvertedVariableName(this.variableStore, variable);
    }
    initTransformFun() {
        if (this.needAddNumber <= 3)
            return;
        this.$element[0].childNodes.forEach((node) => {
            const matrixE = node.transform.baseVal[0].matrix.e;
            node.transform.baseVal[0].matrix.e = matrixE + (this.needAddNumber - 3) * 5;
            if (node.nodeName === 'g') {
                const nodeValue = node.attributes['clip-path'].value.replace('url(#', '').replace(')', '');
                const rootNode = node.parentNode.parentNode.parentElement;
                const clipPath = $(rootNode).find(`clipPath[id="${nodeValue}"]`);
                const demoPath = clipPath.find('path');
                const dValues = demoPath.attr('d').split(',');
                const retValues = [];
                dValues.forEach((line, index) => {
                    const values = [];
                    line.split(' ').forEach((item) => {
                        const nItem = Number(item);
                        if (!isNaN(nItem) && (index === 1 || nItem === -1)) {
                            item = nItem > 0 ? nItem + (this.needAddNumber - 3) * 8 : nItem - (this.needAddNumber - 3) * 8;
                        }
                        values.push(item);
                    });
                    retValues.push(values.join(' '));
                });
                demoPath.attr('d', retValues.join(','));
            }
        });
    }
    initFrameNode() {
        const arcPath = Snap(this.$element[0]);
        const b = arcPath.getBBox(true);
        const width = this.needAddNumber <= 3 ? b.width : b.width + (this.needAddNumber - 3) * 8;
        this.rootElement.append('rect').attr('id', 'StateFrame').attr('width', width).attr('height', b.height).attr('fill', 'transparent');
    }
    init(variableName) {
        if (variableName) {
            let hasVariable = false;
            forEach(this.elementStates, elementState => {
                if (elementState.variableName === variableName) {
                    hasVariable = true;
                }
            });
            if (!hasVariable && variableName === this.readVariableName) {
                this.elementStates.push(new VariableState(variableName, undefined));
            }
        }
    }
    updateValueObj(value, variableName) {
        var _a, _b, _c;
        if (((_a = this.model.variableId) === null || _a === void 0 ? void 0 : _a.variableName.name) === variableName) {
            this.isNeedUpdateScale = false;
            this.valueObj.value = value;
        }
        if (((_b = this.model.minVariable) === null || _b === void 0 ? void 0 : _b.name) === variableName) {
            this.isNeedUpdateScale = true;
            this.valueObj.min = value;
        }
        if (((_c = this.model.maxVariable) === null || _c === void 0 ? void 0 : _c.name) === variableName) {
            this.isNeedUpdateScale = true;
            this.valueObj.max = value;
        }
    }
    updateScale() {
        // 刻度模糊问题
        let isInitTransform = false;
        const matrix = this.$element[0].transform.baseVal[0].matrix;
        if (!this.$element[0].style.transform) {
            this.$element[0].style.transform = `translate3d(${matrix.e}px, ${matrix.f}px, 0)`;
        }
        if (!this.isNeedUpdateScale) {
            return;
        }
        const textElements = this.$element.find('g:first > text');
        let min = this.model.minValueType ? this.valueObj.min : this.model.min;
        let max = this.model.maxValueType ? this.valueObj.max : this.model.max;
        min = Number(min);
        max = Number(max);
        if (isNaN(min) || isNaN(max)) {
            min = RingGraphElement.DEFAULT_MIN_VALUE;
            max = RingGraphElement.DEFAULT_MAX_VALUE;
        }
        if (this.model.minValueType === VariableValueType.Variable) {
            this.needAddNumber = max.toString().length > min.toString().length ? max.toString().length : min.toString().length;
            if (!this.initTransform) {
                this.initTransformFun();
                this.initFrameNode();
            }
        }
        const avgSacle = ((max - min) / this.model.masterDivisionNumber).toFixed(5);
        for (let i = 0; i < textElements.length; i++) {
            const text = textElements[i];
            if (!text.innerHTML) {
                continue;
            }
            let sacleValue = ((Number(avgSacle) * i) + min).toFixed(0);
            // 整数位和小数位格式化；
            if (this.model.fractionDigits > 0) {
                sacleValue = (sacleValue / Math.pow(10, this.model.fractionDigits)).toFixed(this.model.fractionDigits);
            }
            if (!isNaN(sacleValue)) {
                text.innerHTML = sacleValue;
                isInitTransform = true;
                if (this.model.minValueType !== VariableValueType.Constant || this.model.maxValueType !== VariableValueType.Constant) {
                    // FLEXCLOUD-2619 刻度显示不全问题
                    const order = (i + 1) / textElements.length;
                    if (!this.initTransform && order > 0.7 && sacleValue.toString().length > 3) {
                        text.transform.baseVal[0].matrix.e -= (sacleValue.toString().length - 3) * 5;
                    }
                }
            }
        }
        this.initTransform = this.initTransform || isInitTransform;
    }
    updateVariableValue(value, variableName) {
        this.updateValueObj(value, variableName);
        this.updateScale();
        let min = this.model.minValueType ? this.valueObj.min : this.model.min;
        let max = this.model.maxValueType ? this.valueObj.max : this.model.max;
        min = Number(min);
        max = Number(max);
        if (isNaN(min) || isNaN(max)) {
            min = RingGraphElement.DEFAULT_MIN_VALUE;
            max = RingGraphElement.DEFAULT_MAX_VALUE;
        }
        const percent = calculatePercent(min, max, this.valueObj.value || 0);
        this.updateBar(percent);
        this._barElement$.attr('fill', this.getBarColor(value));
        if (this.model.showPercentage) {
            this._textElement$.text((percent * 100).toFixed(0) + '%');
        }
    }
    updateBar(percent) {
        const model = this.model;
        const outer = model.size.width / 2.0;
        const rawStartAngle = model.arc.startAngle;
        const rawEndAngle = model.arc.endAngle;
        const sweepAngle = rawStartAngle === rawEndAngle ? 360 :
            (rawStartAngle < rawEndAngle ? rawEndAngle - rawStartAngle : rawEndAngle + 360 - rawStartAngle);
        const scale = model.scale;
        const inner = outer * (scale / 100.0);
        const arcPath = path();
        switch (Number(model.direction)) {
            case RotationDirectionType.ClockWise:
                this.drawClockWiseArc(rawStartAngle, sweepAngle, percent, arcPath, outer, inner);
                break;
            case RotationDirectionType.ReverseClockWise:
                this.drawAntiClockWiseArc(rawEndAngle, sweepAngle, percent, arcPath, outer, inner);
                break;
        }
        arcPath.closePath();
        this._barElement$.attr('d', arcPath.toString());
    }
    getBarColor(value) {
        const model = this.model;
        if (!model.enableAlarmRange) {
            return model.barFill;
        }
        const alarmRange = model.alarmRange;
        if (value > alarmRange.upper) {
            return alarmRange.upperFill;
        }
        else if (value < alarmRange.lower) {
            return alarmRange.lowerFill;
        }
        else {
            return model.barFill;
        }
    }
    drawClockWiseArc(rawStartAngle, sweepAngle, percent, arcPath, outer, inner) {
        const startRadians = degreesToRadians(rawStartAngle);
        const endAngle = sweepAngle * percent + rawStartAngle;
        const endRadians = degreesToRadians(endAngle);
        arcPath.arc(outer, outer, outer, startRadians, endRadians);
        arcPath.arc(outer, outer, inner, endRadians, startRadians, true);
    }
    drawAntiClockWiseArc(rawEndAngle, sweepAngle, percent, arcPath, outer, inner) {
        const startRadians = degreesToRadians(rawEndAngle);
        const endAngle = rawEndAngle - sweepAngle * percent;
        const endRadians = degreesToRadians(endAngle);
        arcPath.arc(outer, outer, outer, startRadians, endRadians, true);
        arcPath.arc(outer, outer, inner, endRadians, startRadians);
    }
}
RingGraphElement.DEFAULT_MIN_VALUE = 0;
RingGraphElement.DEFAULT_MAX_VALUE = 100;
