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