import { AppServiceBase, KanbanControlInterface, Util } from 'ibiz-core';
import { MDControlBase } from './md-control-base';
import { AppGlobalService, AppViewLogicService } from '../app-service';
import { AppKanbanService } from '../ctrl-service';
import { IPSAppDEKanbanView, IPSAppView, IPSAppViewRef, IPSCodeList, IPSDEKanban } from '@ibiz/dynamic-model-api';
import { Subject, Subscription } from 'rxjs';
/**
 * 看板视图部件基类
 * 
 * @export
 * @class KanbanControlBase
 * @extends {MDControlBase}
 */
export class KanbanControlBase extends MDControlBase implements KanbanControlInterface {

    /**
     * 看板数据
     * 
     * @type {Array<any>}
     * @memberof KanbanControlBase
     */
    public items: Array<any> = [];

    /**
     * 看板部件模型实例
     * 
     * @type {IPSDEKanban}
     * @memberof KanbanControlBase
     */
    public declare controlInstance: IPSDEKanban;

    /**
     * 加载的数据是否附加在items之后
     *
     * @type {boolean}
     * @memberof KanbanControlBase
     */
    public isAddBehind: boolean = false;

    /**
     * 代码表数据
     *
     * @type {Array<any>}
     * @memberof KanbanControlBase
     */
    public allCodeList: Array<any> = [];

    /**
     * 是否分组
     *
     * @type {string}
     * @memberof KanbanControlBase
     */
    public isGroup: boolean = true;

    /**
     * 分组集合
     *
     * @type {string}
     * @memberof KanbanControlBase
     */
    public groups: any[] = [];

    /**
     * 分组属性名称
     *
     * @type {string}
     * @memberof KanbanControlBase
     */
    public groupField: string = '';

    /**
     * 分组模式
     *
     * @type {string}
     * @memberof KanbanControlBase
     */
    public groupMode: string = '';

    /**
     * 分组代码表
     *
     * @type {string}
     * @memberof KanbanControlBase
     */
    public declare groupCodeList: any;

    /**
     * 部件行为--updateGroupAction
     *
     * @type {string}
     * @memberof KanbanControlBase
     */
    public updateGroupAction?: string;

    /**
     * this引用
     *
     * @type {number}
     * @memberof KanbanControlBase
     */
    public thisRef: any = this;

    /**
     * 状态事件
     * 
     * @memberof KanbanControlBase
     */
    public kanbanStateEvent: Subscription | undefined;

     /**
      * @description 看板部件事件
      * @type {(Subscription | undefined)}
      * @memberof KanbanControlBase
      */
    public kanbanControlEvent: Subscription | undefined;

    /**
     * 部件模型数据初始化
     *
     * @param {*} [args]
     * @memberof KanbanControlBase
     */
    public async ctrlModelInit(args?: any) {
        await super.ctrlModelInit();
        if (!(this.Environment && this.Environment.isPreviewMode)) {
            this.service = new AppKanbanService(this.controlInstance, this.context, { localSourceTag: this.localSourceTag });
        }
        this.limit = this.controlInstance?.pagingSize ? this.controlInstance.pagingSize : 20;
        this.minorSortPSDEF = this.controlInstance.getMinorSortPSAppDEField()?.codeName?.toLowerCase() || '';
        this.minorSortDir = this.controlInstance.minorSortDir;
        this.groupField = this.controlInstance.getGroupPSAppDEField()?.codeName?.toLowerCase() || "";
        this.isGroup = this.controlInstance?.enableGroup;
        this.groupMode = this.controlInstance?.groupMode;
        this.updateGroupAction = this.controlInstance.getUpdateGroupPSControlAction()?.actionName;
        const codeList: IPSCodeList | null = this.controlInstance.getGroupPSCodeList();
        await codeList?.fill();
        this.groupCodeList = codeList ? { type: codeList.codeListType, tag: codeList.codeName, data: codeList } : {};
    }

    /**
     * 部件事件
     * 
     * @param {string} controlname
     * @param {string} action
     * @param {*} data
     * @memberof KanbanControlBase
     */
    public onCtrlEvent(controlname: string, action: string, data: any) {
        if (action == 'panelDataChange') {
            this.onPanelDataChange(data.item, data.data);
        } else {
            super.onCtrlEvent(controlname, action, data);
        }
    }

