import { LOGGER_SERVICE_TOKEN } from '../../logger';
import * as d3 from 'd3-selection';
import { isUndefined } from 'lodash';
import { IndicatorLightType, SwitchType, State, BitSwitchOperation } from '../../model';
import { VariableState } from '../../communication';
import { ConditionalEnableElement } from '../base/conditional-enable-element';
import { GraphStateElement } from '../shared/graph/graph-state-element';
import { TextStateElement } from '../shared/text/text-state-element';
import { BitIndicatorLightOperator } from './bit-indicator-light-operator';
import { BitSwitchOperator } from './bit-switch-operator';
import { WordIndicatorLightOperator } from './word-indicator-light-operator';
import { WordSwitchOperator } from './word-switch-operator';
import { ConfirmOperationModalComponent } from '../../modal/confirm-operation/confirm-operation-modal.component';
import { AlertModalComponent } from '../../modal/alert/alert-modal.component';
import { VerifyPasswordModalComponent } from '../../modal/verify-password/verify-password-modal.component';
import { DisplayMode, GlobalSettings } from '../../settings';
import { VariableUtil } from '../../utils/variable-util';
import { VariableDefinition } from '../../communication/variable/variable-definition';
export class SwitchIndicatorLightElement extends ConditionalEnableElement {
    constructor(element, injector, modalService, variableCommunicator, graphStore, permissionChecker, operationRecordService, securityChecker, variableStore, localization, signalRAppId, textLibraryService, languageService, guiContext) {
        super(element, permissionChecker, variableCommunicator, variableStore, localization, signalRAppId);
        this.modalService = modalService;
        this.graphStore = graphStore;
        this.operationRecordService = operationRecordService;
        this.securityChecker = securityChecker;
        this.textLibraryService = textLibraryService;
        this.languageService = languageService;
        this.guiContext = guiContext;
        this.isBitRestoration = false; // 是否是 位设定且执行设置是复位
        this.isVerifiedForRestoration = false; // 位设定且执行设置是复位情况下，是否已经完成了验证
        this.isWriteRestorationDownValue = false;
        this.logger = injector.get(LOGGER_SERVICE_TOKEN);
        this.isMobileMode = DisplayMode.Mobile === injector.get(GlobalSettings).displayMode;
        this.checkState();
        if (this.model.useSwitch) {
            this.initSwitchOperator();
            this.rootElement.style('cursor', 'hand');
            const isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
            this.rootElement.on(this.isMobileMode && isMobile ? 'touchstart' : 'mousedown', () => {
                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.switchOperator.canExecute()) {
                    if (!this.isBitRestoration || !this.isVerifiedForRestoration) {
                        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(true);
                                }
                            });
                        }
                        else {
                            this.checkElementPassword(false);
                            if (!this.model.useIndicatorLight) {
                                this.switchToState(1);
                            }
                        }
                    }
                    else {
                        document.addEventListener(this.isMobileMode ? 'touchend' : 'mouseup', this.onDocMouseUp);
                        this.restorationTimer = setTimeout(() => {
                            this.writeValue(1);
                            this.isWriteRestorationDownValue = true;
                        }, 1000);
                    }
                    d3.event.preventDefault();
                }
            });
            this.rootElement.on(this.isMobileMode && isMobile ? 'touchend' : 'mouseup', () => {
                this.handleMouseUp();
                d3.event.stopPropagation();
            });
            this.initOnDocMouseUpEvent();
        }
        this.initGraphAndText();
        if (this.model.useIndicatorLight) {
            this.initIndictorLightOperator();
        }
        else {
            this.switchToState(0);
        }
    }
    handleMouseUp() {
        if (this.restorationTimer) {
            clearTimeout(this.restorationTimer);
            this.restorationTimer = undefined;
        }
        if (this.isBitRestoration && this.isWriteRestorationDownValue) {
            this.writeValue(0);
        }
        document.removeEventListener(this.isMobileMode ? 'touchend' : 'mouseup', this.onDocMouseUp);
        this.isVerifiedForRestoration = false;
        this.isWriteRestorationDownValue = false;
        if (!this.model.useIndicatorLight) {
            this.switchToState(0);
            if (d3.event) {
                d3.event.preventDefault();
            }
        }
    }
    initOnDocMouseUpEvent() {
        this.onDocMouseUp = () => {
            this.handleMouseUp();
        };
    }
    checkElementPassword(afterConfirm) {
        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) {
                    if (!this.isBitRestoration) {
                        this.doSwitchOperator();
                    }
                    else {
                        this.isVerifiedForRestoration = true;
                    }
                }
            });
        }
        else {
            if (!this.isBitRestoration) {
                this.doSwitchOperator();
            }
            else {
                if (afterConfirm) {
                    this.isVerifiedForRestoration = true;
                }
                else {
                    this.isVerifiedForRestoration = true;
                    document.addEventListener(this.isMobileMode ? 'touchend' : 'mouseup', this.onDocMouseUp);
                    this.restorationTimer = setTimeout(() => {
                        this.writeValue(1);
                        this.isWriteRestorationDownValue = true;
                    }, 1000);
                }
            }
        }
    }
    doSwitchOperator() {
        this.switchOperator.execute().then(args => {
            if (this.model.isRecordOperation || this.model.isRecordOperation === undefined) {
                if (args.newValue !== undefined || args.originValue !== undefined) {
                    this.operationRecordService.record({
                        variableOptionModel: args,
                        operationDescription: this.model.operationDescription
                    });
                }
            }
        }).catch(() => {
            throw new Error('Failure of the operation record:switchOperator');
        });
    }
    writeValue(value) {
        this.switchOperator.writeValue(value).then(args => {
            if (this.model.isRecordOperation || this.model.isRecordOperation === undefined) {
                if (args.newValue !== undefined || args.originValue !== undefined) {
                    this.operationRecordService.record({
                        variableOptionModel: args,
                        operationDescription: this.model.operationDescription
                    });
                }
            }
        }).catch(() => {
            throw new Error('Failure of the operation record:switchOperator');
        });
    }
    initSwitchOperator() {
        const settings = this.model.switchSettings;
        switch (settings.type) {
            case SwitchType.Bit:
                this.switchOperator =
                    new BitSwitchOperator(settings.settings, this.variableCommunicator, this.variableStore, this.signalRAppId);
                this.isBitRestoration = settings.settings.operation === BitSwitchOperation.Restoration;
                break;
            case SwitchType.Word:
                this.switchOperator =
                    new WordSwitchOperator(settings.settings, this.variableCommunicator, this.variableStore, this.signalRAppId);
                break;
            default:
                throw new Error(`Unknown switchType:${settings.type}`);
        }
    }
    initIndictorLightOperator() {
        const settings = this.model.indicatorLightSettings;
        if (settings.settings.variableName) {
            const variable = new VariableDefinition(settings.settings.variableName, settings.settings.variableGroupName, settings.settings.dataSourceCode, settings.settings.variableVersion);
            this.addElementState(new VariableState(VariableUtil.getConvertedVariableName(this.variableStore, variable), undefined));
            this.initState();
        }
        switch (settings.type) {
            case IndicatorLightType.Bit:
                this.indicatorLightOperator = new BitIndicatorLightOperator(settings.settings, this.model.states, this.variableCommunicator, this.variableStore);
                break;
            case IndicatorLightType.Word:
                this.indicatorLightOperator = new WordIndicatorLightOperator(settings.settings, this.model.states, this.variableCommunicator, this.variableStore);
                break;
            default:
                throw new Error(`Unknown switchType:${settings.type}`);
        }
        this.indicatorLightOperator.currentStateIdChanged.subscribe(statusIdValue => {
            this.currentStateIdChange(statusIdValue);
        });
        this.indicatorLightOperator.requestData(this.signalRAppId);
    }
    currentStateIdChange(statusIdValue) {
        if (!isUndefined(statusIdValue.value)) {
            this.switchToState(statusIdValue.value);
        }
        this.updateElementStates([statusIdValue.state]);
        if (this.state === State.Unbind || this.state === State.Offline) {
            this.switchToState(0);
        }
    }
    switchToState(stateId) {
        this.textStateElement.switchToState(stateId);
        if (this.graphStateElement) {
            this.graphStateElement.switchToState(stateId);
        }
    }
    initGraphAndText() {
        this.rootElement.selectAll('*').remove();
        const size = this.model.size;
        const width = size.width;
        const height = size.height;
        this.rootElement.append('rect').attr('id', 'StateFrame').attr('width', width).attr('height', height).attr('fill', 'transparent');
        if (this.model.useGraph === true) {
            this.graphStateElement = new GraphStateElement(this.model.graphSetting, width, height, this.graphStore, this.logger, this.model.version, this.model.states);
            this.$element.append(this.graphStateElement.Element);
        }
        this.textStateElement = new TextStateElement(this.model.states, width, height, this.logger, this.model.version, this.model.states, this.model.textLibrary, this.textLibraryService, this.languageService, this.guiContext);
        this.$element.append(this.textStateElement.Element);
    }
    /**
     * 释放资源
     */
    dispose() {
        // 释放文本元素资源（取消语种变化订阅等）
        if (this.textStateElement) {
            this.textStateElement.dispose();
        }
        // 释放指示灯操作器资源
        if (this.indicatorLightOperator) {
            // indicatorLightOperator 可能有自己的dispose方法
        }
        // 清除定时器
        if (this.restorationTimer) {
            clearTimeout(this.restorationTimer);
            this.restorationTimer = undefined;
        }
        // 移除事件监听
        if (this.onDocMouseUp) {
            document.removeEventListener(this.isMobileMode ? 'touchend' : 'mouseup', this.onDocMouseUp);
        }
    }
    checkState() {
        if (!this.model.states) {
            throw new Error('The switch indicator light\'s states is undefined.');
        }
        if (this.model.states.length < 2) {
            throw new Error('The switch indicator light\'s states must greater than 2.');
        }
    }
}
