/**
 * 工作流设计工具
 *
 * @class IBizWFDesignField2
 */
class IBizWFDesignField2 {

    private $applicationRef: any = null;

    /**
     * activit设计工具iframe的window对象
     * 
     * @private
     * @type {ActivitiWorkflowEditor}
     * @memberof IBizWFDesignField2
     */
    private $flowFrame: ActivitiWorkflowEditor = null;

    /**
     * 打开编辑视图服务
     * 
     * @private
     * @type {WorkFlowEditService}
     * @memberof IBizWFDesignField2
     */
    private $workFlowEditService: WorkFlowEditService = null;

    /**
     * 
     * 
     * @private
     * @type {*}
     * @memberof IBizWFDesignField2
     */
    private $lastValue: any = null;

    /**
     * 
     * 
     * @private
     * @type {boolean}
     * @memberof IBizWFDesignField2
     */
    private $flowFrameLoaded: boolean = false;

    /**
     * 
     * 
     * @private
     * @type {*}
     * @memberof IBizWFDesignField2
     */
    private $logicJson: any = {};

    /**
     * 
     * 
     * @private
     * @type {*}
     * @memberof IBizWFDesignField2
     */
    private $logicJson2: any = {};

    /**
     * 
     * 
     * @private
     * @type {string}
     * @memberof IBizWFDesignField2
     */
    private $logicJsonString: string = '';

    /**
     * 值改变发射流
     * 
     * @private
     * @type {Subject<any>}
     * @memberof IBizWFDesignField2
     */
    private $valueChangeSubject: Subject<any> = new rxjs.Subject();

    /**
     * 全屏按钮事件
     * 
     * @private
     * @type {Subject<any>}
     * @memberof IBizWFDesignField2
     */
    private $fullScreenSubject: Subject<any> = new rxjs.Subject();

    /**
     * 脏检查定时器
     *
     * @private
     * @type {*}
     * @memberof IBizWFDesignField2
     */
    private $tickTimer: any;

    /**
     * vue对象
     *
     * @private
     * @type {*}
     * @memberof IBizWFDesignField2
     */
    private $vue: any = null;

    /**
     * 工作流
     *
     * @private
     * @type {*}
     * @memberof IBizWFDesignField2
     */
    private workFlow: any = {};

    constructor(opts: any = {}) {
        this.$vue = opts.vue;
        Object.assign(this.workFlow, opts.workFlow);
        this.$workFlowEditService = new WorkFlowEditService({ vue: this.$vue, workFlow: opts.workFlow });
    }

    /**
     * 
     * 
     * @param {any} value 
     * @returns 
     * @memberof IBizWFDesignField2
     */
    public setValue(value): void {
        let wfEngineType = this.getWFEngineType();
        this.$lastValue = value;
        if (wfEngineType && wfEngineType === 'ACTIVITI') {
            this.loadFromXML(value);
        }
    }

    /**
     * 
     * 
     * @param {any} strXML 
     * @returns {void} 
     * @memberof IBizWFDesignField2
     */
    public loadFromXML(strXML): void {
        let xmlDoc = IBizActivitiUtil.parseXML(strXML);
        if (xmlDoc == null) {
            alert('工作流流程不正确');
            return;
        }

        for (let i = 0; i < xmlDoc.childNodes.length; i++) {
            if (xmlDoc.childNodes[i].nodeName === 'WFCONFIG') {
                this.loadLogic(xmlDoc.childNodes[i]);
                break;
            }
        }

        if (this.$flowFrameLoaded) {
            this.loadConfig();
        }
    }

    /**
     * 
     * 
     * @param {any} xmlNode 
     * @memberof IBizWFDesignField2
     */
    public loadLogic(xmlNode): void {
        let xml: any = {};
        IBizActivitiUtil.loadXMLNode(xmlNode, xml);
        this.$logicJson = {};
        this.$logicJson2 = {};

        Object.assign(this.$logicJson, xml);
        Object.assign(this.$logicJson2, xml);

        Object.assign(this.$logicJson, { srfparenttype: this.workFlow.NODE.type, srfder1nid: this.workFlow.NODE.der1nid, srfparentkey: xml[this.workFlow.FLOW.id] });
        Object.assign(this.$logicJson2, { srfparenttype: this.workFlow.LINK.type, srfder1nid: this.workFlow.LINK.der1nid, srfparentkey: xml[this.workFlow.FLOW.id] });

        this.$logicJsonString = xml.activitimodel;
        delete this.$logicJson.activitimodel;
        delete this.$logicJson2.activitimodel;
    }