    /**
     * 计算项布局面板部件所需参数
     *
     * @param {*} controlInstance
     * @param {*} item
     * @returns
     * @memberof KanbanControlBase
     */
    public computeTargetCtrlData(controlInstance: any, item?: any) {
        const { targetCtrlName, targetCtrlParam, targetCtrlEvent } = super.computeTargetCtrlData(controlInstance);
        Object.assign(targetCtrlParam.dynamicProps, {
            navdatas: [item],
            actionModel: this.actionModel,
        })
        Object.assign(targetCtrlParam.staticProps, {
            transformData: this.transformData,
            opendata: this.opendata,
            newdata: this.newdata,
            remove: this.remove,
            refresh: this.refresh,
        })
        targetCtrlEvent['ctrl-event'] = ({ controlname, action, data }: { controlname: string, action: string, data: any }) => {
            this.onCtrlEvent(controlname, action, { item: item, data: data });
        };
        return { targetCtrlName, targetCtrlParam, targetCtrlEvent };
    }

    /**
     * 执行mounted后的逻辑
     *
     *  @memberof KanbanControlBase
     */
    public ctrlMounted() {
        super.ctrlMounted();
        if (!this.isEnablePagingBar) {
            this.$el.addEventListener('scroll', () => {
                if (this.$el.scrollTop + this.$el.clientHeight >= this.$el.scrollHeight) {
                    this.loadMore();
                }
            })
        }
    }

    /**
     * 初始化看板部件
     *
     * @memberof KanbanControlBase
     */
    public ctrlInit() {
        super.ctrlInit();
        // 绑定this
        this.transformData = this.transformData.bind(this);
        this.remove = this.remove.bind(this);
        this.refresh = this.refresh.bind(this);

        if (this.viewState) {
            this.kanbanControlEvent = this.viewState.subscribe(({ tag, action, data }: any) => {
                if (!Object.is(this.name, tag)) {
                    return;
                }
                if (Object.is(action, 'load')) {
                    this.refresh(data)
                }
                if (Object.is(action, 'filter')) {
                    this.refresh(data)
                }
            });
        }
    }

    /**
     * 看板数据加载
     *
     * @param {*} [opt={}] 额外参数
     * @param {boolean} [isReset=false] 是否重置items
     * @return {*} 
     * @memberof KanbanControlBase
     */
    public async load(opt: any = {}, isReset: boolean = false) {
        if (!this.fetchAction) {
            this.$throw(this.$t('app.kanban.notconfig.fetchaction'), 'load');
            return;
        }
        const arg: any = { ...opt };
        const page: any = {};
        if (this.isEnablePagingBar) {
            Object.assign(page, { page: this.curPage - 1, size: this.limit });
        }
        // 设置排序
        if (!Object.is(this.minorSortDir, '') && !Object.is(this.minorSortPSDEF, '')) {
            const sort: string = this.minorSortPSDEF + "," + this.minorSortDir;
            Object.assign(page, { sort: sort });
        }
        Object.assign(arg, page);
        const parentdata: any = {};
        this.$emit("ctrl-event", { controlname: "kanban", action: "beforeload", data: parentdata });
        Object.assign(arg, parentdata);
        let tempViewParams: any = parentdata.viewparams ? parentdata.viewparams : {};
        Object.assign(tempViewParams, Util.deepCopy(this.viewparams));
        Object.assign(arg, { viewparams: tempViewParams });
        let tempContext: any = Util.deepCopy(this.context);
        if (!(await this.handleCtrlEvents('onbeforeload', { action: this.fetchAction, navContext: tempContext, navParam: arg }))) {
            return;
        }
        this.onControlRequset('load', tempContext, arg);
        try {
            const response: any = await this.service.search(this.fetchAction, tempContext, arg, this.showBusyIndicator);
            this.onControlResponse('load', response);
            if (!response || response.status !== 200) {
                if (!(await this.handleCtrlEvents('onloaderror', { action: this.fetchAction, navParam: arg, data: response?.data }))) {
                    return;
                }
                this.$throw(response, 'load');
                return;
            }
            const data: any = response.data;
            if (!(await this.handleCtrlEvents('onloadsuccess', { action: this.fetchAction, navParam: arg, data: data }))) {
                return;
            }
            if (!this.isAddBehind) {
                this.items = [];
            }
            if (Object.keys(data).length > 0) {
                let datas = Util.deepCopy(data);
                datas.map((item: any) => {
                    if (!item.srfchecked) {
                        Object.assign(item, { srfchecked: 0 });
                    }
                });
                this.totalRecord = response.total;
                if (isReset) {
                    this.items = datas;
                } else {
                    this.items.push(...datas);
                }
            }
            this.isAddBehind = false;
            this.setGroups();
            this.$emit("ctrl-event", { controlname: "kanban", action: "load", data: this.items });
            if (this.isSelectFirstDefault) {
                this.handleClick(this.items[0]);
            }
        } catch (error: any) {
            this.onControlResponse('load', error);
            if (!(await this.handleCtrlEvents('onloaderror', { action: this.fetchAction, navParam: arg, data: error?.data }))) {
                return;
            }
            this.$throw(error, 'load');
        }
    }

