package cn.axzo.workflow.core.engine.behavior;

import org.flowable.bpmn.model.Activity;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.flowable.engine.impl.bpmn.helper.SkipExpressionUtil;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.util.CommandContextUtil;

import java.util.Collection;
import java.util.Iterator;

/**
 * 自定义多实例(并行)活动行为处理器
 * <p>
 * 主要用来解决多实例自动跳过时,历史的任务实例表中没有该节点的信息
 *
 * @author wangli
 * @since 2023/7/29 00:25
 */
public class CustomParallelMultiInstanceBehavior extends ParallelMultiInstanceBehavior {
    public CustomParallelMultiInstanceBehavior(Activity activity,
                                               AbstractBpmnActivityBehavior originalActivityBehavior) {
        super(activity, originalActivityBehavior);
    }

    @Override
    protected int resolveNrOfInstances(DelegateExecution execution) {
        UserTask userTask = (UserTask) execution.getCurrentFlowElement();
        boolean skipUserTask = SkipExpressionUtil.isSkipExpressionEnabled(userTask.getSkipExpression(),
                userTask.getId(), execution, CommandContextUtil.getCommandContext())
                && SkipExpressionUtil.shouldSkipFlowElement(userTask.getSkipExpression(), userTask.getId(), execution
                , CommandContextUtil.getCommandContext());
        int resolveNrOfInstances = super.resolveNrOfInstances(execution);
        if (skipUserTask || resolveNrOfInstances == 0) {
            // 强制返回一个实例数, 虽然返回了需要创建 1 个任务实例, 但由于多实例也会最终调用 UserTaskActivityBehavior#execution
            // 也就是单实例的自动跳过逻辑, 也就完成了多实例的自动跳过的历史任务信息的记录.
            return 1;
        }
        return resolveNrOfInstances;
    }

    @Override
    protected void executeOriginalBehavior(DelegateExecution execution, ExecutionEntity multiInstanceRootExecution,
                                           int loopCounter) {
        if (usesCollection() && collectionElementVariable != null) {
            Collection collection = resolveAndValidateCollection(execution);

            Object value = null;
            int index = 0;
            if (collection != null && !collection.isEmpty()) {
                Iterator it = collection.iterator();
                while (index <= loopCounter) {
                    value = it.next();
                    index++;
                }
            }
            setLoopVariable(execution, collectionElementVariable, value);
        }

        execution.setCurrentFlowElement(activity);
        CommandContextUtil.getAgenda().planContinueMultiInstanceOperation((ExecutionEntity) execution,
                multiInstanceRootExecution, loopCounter);
    }
}