    /**
     * 
     * 
     * @memberof IBizWFDesignField2
     */
    public loadConfig(): void {
        console.log('loadConfig');
        if (this.$logicJsonString) {
            this.$flowFrame.setModel(this.$logicJsonString);
        }
    }

    /**
     * 
     * 
     * @returns {string} 
     * @memberof IBizWFDesignField2
     */
    public getValue(): string {
        const wfEngineType = this.getWFEngineType();
        if (wfEngineType === 'ACTIVITI') {
            return this.exportToXml();
        }
        return this.$lastValue;
    }

    /**
     * 
     * 
     * @returns {string} 
     * @memberof IBizWFDesignField2
     */
    public exportToXml(): string {
        console.log('exportToXml');
        if (this.$flowFrameLoaded) {
            let value = this.$flowFrame.getModel();
            let writer = new IBizXMLWriter();
            writer.beginNode('WFCONFIG');
            if (this.$logicJson) {
                writer.attrib(this.workFlow.FLOW.id.toUpperCase(), this.$logicJson[this.workFlow.FLOW.id])
                // writer.attrib('PSWFID', this.$logicJson.pswfid);
                // writer.attrib('PSWFVERSIONID', this.$logicJson.pswfversionid);
                // writer.attrib('PSSYSTEMID', this.$logicJson.pssystemid);
            }

            writer.attrib('ACTIVITIMODEL', value);
            writer.endNode();
            writer.close();

            let strXML = '<?xml version="1.0" encoding="utf-8" ?>' + writer.toString();
            return strXML;
        } else {
            return this.$lastValue;
        }
    }

    /**
     * 设置iframeWindow对象
     * 
     * @memberof IBizWFDesignField2
     */
    public setFlowFrame(flowFrame: any): void {
        this.$flowFrame = flowFrame;
    }

    /**
     * 
     * 
     * @memberof IBizWFDesignField2
     */
    public onFlowFrameLoad(): void {
        console.log('onFlowFrameLoad');
        this.$flowFrameLoaded = true;
        this.$flowFrame.setParentObj(this);
    }

    /**
     * 获取当前工作流编辑器类型
     * 
     * @returns {String} 
     * @memberof IBizWFDesignField2
     */
    public getWFEngineType(): String {
        return 'ACTIVITI';
    }

    /**
     * 发射全屏事件
     * 
     * @memberof IBizWFDesignField2
     */
    public showFullScreen(): void {
        this.$fullScreenSubject.next(this.getValue());
    }

    /**
     * 开启全屏模式
     * 
     * @returns {Observable<string>} 
     * @memberof IBizWFDesignField2
     */
    public onFullScreen(): Observable<string> {
        return this.$fullScreenSubject.asObservable();
    }

    /**
     * 全屏模式关闭回调
     * 
     * @param {any} win 
     * @returns {void} 
     * @memberof IBizWFDesignField2
     */
    public onFullScreenWindowClose(res: any): void {
        let activeData = res.activeData;
        if (!activeData) {
            console.log('没有返回任何数据!');
            return;
        }
        let wfmodel = activeData.wfmodel;
        this.setValue(wfmodel);
    }