    /**
     * 加载更多
     *
     * @memberof KanbanControlBase
     */
    public loadMore() {
        if (this.totalRecord > this.items.length) {
            this.curPage = ++this.curPage;
            this.isAddBehind = true;
            this.load({});
        }
    }

    /**
     * 刷新
     *
     * @param {*} [opt={}] 额外参数
     * @memberof KanbanControlBase
     */
    public refresh(args: any = {}) {
        this.curPage = 1;
        this.load(args, true);
    }

    /**
     * 删除
     *
     * @param {any[]} datas 删除数据
     * @returns {Promise<any>}
     * @memberof KanbanControlBase
     */
    public async remove(datas: any[]): Promise<any> {
        if (!this.removeAction) {
            this.$throw(`${this.controlInstance.codeName}` + (this.$t('app.kanban.notconfig.removeaction') as string), 'remove');
            return;
        }
        let _datas: any[] = [];
        datas.forEach((record: any, index: number) => {
            if (Object.is(record.srfuf, '0')) {
                this.items.some((val: any, num: number) => {
                    if (JSON.stringify(val) == JSON.stringify(record)) {
                        this.items.splice(num, 1);
                        return true;
                    }
                });
            } else {
                _datas.push(datas[index]);
            }
        });
        if (_datas.length === 0) {
            return;
        }
        let dataInfo = '';
        _datas.forEach((record: any, index: number) => {
            let srfmajortext = record.srfmajortext;
            if (index < 5) {
                if (!Object.is(dataInfo, '')) {
                    dataInfo += '、';
                }
                dataInfo += srfmajortext;
            } else {
                return false;
            }
        });

        if (_datas.length < 5) {
            dataInfo = dataInfo + this.$t('app.dataview.sum') + _datas.length + this.$t('app.dataview.data');
        } else {
            dataInfo = dataInfo + '...' + this.$t('app.dataview.sum') + _datas.length + this.$t('app.dataview.data');
        }

        const removeData = async () => {
            let keys: any[] = [];
            _datas.forEach((data: any) => {
                keys.push(data.srfkey);
            });
            let _removeAction = this.removeAction;

            let tempContext: any = Util.deepCopy(this.context);
            let _keys = keys.length > 1 ? keys : keys[0];
            let arg: any = { [(this.controlInstance.getPSAppDataEntity as any).codeName?.toLowerCase()]: _keys };
            Object.assign(arg, { viewparams: this.viewparams });
            if (!(await this.handleCtrlEvents('onbeforeremove', { action: this.removeAction, navParam: arg, data: keys }))) {
                return;
            }
            this.onControlRequset('remove', tempContext, arg);            
            let promises: any;
            //逻辑更改
            if (keys && keys.length > 1) {
                let promiseArr: any = [];
                _keys.forEach((ele: any) => {
                    Object.assign(tempContext, { [this.appDeCodeName?.toLowerCase()]: ele });
                    promiseArr.push(this.service.delete(_removeAction, tempContext, arg, this.showBusyIndicator));
                })
                promises = Promise.all(promiseArr);
            } else {
                Object.assign(tempContext, { [this.appDeCodeName?.toLowerCase()]: _keys });
                promises = this.service.delete(_removeAction, tempContext, arg, this.showBusyIndicator);
            }
            return new Promise((resolve: any, reject: any) => {
                promises.then(async (response: any) => {
                    this.onControlResponse('remove', response);
                    if (!response || response.status !== 200 && !Array.isArray(response)) {
                        if (!(await this.handleCtrlEvents('onremoveerror', { action: this.removeAction, navParam: arg, data: response?.data }))) {
                            return;
                        }
                        this.$throw((this.$t('app.commonwords.deldatafail') as string) + ',' + response.info, 'remove');
                        return;
                    } else {
                        if (!(await this.handleCtrlEvents('onremovesuccess', { action: this.removeAction, navParam: arg, data: response?.data }))) {
                            return;
                        }
                        this.$success((this.$t('app.commonwords.deletesuccess') as string), 'remove');
                    }
                    //删除items中已删除的项
                    _datas.forEach((data: any) => {
                        this.items.some((item: any, index: number) => {
                            if (Object.is(item.srfkey, data.srfkey)) {
                                this.items.splice(index, 1);
                                return true;
                            }
                        });
                    });
                    this.$emit("ctrl-event", { controlname: "kanban", action: "remove", data: null });
                    this.selections = [];
                    this.refresh();
                }).catch(async (error: any) => {
                    this.onControlResponse('remove', error);
                    if (!(await this.handleCtrlEvents('onremoveerror', { action: this.removeAction, navParam: arg, data: error?.data }))) {
                        return;
                    }
                    this.$throw(error, 'remove');
                })
            }) 
        }

        dataInfo = dataInfo.replace(/[null]/g, '').replace(/[undefined]/g, '').replace(/[ ]/g, '');
        this.$Modal.confirm({
            title: (this.$t('app.commonwords.warning') as string),
            content: (this.$t('app.kanban.delete1') as string) + dataInfo + ',' + (this.$t('app.kanban.delete2') as string),
            onOk: () => {
                removeData();
            },
            onCancel: () => { }
        });
        return removeData;
    }

