001// --------------------------------------------------------------------------------
002// Copyright 2002-2025 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.control.user.chain.server.command;
018
019import com.echothree.control.user.chain.common.form.CreateChainActionForm;
020import com.echothree.model.control.chain.common.ChainConstants;
021import com.echothree.model.control.chain.server.control.ChainControl;
022import com.echothree.model.control.letter.server.control.LetterControl;
023import com.echothree.model.control.party.common.PartyTypes;
024import com.echothree.model.control.security.common.SecurityRoleGroups;
025import com.echothree.model.control.security.common.SecurityRoles;
026import com.echothree.model.control.uom.common.UomConstants;
027import com.echothree.model.control.uom.server.control.UomControl;
028import com.echothree.model.control.uom.server.util.Conversion;
029import com.echothree.model.data.chain.server.entity.Chain;
030import com.echothree.model.data.chain.server.entity.ChainAction;
031import com.echothree.model.data.chain.server.entity.ChainActionSet;
032import com.echothree.model.data.chain.server.entity.ChainActionType;
033import com.echothree.model.data.chain.server.entity.ChainType;
034import com.echothree.model.data.letter.server.entity.Letter;
035import com.echothree.model.data.party.common.pk.PartyPK;
036import com.echothree.model.data.user.common.pk.UserVisitPK;
037import com.echothree.util.common.message.ExecutionErrors;
038import com.echothree.util.common.validation.FieldDefinition;
039import com.echothree.util.common.validation.FieldType;
040import com.echothree.util.common.command.BaseResult;
041import com.echothree.util.common.form.ValidationResult;
042import com.echothree.util.server.control.BaseSimpleCommand;
043import com.echothree.util.server.control.CommandSecurityDefinition;
044import com.echothree.util.server.control.PartyTypeDefinition;
045import com.echothree.util.server.control.SecurityRoleDefinition;
046import com.echothree.util.server.persistence.Session;
047import com.echothree.util.server.validation.Validator;
048import java.util.Arrays;
049import java.util.Collections;
050import java.util.List;
051import javax.enterprise.context.RequestScoped;
052
053@RequestScoped
054public class CreateChainActionCommand
055        extends BaseSimpleCommand<CreateChainActionForm> {
056    
057    private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION;
058    private final static List<FieldDefinition> FORM_FIELD_DEFINITIONS;
059    private final static List<FieldDefinition> letterFormFieldDefinitions;
060    private final static List<FieldDefinition> surveyFormFieldDefinitions;
061    private final static List<FieldDefinition> chainActionSetFormFieldDefinitions;
062    
063    static {
064        COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(Collections.unmodifiableList(Arrays.asList(
065                new PartyTypeDefinition(PartyTypes.UTILITY.name(), null),
066                new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), Collections.unmodifiableList(Arrays.asList(
067                    new SecurityRoleDefinition(SecurityRoleGroups.ChainAction.name(), SecurityRoles.Create.name())
068                    )))
069                )));
070
071        FORM_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList(
072                new FieldDefinition("ChainKindName", FieldType.ENTITY_NAME, true, null, null),
073                new FieldDefinition("ChainTypeName", FieldType.ENTITY_NAME, true, null, null),
074                new FieldDefinition("ChainName", FieldType.ENTITY_NAME, true, null, null),
075                new FieldDefinition("ChainActionSetName", FieldType.ENTITY_NAME, true, null, null),
076                new FieldDefinition("ChainActionName", FieldType.ENTITY_NAME, true, null, null),
077                new FieldDefinition("ChainActionTypeName", FieldType.ENTITY_NAME, true, null, null),
078                new FieldDefinition("SortOrder", FieldType.SIGNED_INTEGER, true, null, null),
079                new FieldDefinition("Description", FieldType.STRING, false, 1L, 132L)
080                ));
081        
082        letterFormFieldDefinitions = Collections.unmodifiableList(Arrays.asList(
083                new FieldDefinition("LetterName", FieldType.ENTITY_NAME, true, null, null)
084                ));
085        
086        surveyFormFieldDefinitions = Collections.unmodifiableList(Arrays.asList(
087                new FieldDefinition("SurveyName", FieldType.ENTITY_NAME, true, null, null)
088                ));
089        
090        chainActionSetFormFieldDefinitions = Collections.unmodifiableList(Arrays.asList(
091                new FieldDefinition("NextChainActionSetName", FieldType.ENTITY_NAME, true, null, null),
092                new FieldDefinition("DelayTime", FieldType.UNSIGNED_LONG, true, null, null),
093                new FieldDefinition("DelayTimeUnitOfMeasureTypeName", FieldType.ENTITY_NAME, true, null, null)
094                ));
095    }
096    
097    /** Creates a new instance of CreateChainActionCommand */
098    public CreateChainActionCommand() {
099        super(COMMAND_SECURITY_DEFINITION, FORM_FIELD_DEFINITIONS, false);
100    }
101    
102    @Override
103    protected ValidationResult validate() {
104        var validator = new Validator(this);
105        var validationResult = validator.validate(form, FORM_FIELD_DEFINITIONS);
106        
107        if(!validationResult.getHasErrors()) {
108            var chainActionTypeName = form.getChainActionTypeName();
109            
110            if(chainActionTypeName.equals(ChainConstants.ChainActionType_LETTER)) {
111                validationResult = validator.validate(form, letterFormFieldDefinitions);
112            } else if(chainActionTypeName.equals(ChainConstants.ChainActionType_SURVEY)) {
113                validationResult = validator.validate(form, surveyFormFieldDefinitions);
114            } else if(chainActionTypeName.equals(ChainConstants.ChainActionType_CHAIN_ACTION_SET)) {
115                validationResult = validator.validate(form, chainActionSetFormFieldDefinitions);
116            }
117        }
118        
119        return validationResult;
120    }
121    
122    private abstract class BaseChainActionType {
123
124        ChainControl chainControl;
125        ChainActionType chainActionType;
126
127        public BaseChainActionType(ChainControl chainControl, String chainActionTypeName) {
128            this.chainControl = chainControl;
129            chainActionType = chainControl.getChainActionTypeByName(chainActionTypeName);
130
131            if(chainActionType == null) {
132                addExecutionError(ExecutionErrors.UnknownChainActionTypeName.name(), chainActionTypeName);
133            }
134        }
135
136        public abstract void execute(ChainAction chainAction, PartyPK partyPK);
137    }
138    
139    private abstract class LetterComponentChainActionType
140            extends BaseChainActionType {
141
142        protected LetterControl letterControl = Session.getModelController(LetterControl.class);
143
144        public LetterComponentChainActionType(ChainControl chainControl, String chainActionTypeName) {
145            super(chainControl, chainActionTypeName);
146        }
147    }
148    
149    private class LetterChainActionType
150        extends LetterComponentChainActionType {
151        private Letter letter = null;
152        
153        public LetterChainActionType(ChainControl chainControl, ChainType chainType) {
154            super(chainControl, ChainConstants.ChainActionType_LETTER);
155            
156            if(!hasExecutionErrors()) {
157                var letterName = form.getLetterName();
158                
159                letter = letterControl.getLetterByName(chainType, letterName);
160                
161                if(letter == null) {
162                    addExecutionError(ExecutionErrors.UnknownLetterName.name(), letterName);
163                }
164            }
165        }
166        
167        @Override
168        public void execute(ChainAction chainAction, PartyPK partyPK) {
169            chainControl.createChainActionLetter(chainAction, letter, partyPK);
170        }
171    }
172    
173    private class ChainActionSetChainActionType
174        extends BaseChainActionType {
175        ChainActionSet nextChainActionSet = null;
176        Long delayTime = null;
177        
178        public ChainActionSetChainActionType(ChainControl chainControl, Chain chain) {
179            super(chainControl, ChainConstants.ChainActionType_CHAIN_ACTION_SET);
180            
181            if(!hasExecutionErrors()) {
182                var nextChainActionSetName = form.getNextChainActionSetName();
183                
184                nextChainActionSet = chainControl.getChainActionSetByName(chain, nextChainActionSetName);
185                
186                if(nextChainActionSet != null) {
187                    var uomControl = Session.getModelController(UomControl.class);
188                    var timeUnitOfMeasureKind = uomControl.getUnitOfMeasureKindByUnitOfMeasureKindUseTypeUsingNames(UomConstants.UnitOfMeasureKindUseType_TIME);
189
190                    if(timeUnitOfMeasureKind != null) {
191                        var delayTimeUnitOfMeasureTypeName = form.getDelayTimeUnitOfMeasureTypeName();
192                        var delayTimeUnitOfMeasureType = uomControl.getUnitOfMeasureTypeByName(timeUnitOfMeasureKind, delayTimeUnitOfMeasureTypeName);
193
194                        if(delayTimeUnitOfMeasureType != null) {
195                            delayTime = new Conversion(uomControl, delayTimeUnitOfMeasureType, Long.valueOf(form.getDelayTime())).convertToLowestUnitOfMeasureType().getQuantity();
196                        } else {
197                            addExecutionError(ExecutionErrors.UnknownRetainUserVisitsTimeUnitOfMeasureTypeName.name(), delayTimeUnitOfMeasureTypeName);
198                        }
199                    } else {
200                        addExecutionError(ExecutionErrors.UnknownTimeUnitOfMeasureKind.name());
201                    }
202                } else {
203                    addExecutionError(ExecutionErrors.UnknownNextChainActionSetName.name(), nextChainActionSetName);
204                }
205            }
206        }
207        
208        @Override
209        public void execute(ChainAction chainAction, PartyPK partyPK) {
210            chainControl.createChainActionChainActionSet(chainAction, nextChainActionSet, delayTime, partyPK);
211        }
212    }
213    
214    @Override
215    protected BaseResult execute() {
216        var chainControl = Session.getModelController(ChainControl.class);
217        var chainKindName = form.getChainKindName();
218        var chainKind = chainControl.getChainKindByName(chainKindName);
219
220        if(chainKind != null) {
221            var chainTypeName = form.getChainTypeName();
222            var chainType = chainControl.getChainTypeByName(chainKind, chainTypeName);
223
224            if(chainType != null) {
225                var chainName = form.getChainName();
226                var chain = chainControl.getChainByName(chainType, chainName);
227
228                if(chain != null) {
229                    var chainActionSetName = form.getChainActionSetName();
230                    var chainActionSet = chainControl.getChainActionSetByName(chain, chainActionSetName);
231
232                    if(chainActionSet != null) {
233                        var chainActionName = form.getChainActionName();
234                        var chainAction = chainControl.getChainActionByName(chainActionSet, chainActionName);
235
236                        if(chainAction == null) {
237                            var chainActionTypeName = form.getChainActionTypeName();
238                            var chainActionType = chainControl.getChainActionTypeByName(chainActionTypeName);
239
240                            if(chainActionType != null) {
241                                BaseChainActionType baseChainActionType = null;
242                                
243                                if(chainActionTypeName.equals(ChainConstants.ChainActionType_LETTER)) {
244                                    baseChainActionType = new LetterChainActionType(chainControl, chainType);
245                                } else if(chainActionTypeName.equals(ChainConstants.ChainActionType_SURVEY)) {
246                                    // TODO
247                                } else if(chainActionTypeName.equals(ChainConstants.ChainActionType_CHAIN_ACTION_SET)) {
248                                    baseChainActionType = new ChainActionSetChainActionType(chainControl, chain);
249                                }
250                                
251                                if(!hasExecutionErrors()) {
252                                    var partyPK = getPartyPK();
253                                    var sortOrder = Integer.valueOf(form.getSortOrder());
254                                    var description = form.getDescription();
255
256                                    chainAction = chainControl.createChainAction(chainActionSet, chainActionName, chainActionType, sortOrder, partyPK);
257
258                                            if(baseChainActionType != null) { // TODO: Remove test once all Types are implemented.
259                                                baseChainActionType.execute(chainAction, partyPK);
260                                            }
261
262                                    if(description != null) {
263                                        chainControl.createChainActionDescription(chainAction, getPreferredLanguage(), description, partyPK);
264                                    }
265                                }
266                            } else {
267                                    addExecutionError(ExecutionErrors.UnknownChainActionTypeName.name(), chainActionTypeName);
268                            }
269                        } else {
270                                addExecutionError(ExecutionErrors.DuplicateChainActionName.name(), chainKindName, chainTypeName, chainName, chainActionSetName, chainActionName);
271                        }
272                    } else {
273                            addExecutionError(ExecutionErrors.UnknownChainActionSetName.name(), chainKindName, chainTypeName, chainName, chainActionSetName);
274                    }
275                } else {
276                        addExecutionError(ExecutionErrors.UnknownChainName.name(), chainKindName, chainTypeName, chainName);
277                }
278            } else {
279                addExecutionError(ExecutionErrors.UnknownChainTypeName.name(), chainKindName, chainTypeName);
280            }
281        } else {
282            addExecutionError(ExecutionErrors.UnknownChainKindName.name(), chainKindName);
283        }
284
285        return null;
286    }
287    
288}