    /**
     * 
     * 
     * @param {any} shape 
     * @returns {void} 
     * @memberof IBizWFDesignField2
     */
    public editShape(shape): void {
        console.log('editShape');
        if (!shape) {
            return;
        }
        let stencilid = shape.getStencil().id();
        let type = stencilid.replace('http://b3mn.org/stencilset/bpmn2.0#', '');
        let keyvalue = shape.properties['oryx-documentation'];

        if (type === 'StartNoneEvent') {
            this.editProcess(shape, 'START', keyvalue);
            return;
        }
        if (type === 'UserTask') {
            this.editProcess(shape, 'INTERACTIVE', keyvalue);
            return;
        }
        if (type === 'ServiceTask') {
            this.editProcess(shape, 'PROCESS', keyvalue);
            return;
        }
        if (type === 'ExclusiveGateway') {
            this.editProcess(shape, 'EXCLUSIVEGATEWAY', keyvalue);
            return;
        }
        if (type === 'InclusiveGateway') {
            this.editProcess(shape, 'INCLUSIVEGATEWAY', keyvalue);
            return;
        }
        if (type === 'SubProcess') {
            this.editProcess(shape, 'EMBED', keyvalue);
            return;
        }
        if (type === 'CatchTimerEvent') {
            this.editProcess(shape, 'TIMEREVENT', keyvalue);
            return;
        }
        if (type === 'ParallelGateway') {
            this.editProcess(shape, 'PARALLELGATEWAY', keyvalue);
            return;
        }
        if (type === 'TextAnnotation') {
            this.editTextAnnotation(shape);
            return;
        }
        if (type === 'SequenceFlow') {
            let fromShape = this.getFromShape(shape);
            if (!fromShape) {
                alert('无法获取连接源处理对象');
                return;
            }

            let stencilid2 = fromShape.getStencil().id();
            let type2 = stencilid2.replace('http://b3mn.org/stencilset/bpmn2.0#', '');
            if (type2 === 'UserTask') {
                this.editLink(shape, 'IAACTION', keyvalue);
            } else {
                this.editLink(shape, 'ROUTE', keyvalue);
            }
            return;
        }
        if (type === 'EndNoneEvent') {
            this.editProcess(shape, 'END', keyvalue);
            return;
        }
    }

    /**
     * 注释节点编辑
     * 
     * @param {any} tag 
     * @memberof IBizWFDesignField2
     */
    public editTextAnnotation(tag): void {
        throw new Error('暂无视图无法打开');
        // 需要的视图WFDesignField2MemoView
        // this.$workFlowEditService.openEditTextAnnotationView({ 'viewParam': { memo: tag.properties['oryx-text'] }, 'modalZIndex': 800 }).subscribe(
        //     res => {
        //         if (res && Object.is('OK', res.ret)) {
        //             this.onNodeWindowClose(res);
        //         }
        //     }
        // );
    }

    /**
     * 
     * 
     * @param {any} tag 
     * @param {any} detailtype 
     * @param {any} keyvalue 
     * @returns 
     * @memberof IBizWFDesignField2
     */
    public editProcess(tag, detailtype, keyvalue: string = ''): void {
        const param: any = {
            srfparenttype: this.$logicJson.srfparenttype,
            srfder1nid: this.$logicJson.srfder1nid,
            srfparentkey: this.$logicJson.srfparentkey,
            wfprocesstype: detailtype
        };
        if (keyvalue && !Object.is(keyvalue, '')) {
            Object.assign(param, { srfkey: keyvalue });
        }

        this.$workFlowEditService.openProcessEditView(detailtype, { 'viewParam': param, 'modalZIndex': 600 }).subscribe(
            res => {
                if (res && Object.is('OK', res.ret)) {
                    res.activeNode = tag;
                    this.onNodeWindowClose(res);
                    // this.clearTickTimer();
                    // this.allTick();
                }
            }
        );
        // this.modalTick();
        // this.allTick();
    }

    /**
     * 
     * 
     * @param {any} obj 
     * @returns {*} 
     * @memberof IBizWFDesignField2
     */
    public getFromShape(obj): any {
        let shapeFacade = this.getShapeFacade(obj);
        if (!shapeFacade) {
            return null;
        }

        let strResourceId = obj['resourceId'];
        if (!strResourceId) {
            return null;
        }

        let shapes = shapeFacade.getCanvas().getChildShapes(true);
        if (!shapes || shapes.length === 0) {
            return null;
        }

        for (let i = 0; i < shapes.length; i++) {
            let shape = shapes[i];
            let outgoings = shape['outgoing'];
            if (!outgoings || outgoings.length === 0) {
                continue;
            }

            for (let j = 0; j < outgoings.length; j++) {
                let outgoing = outgoings[j];
                if (outgoing['resourceId'] === strResourceId) {
                    return shape;
                }
            }
        }
        return null;
    }

    /**
     * 
     * 
     * @param {any} obj 
     * @returns 
     * @memberof IBizWFDesignField2
     */
    public getShapeFacade(obj): any {
        if (obj.facade) {
            return obj.facade;
        }
        if (obj.parent) {
            return this.getShapeFacade(obj.parent);
        }
        return null;
    }