    /**
     * 界面行为
     *
     * @param {*} detail 界面行为
     * @param {*} $event 事件源
     * @param {*} group 看板分组
     * @memberof KanbanControlBase
     */
    public uiActionClick(detail: any, $event: any, group: any) {
        let row = this.selections.length > 0 && group.items.includes(this.selections[0]) ? this.selections[0] : {};
        if (!row.hasOwnProperty('srfgroup')) {
            Object.assign(row, { srfgroup: group.value });
        }
        if (AppServiceBase.getInstance().getEnableUIModelEx()) {
            AppGlobalService.getInstance().executeGlobalUIAction(detail.getPSUIAction(), $event, this, undefined, row);
        } else {
            AppViewLogicService.getInstance().executeViewLogic(this.getViewLogicTag(this.controlInstance.name, 'group', detail.name), $event, this, row, this.controlInstance?.getPSAppViewLogics() as any);
        }
    }

    /**
     * 面板数据变化处理事件
     * @param {any} item 当前列数据
     * @param {any} $event 面板事件数据
     *
     * @memberof KanbanControlBase
     */
    public onPanelDataChange(item: any, $event: any) {
        Object.assign(item, $event, { rowDataState: 'update' });
    }

    /**
     * 拖拽结束
     * 
     */
    public onDragEnd() {
        this.$forceUpdate();
    }

    /**
     * 拖拽变化
     *
     * @param {*} evt 拖住对象
     * @param {*} name 分组名
     * @memberof KanbanControlBase
     */
    public async onDragChange(evt: any, name: string) {
        if (evt?.added?.element) {
            let item: any = Util.deepCopy(evt.added.element)
            let updateView: IPSAppView | null = await this.getUpdateView(name);
            if (updateView) {
                let view: any = {
                    viewname: 'app-view-shell',
                    height: updateView.height,
                    width: updateView.width,
                    title: this.$tl(updateView.getTitlePSLanguageRes()?.lanResTag, updateView.title),
                };
                const _context: any = Util.deepCopy(this.context);
                const _param: any = Util.deepCopy(this.viewparams);
                Object.assign(_context, { [this.appDeCodeName.toLowerCase()]: item.srfkey });
                if (updateView && updateView.modelPath) {
                    Object.assign(_context, { viewpath: updateView.modelPath });
                }
                let container: Subject<any>;
                if (updateView.openMode && !Object.is(updateView.openMode, '') && updateView.openMode.indexOf('DRAWER') !== -1) {
                    if (Object.is(updateView.openMode, 'DRAWER_TOP')) {
                        Object.assign(view, { isfullscreen: true });
                        container = this.$appdrawer.openTopDrawer(
                            view,
                            Util.getViewProps(_context, _param),
                        );
                    } else {
                        Object.assign(view, { placement: updateView.openMode });
                        container = this.$appdrawer.openDrawer(view, Util.getViewProps(_context, _param));
                    }
                } else {
                    container = this.$appmodal.openModal(view, _context, _param);
                }
                this.kanbanStateEvent = container.subscribe((result: any) => {
                    if (!result || !Object.is(result.ret, 'OK')) {
                        this.setGroups();
                        return;
                    }
                    this.refresh();
                });
            } else {
                await this.updateData(item, name)
            }
        }
    }

