package com.qmth.distributed.print.business.activiti.custom.service;

import com.qmth.distributed.print.business.bean.flow.CustomFlowDto;
import com.qmth.distributed.print.business.bean.flow.link.FlowTaskLink;
import com.qmth.distributed.print.business.bean.flow.link.FlowTaskNode;
import com.qmth.distributed.print.business.enums.CustomFlowTypeEnum;
import org.activiti.bpmn.model.MultiInstanceLoopCharacteristics;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.el.ExpressionManager;
import org.springframework.beans.BeanUtils;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.StringJoiner;

/**
 * @Description: 并行/串行业务service
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2022/2/8
 */
public abstract class AbstractMultiWorkFlowService implements DefaultInstanceConvertToMultiInstance {

    @Resource
    protected ProcessEngine processEngine;

    /**
     * 创建多实例行为解释器
     *
     * @param id
     * @param isSequential 是否 串行
     * @return
     */
    @Override
    public MultiInstanceLoopCharacteristics createMultiInstanceLoopCharacteristics(String id, boolean isSequential) {
        return createMultiInstanceLoopCharacteristics(isSequential, new StringJoiner("")
                .add(MessageFormat.format("{0}{1}{2}", DEFAULT_ASSIGNEE_LIST_EXP, id, EXP_SUFFIX)).toString(), new StringJoiner("")
                .add(MessageFormat.format("{0}{1}", ASSIGNEE_USER, id)).toString());
    }

    /**
     * 创建多实例行为解释器
     *
     * @param isSequential    是否串行
     * @param assigneeListExp 用户组表达
     * @param assignee        用户标识
     * @return
     */
    @Override
    public MultiInstanceLoopCharacteristics createMultiInstanceLoopCharacteristics(boolean isSequential, String assigneeListExp, String assignee) {
        MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = new MultiInstanceLoopCharacteristics();
        multiInstanceLoopCharacteristics.setSequential(isSequential);
        multiInstanceLoopCharacteristics.setInputDataItem(assigneeListExp);
        multiInstanceLoopCharacteristics.setElementVariable(assignee);
        return multiInstanceLoopCharacteristics;
    }

    /**
     * 创建多实例 循环解释器
     *
     * @param userTask
     * @param sequential
     * @return
     */
    @Override
    public UserTask createMultiInstanceBehavior(UserTask userTask, boolean sequential) {
        String id = userTask.getId().substring(userTask.getId().length() - 1, userTask.getId().length());
        MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = this.createMultiInstanceLoopCharacteristics(id, sequential);
        multiInstanceLoopCharacteristics.setCompletionCondition(DefaultInstanceConvertToMultiInstance.REJECT_EXP + id + DefaultInstanceConvertToMultiInstance.REJECT_EXP_SUFFIX);
        userTask.setAssignee(new StringJoiner("").add(MessageFormat.format("{0}{1}{2}", ASSIGNEE_USER_EXP, id, EXP_SUFFIX)).toString());
        userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
        return createMultiInstanceBehavior(userTask, sequential, new StringJoiner("").add(MessageFormat.format("{0}{1}{2}", DEFAULT_ASSIGNEE_LIST_EXP, id, EXP_SUFFIX)).toString(), new StringJoiner("").add(MessageFormat.format("{0}{1}", ASSIGNEE_USER, id)).toString());
    }

    /**
     * 创建多实例 循环解释器
     *
     * @param userTask        流程节点
     * @param sequential      是否串行
     * @param assigneeListExp 用户组表达
     * @param assignee
     * @return
     */
    @Override
    public UserTask createMultiInstanceBehavior(UserTask userTask, boolean sequential, String assigneeListExp, String assignee) {
        ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration();
        //创建解释器
        UserTaskActivityBehavior userTaskActivityBehavior = processEngineConfiguration.getActivityBehaviorFactory().createUserTaskActivityBehavior(userTask);
        MultiInstanceActivityBehavior behavior = sequential ? new SequentialMultiInstanceBehavior(userTask, userTaskActivityBehavior) : new ParallelMultiInstanceBehavior(userTask, userTaskActivityBehavior);
        //注入表达式 解释器
        ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();
        //设置表达式变量
        behavior.setCollectionExpression(expressionManager.createExpression(assigneeListExp));
        behavior.setCollectionElementVariable(assignee);
        return userTask;
    }

    /**
     * 创建默认用户节点
     *
     * @param customFlowDto
     * @param flowTaskLink
     * @param id
     * @return
     */
    @Override
    public CustomFlowDto createDefaultUserTask(CustomFlowDto customFlowDto, FlowTaskLink flowTaskLink, String id) {
        CustomFlowDto customFlowDefaultDto = new CustomFlowDto();
        BeanUtils.copyProperties(customFlowDto, customFlowDefaultDto);
        customFlowDefaultDto.setId(id);
        customFlowDefaultDto.setSetup(1);
        customFlowDefaultDto.setType(CustomFlowTypeEnum.PROCESS);
        customFlowDefaultDto.setContent(DEFAULT_USER_TASK_NAME);
        customFlowDefaultDto.setH(customFlowDefaultDto.getH() + 30D);
        customFlowDefaultDto.setY(customFlowDefaultDto.getY() + 50D);
        customFlowDefaultDto.setFlowTaskId(CustomFlowTypeEnum.USER_TASK.getId() + id);
        FlowTaskNode nodeDefault = new FlowTaskNode(customFlowDefaultDto);
        flowTaskLink.add(nodeDefault);
        return customFlowDefaultDto;
    }

//    /**
//     * 更新atomicInteger值
//     *
//     * @param atomicInteger
//     * @return
//     */
//    @Override
//    public int getAndIncrement(AtomicInteger atomicInteger) {
//        int value = 1;
//        if (atomicInteger.get() >= Integer.MAX_VALUE) {
//            atomicInteger.compareAndSet(atomicInteger.get(), value);
//        } else {
//            value = atomicInteger.getAndIncrement();
//        }
//        return value;
//    }
}