    /**
     * 
     * 
     * @param {any} tag 
     * @param {any} linktype 
     * @param {any} keyvalue 
     * @returns 
     * @memberof IBizWFDesignField2
     */
    public editLink(tag, linktype, keyvalue): void {
        const loadParam: any = {
            srfparenttype: this.$logicJson2.srfparenttype,
            srfder1nid: this.$logicJson2.srfder1nid,
            srfparentkey: this.$logicJson2.srfparentkey,
            wflinktype: linktype,
        };
        if (keyvalue && !Object.is(keyvalue, '')) {
            Object.assign(loadParam, { srfkey: keyvalue });
        }
        let _data = {};
        if (!keyvalue || Object.is(keyvalue, '')) {
            _data[this.workFlow.FORM.id] = 'SRFTEMPKEY:' + this.newGuid();
            _data[this.workFlow.FORM.name] = '源处理名称';
        }

        Object.assign(loadParam, _data);

        this.$workFlowEditService.openLinkEditView(linktype, { 'viewParam': loadParam, 'modalZIndex': 600 }).subscribe(
            res => {
                if (res && Object.is('OK', res.ret)) {
                    res.activeLink = tag;
                    this.onLinkWindowClose(res);
                    // this.clearTickTimer();
                    // this.allTick();
                }
            }
        );
        // this.allTick();
        // this.modalTick();
    }

    /**
     * 
     * 
     * @returns {string} 
     * @memberof IBizWFDesignField2
     */
    public newGuid(): string {
        let guid = '';
        for (let i = 1; i <= 32; i++) {
            let n = Math.floor(Math.random() * 16.0).toString(16);
            guid += n;
            if ((i === 8) || (i === 12) || (i === 16) || (i === 20)) {
                guid += '-';
            }
        }
        return guid;
    }

    /**
     * 节点编辑视图关闭回调
     * 
     * @param {any} res 
     * @returns {*} 
     * @memberof IBizWFDesignField2
     */
    public onNodeWindowClose(res: any): any {
        let node = res.activeNode;
        let activeData = res.activeData;
        if (!activeData) {
            console.log('没有返回任何数据!');
            return;
        }
        let xml: any = {};
        Object.assign(xml, activeData);

        node.setProperty('oryx-name', xml[this.workFlow.NODE.name]);
        node.setProperty('oryx-documentation', xml[this.workFlow.NODE.id]);
        this.$flowFrame.updateProcess(node);
        this.$valueChangeSubject.next(this.getValue());
    }

    /**
     * 链接线编辑视图关闭回调
     * 
     * @param {any} win 
     * @param {any} eOpts 
     * @returns 
     * @memberof IBizWFDesignField2
     */
    public onLinkWindowClose(res: any): void {
        let link = res.activeLink;
        let activeData = res.activeData;
        if (!activeData) {
            console.log('没有返回任何数据!');
            return;
        }

        let xml: any = {};
        Object.assign(xml, activeData);
        // let logicname = xml.logicname;
        // if (!logicname) {
        //     logicname = xml.pswflinkname;
        // }
        link.setProperty('oryx-name', xml[this.workFlow.LINK.name]);
        link.setProperty('oryx-documentation', xml[this.workFlow.LINK.id]);

        // 更新
        this.$flowFrame.updateConnection(link);
        this.$valueChangeSubject.next(this.getValue());
    }

    /**
     * 对创建的模态框及其子组件进行脏检查，检查完毕后进行一次全局脏检查
     * 
     * @private
     * @memberof IBizWFDesignField2
     */
    public allTick(): void {
        for (let i = 0; i < 3; i++) {
            setTimeout(() => {
                // this.$applicationRef.tick();
            }, 300);
        }
    }

    /**
     * 对打开的模态框进行脏检查
     *
     * @memberof IBizWFDesignField2
     */
    public modalTick(): void {
        let components: any[] = this.$applicationRef.components;
        if (this.$tickTimer) {
            clearInterval(this.$tickTimer);
            this.$tickTimer = undefined;
        }
        this.$tickTimer = setInterval(() => {
            // this.$applicationRef.tick();
        }, 100);
    }

    /**
     * 清除脏检查定时器
     *
     * @memberof IBizWFDesignField2
     */
    public clearTickTimer(): void {
        if (this.$tickTimer) {
            clearInterval(this.$tickTimer);
            this.$tickTimer = undefined;
        }
    }

    /**
     * 使用该方法订阅工作流值改变
     * 
     * @returns {Observable<string>} 
     * @memberof IBizWFDesignField2
     */
    public wfDataChange(): Observable<string> {
        return this.$valueChangeSubject.asObservable();
    }

}