001// --------------------------------------------------------------------------------
002// Copyright 2002-2026 Echo Three, LLC
003//
004// Licensed under the Apache License, Version 2.0 (the "License");
005// you may not use this file except in compliance with the License.
006// You may obtain a copy of the License at
007//
008//     http://www.apache.org/licenses/LICENSE-2.0
009//
010// Unless required by applicable law or agreed to in writing, software
011// distributed under the License is distributed on an "AS IS" BASIS,
012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013// See the License for the specific language governing permissions and
014// limitations under the License.
015// --------------------------------------------------------------------------------
016
017package com.echothree.model.control.workflow.server.logic;
018
019import com.echothree.control.user.workflow.common.spec.WorkflowStepUniversalSpec;
020import com.echothree.model.control.core.common.ComponentVendors;
021import com.echothree.model.control.core.common.EntityTypes;
022import com.echothree.model.control.core.common.exception.InvalidParameterCountException;
023import com.echothree.model.control.core.server.control.EntityInstanceControl;
024import com.echothree.model.control.core.server.logic.EntityInstanceLogic;
025import com.echothree.model.control.workflow.common.exception.MissingRequiredWorkflowNameException;
026import com.echothree.model.control.workflow.common.exception.UnknownDefaultWorkflowStepException;
027import com.echothree.model.control.workflow.common.exception.UnknownWorkflowStepNameException;
028import com.echothree.model.control.workflow.server.control.WorkflowControl;
029import com.echothree.model.data.core.server.entity.EntityInstance;
030import com.echothree.model.data.workflow.server.entity.Workflow;
031import com.echothree.model.data.workflow.server.entity.WorkflowEntityStatus;
032import com.echothree.model.data.workflow.server.entity.WorkflowStep;
033import com.echothree.util.common.exception.BaseException;
034import com.echothree.util.common.message.ExecutionErrors;
035import com.echothree.util.common.persistence.BasePK;
036import com.echothree.util.server.control.BaseLogic;
037import com.echothree.util.server.message.ExecutionErrorAccumulator;
038import com.echothree.util.server.persistence.BaseEntity;
039import com.echothree.util.server.persistence.EntityPermission;
040import com.echothree.util.server.validation.ParameterUtils;
041import java.util.Arrays;
042import java.util.HashSet;
043import java.util.Set;
044import javax.enterprise.context.ApplicationScoped;
045import javax.inject.Inject;
046
047@ApplicationScoped
048public class WorkflowStepLogic
049        extends BaseLogic {
050
051    @Inject
052    EntityInstanceControl entityInstanceControl;
053
054    @Inject
055    WorkflowControl workflowControl;
056
057    @Inject
058    EntityInstanceLogic entityInstanceLogic;
059
060    @Inject
061    WorkflowLogic workflowLogic;
062
063    protected WorkflowStepLogic() {
064        super();
065    }
066
067    public WorkflowStep getWorkflowStepByName(final Class<? extends BaseException> unknownWorkflowException, final ExecutionErrors unknownWorkflowExecutionError,
068            final Class<? extends BaseException>  unknownWorkflowStepException, final ExecutionErrors unknownWorkflowStepExecutionError,
069            final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName) {
070        var workflow = workflowLogic.getWorkflowByName(unknownWorkflowException, unknownWorkflowExecutionError,
071                eea, workflowName, EntityPermission.READ_ONLY);
072        WorkflowStep workflowStep = null;
073
074        if(eea == null || !eea.hasExecutionErrors()) {
075            workflowStep = getWorkflowStepByName(unknownWorkflowStepException, unknownWorkflowStepExecutionError, eea,
076                    workflow, workflowStepName);
077        }
078
079        return workflowStep;
080    }
081
082    public WorkflowStep getWorkflowStepByName(final Class<? extends BaseException> unknownException, final ExecutionErrors unknownExecutionError,
083            final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName, EntityPermission entityPermission) {
084        var workflowStep = workflowControl.getWorkflowStepByName(workflow, workflowStepName, entityPermission);
085
086        if(workflowStep == null) {
087            handleExecutionError(unknownException, eea, unknownExecutionError.name(), workflow.getLastDetail().getWorkflowName(),
088                    workflowStepName);
089        }
090
091        return workflowStep;
092    }
093
094    public WorkflowStep getWorkflowStepByName(final Class<? extends BaseException> unknownException, final ExecutionErrors unknownExecutionError,
095            final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) {
096        return getWorkflowStepByName(unknownException, unknownExecutionError, eea, workflow, workflowStepName, EntityPermission.READ_ONLY);
097    }
098
099    public WorkflowStep getWorkflowStepByNameForUpdate(final Class<? extends BaseException> unknownException, final ExecutionErrors unknownExecutionError,
100            final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) {
101        return getWorkflowStepByName(unknownException, unknownExecutionError, eea, workflow, workflowStepName, EntityPermission.READ_WRITE);
102    }
103
104    public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName,
105            final EntityPermission entityPermission) {
106        return getWorkflowStepByName(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName,
107                eea, workflow, workflowStepName, entityPermission);
108    }
109
110    public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) {
111        return getWorkflowStepByName(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName,
112                eea, workflow, workflowStepName);
113    }
114
115    public WorkflowStep getWorkflowStepByNameForUpdate(final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) {
116        return getWorkflowStepByNameForUpdate(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName,
117                eea, workflow, workflowStepName);
118    }
119
120    public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName,
121            final EntityPermission entityPermission) {
122        var workflow = workflowLogic.getWorkflowByName(eea, workflowName);
123        WorkflowStep workflowStep = null;
124
125        if(eea == null || !eea.hasExecutionErrors()) {
126            workflowStep = getWorkflowStepByName(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName,
127                    eea, workflow, workflowStepName, entityPermission);
128        }
129
130        return workflowStep;
131    }
132
133    public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName) {
134        return getWorkflowStepByName(eea, workflowName, workflowStepName, EntityPermission.READ_ONLY);
135    }
136
137    public WorkflowStep getWorkflowStepByNameForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName) {
138        return getWorkflowStepByName(eea, workflowName, workflowStepName, EntityPermission.READ_WRITE);
139    }
140
141    public WorkflowStep getWorkflowStepByUniversalSpec(final ExecutionErrorAccumulator eea, final WorkflowStepUniversalSpec universalSpec,
142            final boolean allowDefault, final EntityPermission entityPermission) {
143        var workflowName = universalSpec.getWorkflowName();
144        var workflowStepName = universalSpec.getWorkflowStepName();
145        var nameParameterCount= ParameterUtils.getInstance().countNonNullParameters(workflowName, workflowStepName);
146        var possibleEntitySpecs= entityInstanceLogic.countPossibleEntitySpecs(universalSpec);
147        WorkflowStep workflowStep = null;
148
149        if(nameParameterCount < 3 && possibleEntitySpecs == 0) {
150            Workflow workflow = null;
151
152            if(workflowName != null) {
153                workflow = workflowLogic.getWorkflowByName(eea, workflowName);
154            } else {
155                handleExecutionError(MissingRequiredWorkflowNameException.class, eea, ExecutionErrors.MissingRequiredWorkflowName.name());
156            }
157
158            if(eea == null || !eea.hasExecutionErrors()) {
159                if(workflowStepName == null) {
160                    if(allowDefault) {
161                        workflowStep = workflowControl.getDefaultWorkflowStep(workflow, entityPermission);
162
163                        if(workflowStep == null) {
164                            handleExecutionError(UnknownDefaultWorkflowStepException.class, eea, ExecutionErrors.UnknownDefaultWorkflowStep.name());
165                        }
166                    } else {
167                        handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
168                    }
169                } else {
170                    workflowStep = getWorkflowStepByName(eea, workflow, workflowStepName, entityPermission);
171                }
172            }
173        } else if(nameParameterCount == 0 && possibleEntitySpecs == 1) {
174            var entityInstance = entityInstanceLogic.getEntityInstance(eea, universalSpec,
175                    ComponentVendors.ECHO_THREE.name(), EntityTypes.WorkflowStep.name());
176
177            if(eea == null || !eea.hasExecutionErrors()) {
178                workflowStep = workflowControl.getWorkflowStepByEntityInstance(entityInstance, entityPermission);
179            }
180        } else {
181            handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
182        }
183
184        return workflowStep;
185    }
186
187    public WorkflowStep getWorkflowStepByUniversalSpec(final ExecutionErrorAccumulator eea, final WorkflowStepUniversalSpec universalSpec,
188            boolean allowDefault) {
189        return getWorkflowStepByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_ONLY);
190    }
191
192    public WorkflowStep getWorkflowStepByUniversalSpecForUpdate(final ExecutionErrorAccumulator eea, final WorkflowStepUniversalSpec universalSpec,
193            boolean allowDefault) {
194        return getWorkflowStepByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_WRITE);
195    }
196
197    public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BaseEntity baseEntity,
198            String... workflowStepNames) {
199        return isEntityInWorkflowSteps(eea, workflowName, baseEntity, EntityPermission.READ_ONLY, workflowStepNames);
200    }
201    
202    public Set<WorkflowEntityStatus> isEntityInWorkflowStepsForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final BaseEntity baseEntity,
203            String... workflowStepNames) {
204        return isEntityInWorkflowSteps(eea, workflowName, baseEntity, EntityPermission.READ_WRITE, workflowStepNames);
205    }
206    
207    public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BaseEntity baseEntity,
208            EntityPermission entityPermission, String... workflowStepNames) {
209        return isEntityInWorkflowSteps(eea, workflowName, baseEntity.getPrimaryKey(), entityPermission, workflowStepNames);
210    }
211
212    public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BasePK pk,
213            String... workflowStepNames) {
214        return isEntityInWorkflowSteps(eea, workflowName, pk, EntityPermission.READ_ONLY, workflowStepNames);
215    }
216    
217    public Set<WorkflowEntityStatus> isEntityInWorkflowStepsForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final BasePK pk,
218            String... workflowStepNames) {
219        return isEntityInWorkflowSteps(eea, workflowName, pk, EntityPermission.READ_WRITE, workflowStepNames);
220    }
221    
222    public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BasePK pk,
223            EntityPermission entityPermission, String... workflowStepNames) {
224        var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(pk);
225        
226        return isEntityInWorkflowSteps(eea, workflowName, entityInstance, entityPermission, workflowStepNames);
227    }
228
229    public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final EntityInstance entityInstance,
230            final String... workflowStepNames) {
231        return isEntityInWorkflowSteps(eea, workflowName, entityInstance, EntityPermission.READ_ONLY, workflowStepNames);
232    }
233    
234    public Set<WorkflowEntityStatus> isEntityInWorkflowStepsForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final EntityInstance entityInstance,
235            final String... workflowStepNames) {
236        return isEntityInWorkflowSteps(eea, workflowName, entityInstance, EntityPermission.READ_WRITE, workflowStepNames);
237    }
238    
239    private Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final EntityInstance entityInstance,
240            final EntityPermission entityPermission, final String... workflowStepNames) {
241        var workflow = workflowLogic.getWorkflowByName(eea, workflowName);
242        Set<WorkflowEntityStatus> result = new HashSet<>();
243        
244        if(!hasExecutionErrors(eea)) {
245            var workflowEntityStatuses = workflowControl.getWorkflowEntityStatusesByEntityInstance(workflow, entityInstance, entityPermission);
246            Set<String> possibleWorkflowStepNames = new HashSet<>(workflowStepNames.length);
247            
248            possibleWorkflowStepNames.addAll(Arrays.asList(workflowStepNames));
249            
250            workflowEntityStatuses.forEach((workflowEntityStatus) -> {
251                var workflowStepDetail = workflowEntityStatus.getWorkflowStep().getLastDetail();
252                if (workflowStepDetail.getWorkflow().equals(workflow)) {
253                    var workflowStepName = workflowStepDetail.getWorkflowStepName();
254                    if (possibleWorkflowStepNames.contains(workflowStepName)) {
255                        result.add(workflowEntityStatus);
256                    }
257                }
258            });
259
260        }
261
262        return result;
263    }
264    
265    public boolean isWorkflowStepInSet(Set<WorkflowEntityStatus> workflowEntityStatuses, String workflowStepName) {
266        var result = false;
267        
268        for(var workflowEntityStatus : workflowEntityStatuses) {
269            if(result |= workflowEntityStatus.getWorkflowStep().getLastDetail().getWorkflowStepName().equals(workflowStepName)) {
270                break;
271            }
272        }
273        
274        return result;
275    }
276
277}