import { LOGGER_SERVICE_TOKEN } from '../../logger';
import { WriteValueModalArgs } from '../../modal/write-value/write-value-modal-args';
import { State, DisplayDataType } from '../../model';
import { AccessPermissionService, DataTypeService, FractionDigitService, NumericalOperationService } from '../../utils';
import { ReadableElement } from '../base/readable-element';
import { GraphStateElement } from '../shared/graph/graph-state-element';
import { TextElementModal } from '../shared/text/text-element';
import { AlertModalComponent } from '../../modal/alert/alert-modal.component';
import { WriteValueModalComponent } from '../../modal/write-value/write-value-modal.component';
import { ConfirmOperationModalComponent } from '../../modal/confirm-operation/confirm-operation-modal.component';
import { VerifyPasswordModalComponent } from '../../modal/verify-password/verify-password-modal.component';
import { isNil } from 'lodash';
import { FCloudDataType } from '../../model/shared/data-type/fcloud-data-Type';
var variableRwTypeEnum;
(function (variableRwTypeEnum) {
    variableRwTypeEnum[variableRwTypeEnum["read"] = 4] = "read";
    variableRwTypeEnum[variableRwTypeEnum["witer"] = 2] = "witer";
    variableRwTypeEnum[variableRwTypeEnum["readWiter"] = 6] = "readWiter";
})(variableRwTypeEnum || (variableRwTypeEnum = {}));
export class NumericalDisplayElement extends ReadableElement {
    constructor(element, injector, modalService, permissionChecker, variableCommunicator, graphStore, operationRecordService, releasedVariableService, securityChecker, variableStore, localization, signalRAppId) {
        super(element, permissionChecker, variableCommunicator, variableStore, localization, signalRAppId);
        this.modalService = modalService;
        this.graphStore = graphStore;
        this.operationRecordService = operationRecordService;
        this.releasedVariableService = releasedVariableService;
        this.securityChecker = securityChecker;
        this.displayText = '';
        this.enableDataParsed = false;
        this.logger = injector.get(LOGGER_SERVICE_TOKEN);
        this.dataTypeService = injector.get(DataTypeService);
        this.fractionDigitService = injector.get(FractionDigitService);
        this.accessPermissionService = injector.get(AccessPermissionService);
        this.numericalOperationService = injector.get(NumericalOperationService);
        if (!isNil(this.model.displayDataType)) {
            if (this.model.displayDataType === DisplayDataType.Binary) {
                this.model.dataType = FCloudDataType.Binary;
            }
            if (this.model.displayDataType === DisplayDataType.Hex) {
                this.model.dataType = FCloudDataType.Hex;
            }
        }
        // version小于6时是老版本，默认支持数据解析
        if (this.model.version < 6 || this.model.enableDataParsed) {
            this.enableDataParsed = true;
        }
        this.initElement();
    }
    get writeVariableName() {
        return this.readVariableName;
    }
    dispose() {
        if (this.displayForeignObject) {
            this.displayForeignObject.remove();
        }
        if (this.$element) {
            this.$element.remove();
        }
    }
    initElement() {
        const { rootElement } = this;
        rootElement.selectAll('*').remove();
        let width = null, height = null;
        if (this.model.size) {
            width = this.model.size.width;
            height = this.model.size.height;
        }
        if (!width || !height) {
            width = 60;
            height = 38;
        }
        rootElement.append('rect').attr('id', 'StateFrame').attr('width', width).attr('height', height).attr('fill', 'transparent');
        this.initVariableText(width, height);
        this.initGraphAndText(width, height);
        if (!this.accessPermissionService.canWrite(this.model.accessPermission) || null == this.model.dataType) {
            return;
        }
        this.rootElement.style('cursor', 'hand');
        this.$element.click(__ => {
            if (!this.isInitialized) {
                return;
            }
            if (!this.isEnable) {
                const message = !this.isGrantedPermission ? this.localization.permissiontip : this.localization.conditionIsNotMetTip;
                const modalRef = this.modalService.show(AlertModalComponent, { initialState: { alermMessage: message }, backdrop: 'static', class: 'gui-modal-dialog-position', animated: false });
                const onClosedSub = modalRef.content.onClosed.subscribe(() => {
                    modalRef.hide();
                    onClosedSub.unsubscribe();
                });
                return;
            }
            if (this.model.useSecurity) {
                const modalRef = this.modalService.show(ConfirmOperationModalComponent, {
                    backdrop: 'static', class: 'gui-modal-dialog-position', animated: false
                });
                const onClosedSub = modalRef.content.onClosed.subscribe(result => {
                    modalRef.hide();
                    onClosedSub.unsubscribe();
                    if (result) {
                        this.checkElementPassword();
                    }
                });
            }
            else {
                this.checkElementPassword();
            }
        });
    }
    checkElementPassword() {
        if (this.model.enablePassword) {
            const modalRef = this.modalService.show(VerifyPasswordModalComponent, { initialState: { securityChecker: this.securityChecker }, backdrop: 'static', class: 'gui-modal-dialog-position', animated: false });
            const onClosedSub = modalRef.content.onClosed.subscribe(result => {
                modalRef.hide();
                onClosedSub.unsubscribe();
                if (result) {
                    this.doWriteValue();
                }
            });
        }
        else {
            this.doWriteValue();
        }
    }
    initVariableText(width, height) {
        if (!this.model.showVariableText) {
            return;
        }
        const font = {
            isUnderline: this.model.variableText.font.isUnderline,
            isBold: this.model.variableText.font.isBold,
            isItalic: this.model.variableText.font.isItalic,
            fontSize: this.model.variableText.font.fontSize,
            fontFamily: this.model.variableText.font.fontFamily,
            color: this.model.variableText.font.color,
            textAlign: this.model.variableText.font.textAlign
        };
        const textElement = new TextElementModal(this.model.variableText.content + ':', font, width * 7 / 11, height, true);
        this.$element.append(textElement.Element);
    }
    initGraphAndText(width, height) {
        let translateX = '';
        if (this.model.showVariableText) {
            translateX = `translate(${width * 7 / 11},0)`;
            width = width * 4 / 11;
        }
        else {
            translateX = 'translate(0,0)';
        }
        if (this.model.useGraph === true) {
            const graphStateElement = new GraphStateElement(this.model.graphSetting, width, height, this.graphStore, this.logger);
            graphStateElement.Element.setAttribute('transform', translateX);
            this.$element.append(graphStateElement.Element);
            graphStateElement.switchToState(0);
        }
        let isUnderline = false;
        let isBold = false;
        let isItalic = false;
        let fontFamily = 'Microsoft YaHei';
        if (this.model.font) {
            const fontStyle = this.model.font.split(' ');
            isUnderline = this.model.isUnderline;
            isBold = $.inArray('bold', fontStyle) >= 0;
            isItalic = $.inArray('Italic', fontStyle) >= 0;
            fontFamily = this.model.font.split(' ').pop();
        }
        const font = {
            isUnderline: isUnderline,
            isBold: isBold,
            isItalic: isItalic,
            fontSize: this.model.fontSize,
            fontFamily: fontFamily,
            color: this.model.stroke,
            textAlign: this.model.textAlign
        };
        const textElement = new TextElementModal('', font, width, height);
        textElement.Element.setAttribute('transform', translateX);
        this.$element.append(textElement.Element);
    }
    doWriteValue() {
        if (null == this.writeVariableName) {
            return;
        }
        const args = new WriteValueModalArgs(this.writeVariableName, this.model.dataType, this.model.fBoxDataType, this.model.integerDigits, this.model.fractionDigits, this.numericalOperationService.getNumericalOperations(this.model), this.model.version, this.enableDataParsed, this.releasedVariableService);
        this.writeValueMmodalRef = this.modalService.show(WriteValueModalComponent, {
            initialState: { args: args }, backdrop: 'static', class: 'gui-modal-dialog-position', animated: false
        });
        this.writeValueMmodalRef.content.onClosed = (result) => {
            if (result) {
                if (this.restorationTimer) {
                    clearTimeout(this.restorationTimer);
                    this.restorationTimer = undefined;
                }
                const writeValue = this.dataTypeService.formatToDecimal(this.model.version, result.value, this.model.dataType);
                this.writeValue = writeValue;
                this.showValue = result.showValue;
                if (+this.displayText !== +this.showValue || result.variableRwType === variableRwTypeEnum.witer) {
                    if (this.numericalOperation || result.enableNumericalOperation || result.isNumericalOperation || result.variableRwType === variableRwTypeEnum.witer) {
                        this.writeValueMmodalRef.hide();
                    }
                    else {
                        this.restorationTimer = setTimeout(() => {
                            if (+this.displayText !== +this.showValue) {
                                this.writeValueMmodalRef.content.isSubmitting = false;
                                this.writeValueMmodalRef.content.showValidationErrorInfo(this.localization.writeValueTimeout);
                            }
                        }, 10000);
                    }
                    this.variableCommunicator.write(this.writeVariableName, writeValue).subscribe();
                }
                else {
                    this.writeValueMmodalRef.hide();
                }
            }
        };
    }
    recordOperation(newValue) {
        if (this.model.isRecordOperation || this.model.isRecordOperation === undefined) {
            this.operationRecordService.record({
                variableOptionModel: {
                    variableName: this.writeVariableName,
                    originValue: this.formatDisplayTextUnit(this.displayText),
                    newValue: this.formatDisplayTextUnit(this.formatNumericalDisplayText(this.model.dataType, this.model.fractionDigits, newValue))
                },
                operationDescription: this.model.operationDescription
            });
        }
    }
    changeStates() {
        super.changeStates();
        if (this.state === State.Normal || this.state === State.Disable) {
            this.updateDisplayText(this.formatDisplayTextUnit(this.displayText));
        }
        else {
            if (this.preState !== this.state) {
                this.updateDisplayText('');
            }
        }
    }
    updateVariableValue(value) {
        var _a;
        this.displayText = this.formatNumericalDisplayText(this.model.dataType, this.model.fractionDigits, value);
        this.updateDisplayText(this.formatDisplayTextUnit(this.displayText));
        if (((_a = this.writeValueMmodalRef) === null || _a === void 0 ? void 0 : _a.content) && +this.displayText === +this.showValue) {
            if (this.restorationTimer) {
                clearTimeout(this.restorationTimer);
                this.restorationTimer = undefined;
            }
            this.writeValueMmodalRef.hide();
            this.writeValueMmodalRef.content.hideValidationErrorInfo();
            this.recordOperation(this.writeValue);
        }
    }
    updateDisplayText(text) {
        if (!this.displayForeignObject) {
            if (this.model.showVariableText) {
                this.displayForeignObject = this.$element.find('foreignObject').eq(1);
            }
            else {
                this.displayForeignObject = this.$element.find('foreignObject').eq(0);
            }
        }
        if (isNil(text)) {
            this.displayForeignObject.remove();
        }
        else {
            const textList = this.displayForeignObject.find('.text-list');
            const textArray = text.toString().split('\n');
            if (textList.length === textArray.length) {
                for (let index = 0; index < textList.length; index++) {
                    textList[index].innerText = textArray[index];
                }
            }
            else {
                this.displayForeignObject.remove();
                const width = this.displayForeignObject.attr('width');
                const height = this.displayForeignObject.attr('height');
                const transform = this.displayForeignObject.attr('transform');
                this.displayForeignObject = $(this.rebuildTextElement(width, height, transform, text));
            }
        }
    }
    rebuildTextElement(width, height, transform, text) {
        let isUnderline = false;
        let isBold = false;
        let isItalic = false;
        let fontFamily = 'Microsoft YaHei';
        if (this.model.font) {
            const fontStyle = this.model.font.split(' ');
            isUnderline = this.model.isUnderline;
            isBold = $.inArray('bold', fontStyle) >= 0;
            isItalic = $.inArray('Italic', fontStyle) >= 0;
            fontFamily = this.model.font.split(' ').pop();
        }
        const font = {
            isUnderline: isUnderline,
            isBold: isBold,
            isItalic: isItalic,
            fontSize: this.model.fontSize,
            fontFamily: fontFamily,
            color: this.model.stroke,
            textAlign: this.model.textAlign
        };
        const textElement = new TextElementModal(text, font, Number(width), Number(height));
        textElement.Element.setAttribute('transform', transform);
        this.$element.append(textElement.Element);
        return textElement.Element;
    }
    formatNumericalDisplayText(dataType, fractionDigits, value) {
        if (null == value || value.toString().trim().length <= 0) {
            return '';
        }
        value = +value;
        // 16进制数
        if (this.dataTypeService.isHexType(this.model.version, dataType)) {
            // eslint-disable-next-line no-bitwise
            return (value >>> 0).toString(16).toUpperCase();
        }
        // 2进制
        if (this.dataTypeService.isBinaryType(this.model.version, dataType)) {
            // eslint-disable-next-line no-bitwise
            const formatValue = (value >>> 0).toString(2);
            if (formatValue.length < 17) {
                return formatValue;
            }
            const constOne = '1111111111111111';
            if (formatValue.indexOf(constOne) === 0) {
                return formatValue.replace(constOne, '');
            }
            const constZero = '0000000000000000';
            if (formatValue.indexOf(constZero) === 0) {
                return formatValue.replace(constZero, '');
            }
            return formatValue;
        }
        if (!this.isNumeric(value) || null == fractionDigits || fractionDigits < 0) {
            return value;
        }
        // 数据解析
        if (!this.enableDataParsed) {
            return value;
        }
        const supportFractionDigits = this.dataTypeService.isSupportFractionDigit(this.model.version, dataType);
        if (!supportFractionDigits) {
            return value;
        }
        // 数值运算
        if (this.dataTypeService.isSupportNumericalOperation(this.model.version, dataType)) {
            if (this.model.enableNumericalOperation && this.isNumeric(value)) {
                return this.numericalOperationService.getNumericalOperationedValue(this.model, value, fractionDigits);
            }
        }
        // 浮点数
        if (this.dataTypeService.isFloat(this.model.version, dataType)) {
            return this.formatFloatDisplayText(fractionDigits, value);
        }
        // 有符号数及无符号数
        if (fractionDigits === 0) {
            return value;
        }
        let displayText = Number(value).toFixed(0).toString();
        const isNegative = +displayText < 0;
        if (isNegative) {
            displayText = displayText.slice(1, displayText.length);
        }
        if (displayText.length > fractionDigits) {
            const dotPosition = displayText.length - fractionDigits;
            displayText = displayText.substr(0, dotPosition) + '.' + displayText.substr(dotPosition);
        }
        else {
            const fillZeroCount = fractionDigits - displayText.length;
            for (let i = 0; i < fillZeroCount; i++) {
                displayText = `0${displayText}`;
            }
            displayText = `0.${displayText}`;
        }
        return isNegative ? `-${displayText}` : displayText;
    }
    formatFloatDisplayText(fractionDigits, text) {
        let value = Number(text);
        if (!isNil(fractionDigits)) {
            value = +value.toFixed(fractionDigits + 2);
        }
        else {
            return value.toFixed(0);
        }
        return this.fractionDigitService.roundingToFixedFractionDigits(value, fractionDigits);
    }
    isNumeric(num) {
        return !isNaN(num);
    }
    formatDisplayTextUnit(displayText) {
        if (this.model.showUnit !== false && this.model.unit) {
            return `${displayText || 0} ${this.model.unit}`;
        }
        return displayText;
    }
}
