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