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