    /**
     * 修改分组集合
     *
     * @param {*} opt 数据
     * @param {*} newVal 新分组值
     * @memberof KanbanControlBase
     */
    public async updateData(opt: any, newVal: any) {
        const oldVal = opt[this.groupField];
        if (newVal) {
            opt[this.groupField] = newVal;
        }
        const arg: any = { ...opt };
        Object.assign(arg, { viewparams: this.viewparams });
        let tempContext: any = Util.deepCopy(this.context);
        if (this.controlInstance.getPSAppDataEntity()?.codeName) {
            Object.assign(tempContext, { [(this.controlInstance.getPSAppDataEntity()?.codeName?.toLowerCase() as string)]: opt.srfkey });
        }
        if (!(await this.handleCtrlEvents('onbeforedragchange', { action: this.updateGroupAction, navContext: tempContext, navParam: arg }))) {
            return;
        }
        this.onControlRequset('updateData', tempContext, arg);
        try {
            const response: any = await this.service.update(this.updateGroupAction, tempContext, arg, this.showBusyIndicator);
            this.onControlResponse('updateData', response);
            if (!response.status || response.status !== 200) {
                if (!(await this.handleCtrlEvents('ondragchangeerror', { action: this.updateGroupAction, navParam: arg, data: response?.data }))) {
                    return;
                }
                this.$throw(response, 'updateData');
                opt[this.groupField] = oldVal;
                this.setGroups();
                return;
            }
            let item = this.items.find((item: any) => Object.is(item.srfkey, response.data.srfkey));
            Object.assign(item, response.data);
            if (!(await this.handleCtrlEvents('ondragchangesuccess', { action: this.updateGroupAction, navParam: arg, data: response.data }))) {
                return;
            }
            this.setGroups();
            this.$emit("ctrl-event", { controlname: "kanban", action: "update", data: this.items });
        } catch (error: any) {
            this.onControlResponse('updateData', error);
            if (!(await this.handleCtrlEvents('ondragchangeerror', { action: this.updateGroupAction, navParam: arg, data: error?.data }))) {
                return;
            }
            opt[this.groupField] = oldVal;
            this.setGroups();
            this.$throw(error, 'updateData');
        }
    }

    /**
     * 单击事件
     * 
     * @param {*} args 数据
     * @memberof KanbanControlBase
     */
    public handleClick(args: any) {
        this.handleCtrlEvents('onrowclick', { action: 'RowClick', data: args }).then((res: boolean) => {
            if (res) {
                if (this.mDCtrlActiveMode === 1) {
                    this.ctrlEvent({ controlname: this.name, action: 'rowclick', data: args });
                    return;
                }
                args.srfchecked = Number(!args.srfchecked);
                this.items.forEach((item: any) => {
                    if (item.srfkey !== args.srfkey) {
                        item.srfchecked = 0;
                    }
                })
                this.selectchange();
            }
        });
    }

    /**
     * 双击事件
     *
     * @param {*} args 数据
     * @memberof KanbanControlBase
     */
    public handleDblClick(args: any) {
        this.handleCtrlEvents('onrowdblclick', { action: 'RowDBLClick', data: args }).then((res: boolean) => {
            if (res) {
                if (this.mDCtrlActiveMode !== 0) {
                    args.srfchecked = 1;
                    this.items.forEach((item: any) => {
                        if (item.srfkey !== args.srfkey) {
                            item.srfchecked = 0;
                        }
                    })
                    this.$emit("ctrl-event", { controlname: "kanban", action: "rowdblclick", data: args });
                }
            }
        });
    }

