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.enterprise.inject.spi.CDI;
046import javax.inject.Inject;
047
048@ApplicationScoped
049public class WorkflowStepLogic
050        extends BaseLogic {
051
052    @Inject
053    EntityInstanceControl entityInstanceControl;
054
055    @Inject
056    WorkflowControl workflowControl;
057
058    @Inject
059    EntityInstanceLogic entityInstanceLogic;
060
061    @Inject
062    WorkflowLogic workflowLogic;
063
064    protected WorkflowStepLogic() {
065        super();
066    }
067
068    public static WorkflowStepLogic getInstance() {
069        return CDI.current().select(WorkflowStepLogic.class).get();
070    }
071
072    public WorkflowStep getWorkflowStepByName(final Class<? extends BaseException> unknownWorkflowException, final ExecutionErrors unknownWorkflowExecutionError,
073            final Class<? extends BaseException>  unknownWorkflowStepException, final ExecutionErrors unknownWorkflowStepExecutionError,
074            final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName) {
075        var workflow = workflowLogic.getWorkflowByName(unknownWorkflowException, unknownWorkflowExecutionError,
076                eea, workflowName, EntityPermission.READ_ONLY);
077        WorkflowStep workflowStep = null;
078
079        if(eea == null || !eea.hasExecutionErrors()) {
080            workflowStep = getWorkflowStepByName(unknownWorkflowStepException, unknownWorkflowStepExecutionError, eea,
081                    workflow, workflowStepName);
082        }
083
084        return workflowStep;
085    }
086
087    public WorkflowStep getWorkflowStepByName(final Class<? extends BaseException> unknownException, final ExecutionErrors unknownExecutionError,
088            final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName, EntityPermission entityPermission) {
089        var workflowStep = workflowControl.getWorkflowStepByName(workflow, workflowStepName, entityPermission);
090
091        if(workflowStep == null) {
092            handleExecutionError(unknownException, eea, unknownExecutionError.name(), workflow.getLastDetail().getWorkflowName(),
093                    workflowStepName);
094        }
095
096        return workflowStep;
097    }
098
099    public WorkflowStep getWorkflowStepByName(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_ONLY);
102    }
103
104    public WorkflowStep getWorkflowStepByNameForUpdate(final Class<? extends BaseException> unknownException, final ExecutionErrors unknownExecutionError,
105            final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) {
106        return getWorkflowStepByName(unknownException, unknownExecutionError, eea, workflow, workflowStepName, EntityPermission.READ_WRITE);
107    }
108
109    public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName,
110            final EntityPermission entityPermission) {
111        return getWorkflowStepByName(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName,
112                eea, workflow, workflowStepName, entityPermission);
113    }
114
115    public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) {
116        return getWorkflowStepByName(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName,
117                eea, workflow, workflowStepName);
118    }
119
120    public WorkflowStep getWorkflowStepByNameForUpdate(final ExecutionErrorAccumulator eea, final Workflow workflow, final String workflowStepName) {
121        return getWorkflowStepByNameForUpdate(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName,
122                eea, workflow, workflowStepName);
123    }
124
125    public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName,
126            final EntityPermission entityPermission) {
127        var workflow = workflowLogic.getWorkflowByName(eea, workflowName);
128        WorkflowStep workflowStep = null;
129
130        if(eea == null || !eea.hasExecutionErrors()) {
131            workflowStep = getWorkflowStepByName(UnknownWorkflowStepNameException.class, ExecutionErrors.UnknownWorkflowStepName,
132                    eea, workflow, workflowStepName, entityPermission);
133        }
134
135        return workflowStep;
136    }
137
138    public WorkflowStep getWorkflowStepByName(final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName) {
139        return getWorkflowStepByName(eea, workflowName, workflowStepName, EntityPermission.READ_ONLY);
140    }
141
142    public WorkflowStep getWorkflowStepByNameForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final String workflowStepName) {
143        return getWorkflowStepByName(eea, workflowName, workflowStepName, EntityPermission.READ_WRITE);
144    }
145
146    public WorkflowStep getWorkflowStepByUniversalSpec(final ExecutionErrorAccumulator eea, final WorkflowStepUniversalSpec universalSpec,
147            final boolean allowDefault, final EntityPermission entityPermission) {
148        var workflowName = universalSpec.getWorkflowName();
149        var workflowStepName = universalSpec.getWorkflowStepName();
150        var nameParameterCount= ParameterUtils.getInstance().countNonNullParameters(workflowName, workflowStepName);
151        var possibleEntitySpecs= entityInstanceLogic.countPossibleEntitySpecs(universalSpec);
152        WorkflowStep workflowStep = null;
153
154        if(nameParameterCount < 3 && possibleEntitySpecs == 0) {
155            Workflow workflow = null;
156
157            if(workflowName != null) {
158                workflow = workflowLogic.getWorkflowByName(eea, workflowName);
159            } else {
160                handleExecutionError(MissingRequiredWorkflowNameException.class, eea, ExecutionErrors.MissingRequiredWorkflowName.name());
161            }
162
163            if(eea == null || !eea.hasExecutionErrors()) {
164                if(workflowStepName == null) {
165                    if(allowDefault) {
166                        workflowStep = workflowControl.getDefaultWorkflowStep(workflow, entityPermission);
167
168                        if(workflowStep == null) {
169                            handleExecutionError(UnknownDefaultWorkflowStepException.class, eea, ExecutionErrors.UnknownDefaultWorkflowStep.name());
170                        }
171                    } else {
172                        handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
173                    }
174                } else {
175                    workflowStep = getWorkflowStepByName(eea, workflow, workflowStepName, entityPermission);
176                }
177            }
178        } else if(nameParameterCount == 0 && possibleEntitySpecs == 1) {
179            var entityInstance = entityInstanceLogic.getEntityInstance(eea, universalSpec,
180                    ComponentVendors.ECHO_THREE.name(), EntityTypes.WorkflowStep.name());
181
182            if(eea == null || !eea.hasExecutionErrors()) {
183                workflowStep = workflowControl.getWorkflowStepByEntityInstance(entityInstance, entityPermission);
184            }
185        } else {
186            handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
187        }
188
189        return workflowStep;
190    }
191
192    public WorkflowStep getWorkflowStepByUniversalSpec(final ExecutionErrorAccumulator eea, final WorkflowStepUniversalSpec universalSpec,
193            boolean allowDefault) {
194        return getWorkflowStepByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_ONLY);
195    }
196
197    public WorkflowStep getWorkflowStepByUniversalSpecForUpdate(final ExecutionErrorAccumulator eea, final WorkflowStepUniversalSpec universalSpec,
198            boolean allowDefault) {
199        return getWorkflowStepByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_WRITE);
200    }
201
202    public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BaseEntity baseEntity,
203            String... workflowStepNames) {
204        return isEntityInWorkflowSteps(eea, workflowName, baseEntity, EntityPermission.READ_ONLY, workflowStepNames);
205    }
206    
207    public Set<WorkflowEntityStatus> isEntityInWorkflowStepsForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final BaseEntity baseEntity,
208            String... workflowStepNames) {
209        return isEntityInWorkflowSteps(eea, workflowName, baseEntity, EntityPermission.READ_WRITE, workflowStepNames);
210    }
211    
212    public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BaseEntity baseEntity,
213            EntityPermission entityPermission, String... workflowStepNames) {
214        return isEntityInWorkflowSteps(eea, workflowName, baseEntity.getPrimaryKey(), entityPermission, workflowStepNames);
215    }
216
217    public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BasePK pk,
218            String... workflowStepNames) {
219        return isEntityInWorkflowSteps(eea, workflowName, pk, EntityPermission.READ_ONLY, workflowStepNames);
220    }
221    
222    public Set<WorkflowEntityStatus> isEntityInWorkflowStepsForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final BasePK pk,
223            String... workflowStepNames) {
224        return isEntityInWorkflowSteps(eea, workflowName, pk, EntityPermission.READ_WRITE, workflowStepNames);
225    }
226    
227    public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final BasePK pk,
228            EntityPermission entityPermission, String... workflowStepNames) {
229        var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(pk);
230        
231        return isEntityInWorkflowSteps(eea, workflowName, entityInstance, entityPermission, workflowStepNames);
232    }
233
234    public Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final EntityInstance entityInstance,
235            final String... workflowStepNames) {
236        return isEntityInWorkflowSteps(eea, workflowName, entityInstance, EntityPermission.READ_ONLY, workflowStepNames);
237    }
238    
239    public Set<WorkflowEntityStatus> isEntityInWorkflowStepsForUpdate(final ExecutionErrorAccumulator eea, final String workflowName, final EntityInstance entityInstance,
240            final String... workflowStepNames) {
241        return isEntityInWorkflowSteps(eea, workflowName, entityInstance, EntityPermission.READ_WRITE, workflowStepNames);
242    }
243    
244    private Set<WorkflowEntityStatus> isEntityInWorkflowSteps(final ExecutionErrorAccumulator eea, final String workflowName, final EntityInstance entityInstance,
245            final EntityPermission entityPermission, final String... workflowStepNames) {
246        var workflow = workflowLogic.getWorkflowByName(eea, workflowName);
247        Set<WorkflowEntityStatus> result = new HashSet<>();
248        
249        if(!hasExecutionErrors(eea)) {
250            var workflowEntityStatuses = workflowControl.getWorkflowEntityStatusesByEntityInstance(workflow, entityInstance, entityPermission);
251            Set<String> possibleWorkflowStepNames = new HashSet<>(workflowStepNames.length);
252            
253            possibleWorkflowStepNames.addAll(Arrays.asList(workflowStepNames));
254            
255            workflowEntityStatuses.forEach((workflowEntityStatus) -> {
256                var workflowStepDetail = workflowEntityStatus.getWorkflowStep().getLastDetail();
257                if (workflowStepDetail.getWorkflow().equals(workflow)) {
258                    var workflowStepName = workflowStepDetail.getWorkflowStepName();
259                    if (possibleWorkflowStepNames.contains(workflowStepName)) {
260                        result.add(workflowEntityStatus);
261                    }
262                }
263            });
264
265        }
266
267        return result;
268    }
269    
270    public boolean isWorkflowStepInSet(Set<WorkflowEntityStatus> workflowEntityStatuses, String workflowStepName) {
271        var result = false;
272        
273        for(var workflowEntityStatus : workflowEntityStatuses) {
274            if(result |= workflowEntityStatus.getWorkflowStep().getLastDetail().getWorkflowStepName().equals(workflowStepName)) {
275                break;
276            }
277        }
278        
279        return result;
280    }
281
282}