    /**
     * 触发事件
     * @memberof KanbanControlBase
     *
     */
    public selectchange() {
        this.selections = [];
        this.items.map((item: any) => {
            if (item.srfchecked === 1) {
                this.selections.push(item);
            }
        });
        this.$emit("ctrl-event", { controlname: "kanban", action: "selectionchange", data: this.selections });
    }

    /**
     * 点击时触发看板的展开和收起
     * 
     * @param group 分组看板
     * @param index 分组看板编号
     * @memberof KanbanControlBase
     */
    public onClick(group: any, index: number) {
        group.folding = !group.folding;
        this.$forceUpdate();
    }

    /**
     * 设置分组集合
     *
     * @memberof KanbanControlBase
     */
    public async setGroups() {
        let tempGroups: Array<any> = this.groups;
        if (!this.isGroup || !this.groupField || Object.is(this.groupMode, 'NONE')) {
            return;
        }
        if (Object.is(this.groupMode, 'AUTO')) {
            this.groups = [];
            this.items.forEach(item => {
                let group: any = this.groups.find((group: any) => Object.is(group.name, item[this.groupField]));
                let state: any = tempGroups.filter((temp: any) => Object.is(item[this.groupField], temp.value))[0];
                if (!group) {
                    this.groups.push({
                        name: item[this.groupField],
                        value: item[this.groupField],
                        folding: (state && !state.folding) ? state.folding : true,
                        items: this.getGroupItems(item[this.groupField])
                    })
                }
            });
        }
        if (Object.is(this.groupMode, 'CODELIST') && this.groupCodeList) {
            this.groups = [];
            let codelistItems: any = await this.codeListService.getDataItems({ ...this.groupCodeList, context: this.context });
            this.allCodeList = Util.deepCopy(codelistItems);
            if (codelistItems && codelistItems.length > 0) {
                codelistItems.forEach((item: any) => {
                    let state: any = tempGroups.filter((temp: any) => Object.is(item.value, temp.value))[0];
                    this.groups.push({
                        name: item.value,
                        value: item.value,
                        color: item.color,
                        folding: (state && !state.folding) ? state.folding : true,
                        items: this.getGroupItems(item.value)
                    })
                })
            }
        }
    }

    /**
     * 拖拽更新页面
     *
     * @param {string} group 分组名称
     * @memberof KanbanControlBase
     */
    public async getUpdateView(group: string) {
        if (!group) return null;
        let parentModel: IPSAppDEKanbanView = (this.controlInstance as any).parentModel;
        if (parentModel.getPSAppViewRefs() && (parentModel.getPSAppViewRefs() as IPSAppViewRef[]).length > 0) {
            let activeAppViewRef: any = parentModel.getPSAppViewRefs()?.find((item: IPSAppViewRef) => {
                return item.name === `EDITDATA:${group.toUpperCase()}`;
            })
            if (!activeAppViewRef || !activeAppViewRef.getRefPSAppView()) return null;
            const openView: IPSAppView = activeAppViewRef.getRefPSAppView();
            await openView.fill();
            return openView;
        } else {
            return null;
        }
    }

    /**
     * 获取对应分组的数据集合
     *
     * @param {string} name 分组值
     * @memberof KanbanControlBase
     */
    public getGroupItems(name: string) {
        let datas: any = [];
        this.items.forEach(item => {
            if (Object.is(item[this.groupField], name)) {
                datas.push(item);
            }
        })
        return datas;
    }

    /**
     * 获取分组的text
     *
     * @param {string} name 分组值
     * @memberof KanbanControlBase
     */
    public getGroupText(name: string) {
        if (Object.is(this.groupMode, 'CODELIST') && this.groupCodeList) {
            if (this.allCodeList && this.allCodeList.length > 0) {
                if (!name) {
                    return this.$t('app.chart.undefined');
                }
                let item = this.allCodeList.find((item: any) => Object.is(item.value, name));
                if (item) {
                    return item.text;
                }
            }
        } else {
            return name;
        }
    }

    /**
     * @description:部件订阅
     * 
     * @return {*}
     */ 
    public ctrlDestroyed(){
        super.ctrlDestroyed()
        if(this.kanbanStateEvent){
            this.kanbanStateEvent.unsubscribe();
        }
        if (this.kanbanControlEvent) {
            this.kanbanControlEvent.unsubscribe();
        }
    }
}