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.chain.server.logic;
018
019import com.echothree.control.user.chain.common.spec.ChainUniversalSpec;
020import com.echothree.model.control.chain.common.exception.CannotDeleteChainInUseException;
021import com.echothree.model.control.chain.common.exception.DuplicateChainNameException;
022import com.echothree.model.control.chain.common.exception.UnknownChainNameException;
023import com.echothree.model.control.chain.common.exception.UnknownDefaultChainException;
024import com.echothree.model.control.chain.common.exception.UnknownDefaultChainKindException;
025import com.echothree.model.control.chain.common.exception.UnknownDefaultChainTypeException;
026import com.echothree.model.control.chain.server.control.ChainControl;
027import com.echothree.model.control.core.common.ComponentVendors;
028import com.echothree.model.control.core.common.EntityTypes;
029import com.echothree.model.control.core.common.exception.InvalidParameterCountException;
030import com.echothree.model.control.core.server.logic.EntityInstanceLogic;
031import com.echothree.model.control.customer.server.control.CustomerControl;
032import com.echothree.model.control.offer.server.control.OfferControl;
033import com.echothree.model.control.sequence.common.SequenceTypes;
034import com.echothree.model.control.sequence.server.logic.SequenceLogic;
035import com.echothree.model.data.chain.server.entity.Chain;
036import com.echothree.model.data.chain.server.entity.ChainKind;
037import com.echothree.model.data.chain.server.entity.ChainType;
038import com.echothree.model.data.party.server.entity.Language;
039import com.echothree.model.data.party.server.entity.Party;
040import com.echothree.model.data.sequence.server.entity.Sequence;
041import com.echothree.util.common.message.ExecutionErrors;
042import com.echothree.util.common.persistence.BasePK;
043import com.echothree.util.server.control.BaseLogic;
044import com.echothree.util.server.message.ExecutionErrorAccumulator;
045import com.echothree.util.server.persistence.EntityPermission;
046import com.echothree.util.server.validation.ParameterUtils;
047import javax.enterprise.context.ApplicationScoped;
048import javax.inject.Inject;
049
050@ApplicationScoped
051public class ChainLogic
052        extends BaseLogic {
053
054    @Inject
055    ChainControl chainControl;
056
057    @Inject
058    CustomerControl customerControl;
059
060    @Inject
061    OfferControl offerControl;
062
063    @Inject
064    ChainKindLogic chainKindLogic;
065
066    @Inject
067    ChainTypeLogic chainTypeLogic;
068
069    @Inject
070    EntityInstanceLogic entityInstanceLogic;
071
072    @Inject
073    SequenceLogic sequenceLogic;
074
075    protected ChainLogic() {
076        super();
077    }
078
079    public Chain createChain(final ExecutionErrorAccumulator eea, final String chainKindName, final String chainTypeName,
080            final String chainName, final String initialChainAdjustmentName, final String chainItemSelectorName,
081            final Boolean isDefault, final Integer sortOrder, final Language language, final String description,
082            final BasePK createdBy) {
083        var chainType = chainTypeLogic.getChainTypeByName(eea, chainKindName, chainTypeName);
084        Chain chain = null;
085
086        if(eea == null || !eea.hasExecutionErrors()) {
087            var chainInstanceSequence = initialChainAdjustmentName == null ? null :
088                    sequenceLogic.getSequenceByName(eea, SequenceTypes.CHAIN_INSTANCE.name(), initialChainAdjustmentName);
089
090            if(eea == null || !eea.hasExecutionErrors()) {
091                chain = createChain(eea, chainType, chainName, chainInstanceSequence,
092                        isDefault, sortOrder, language, description, createdBy);
093            }
094        }
095
096        return chain;
097    }
098
099    public Chain createChain(final ExecutionErrorAccumulator eea, final ChainType chainType, final String chainName,
100            final Sequence chainInstanceSequence, final Boolean isDefault, final Integer sortOrder, final Language language,
101            final String description, final BasePK createdBy) {
102        var chain = chainControl.getChainByName(chainType, chainName);
103
104        if(chain == null) {
105            chain = chainControl.createChain(chainType, chainName, chainInstanceSequence, isDefault, sortOrder, createdBy);
106
107            if(description != null) {
108                chainControl.createChainDescription(chain, language, description, createdBy);
109            }
110        } else {
111            handleExecutionError(DuplicateChainNameException.class, eea, ExecutionErrors.DuplicateChainName.name(), chainName);
112        }
113        return chain;
114    }
115
116    public Chain getChainByName(final ExecutionErrorAccumulator eea, final ChainType chainType, final String chainName,
117            final EntityPermission entityPermission) {
118        var chain = chainControl.getChainByName(chainType, chainName, entityPermission);
119
120        if(chain == null) {
121            handleExecutionError(UnknownChainNameException.class, eea, ExecutionErrors.UnknownChainName.name(),
122                    chainType.getLastDetail().getChainKind().getLastDetail().getChainKindName(),
123                    chainType.getLastDetail().getChainTypeName(), chainName);
124        }
125
126        return chain;
127    }
128
129    public Chain getChainByName(final ExecutionErrorAccumulator eea, final ChainType chainType, final String chainName) {
130        return getChainByName(eea, chainType, chainName, EntityPermission.READ_ONLY);
131    }
132
133    public Chain getChainByNameForUpdate(final ExecutionErrorAccumulator eea, final ChainType chainType, final String chainName) {
134        return getChainByName(eea, chainType, chainName, EntityPermission.READ_WRITE);
135    }
136
137    public Chain getChainByName(final ExecutionErrorAccumulator eea, final String chainKindName, final String chainTypeName,
138            final String chainName, final EntityPermission entityPermission) {
139        var chainType = chainTypeLogic.getChainTypeByName(eea, chainKindName, chainTypeName);
140        Chain chain = null;
141
142        if(eea == null || !eea.hasExecutionErrors()) {
143            chain = getChainByName(eea, chainType, chainName, entityPermission);
144        }
145
146        return chain;
147    }
148
149    public Chain getChainByName(final ExecutionErrorAccumulator eea, final String chainKindName, final String chainTypeName, final String chainName) {
150        return getChainByName(eea, chainKindName, chainTypeName, chainName, EntityPermission.READ_ONLY);
151    }
152
153    public Chain getChainByNameForUpdate(final ExecutionErrorAccumulator eea, final String chainKindName, final String chainTypeName, final String chainName) {
154        return getChainByName(eea, chainKindName, chainTypeName, chainName, EntityPermission.READ_WRITE);
155    }
156
157    public Chain getChainByUniversalSpec(final ExecutionErrorAccumulator eea, final ChainUniversalSpec universalSpec,
158            final boolean allowDefault, final EntityPermission entityPermission) {
159        var chainKindName = universalSpec.getChainKindName();
160        var chainTypeName = universalSpec.getChainTypeName();
161        var chainName = universalSpec.getChainName();
162        var nameParameterCount = ParameterUtils.getInstance().countNonNullParameters(chainKindName, chainTypeName, chainName);
163        var possibleEntitySpecs = entityInstanceLogic.countPossibleEntitySpecs(universalSpec);
164        Chain chain = null;
165
166        if(nameParameterCount < 4 && possibleEntitySpecs == 0) {
167            ChainKind chainKind = null;
168            ChainType chainType = null;
169
170            if(chainKindName == null) {
171                if(allowDefault) {
172                    chainKind = chainControl.getDefaultChainKind();
173
174                    if(chainKind == null) {
175                        handleExecutionError(UnknownDefaultChainKindException.class, eea, ExecutionErrors.UnknownDefaultChainKind.name());
176                    }
177                } else {
178                    handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
179                }
180            } else {
181                chainKind = chainKindLogic.getChainKindByName(eea, chainKindName);
182            }
183
184            if(eea == null || !eea.hasExecutionErrors()) {
185                if(chainTypeName == null) {
186                    if(allowDefault) {
187                        chainType = chainControl.getDefaultChainType(chainKind);
188
189                        if(chainType == null) {
190                            handleExecutionError(UnknownDefaultChainTypeException.class, eea, ExecutionErrors.UnknownDefaultChainType.name(),
191                                    chainKind.getLastDetail().getChainKindName());
192                        }
193                    } else {
194                        handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
195                    }
196                } else {
197                    chainType = chainTypeLogic.getChainTypeByName(eea, chainKind, chainTypeName);
198                }
199            }
200
201            if(eea == null || !eea.hasExecutionErrors()) {
202                if(chainName == null) {
203                    if(allowDefault) {
204                        chain = chainControl.getDefaultChain(chainType, entityPermission);
205
206                        if(chain == null) {
207                            handleExecutionError(UnknownDefaultChainException.class, eea, ExecutionErrors.UnknownDefaultChain.name(),
208                                    chainKind.getLastDetail().getChainKindName(),
209                                    chainType.getLastDetail().getChainTypeName());
210                        }
211                    } else {
212                        handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
213                    }
214                } else {
215                    chain = getChainByName(eea, chainType, chainName, entityPermission);
216                }
217            }
218        } else if(nameParameterCount == 0 && possibleEntitySpecs == 1) {
219            var entityInstance = entityInstanceLogic.getEntityInstance(eea, universalSpec,
220                    ComponentVendors.ECHO_THREE.name(), EntityTypes.Chain.name());
221
222            if(eea == null || !eea.hasExecutionErrors()) {
223                chain = chainControl.getChainByEntityInstance(entityInstance, entityPermission);
224            }
225        } else {
226            handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
227        }
228
229        return chain;
230    }
231
232    public Chain getChainByUniversalSpec(final ExecutionErrorAccumulator eea, final ChainUniversalSpec universalSpec,
233            boolean allowDefault) {
234        return getChainByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_ONLY);
235    }
236
237    public Chain getChainByUniversalSpecForUpdate(final ExecutionErrorAccumulator eea, final ChainUniversalSpec universalSpec,
238            boolean allowDefault) {
239        return getChainByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_WRITE);
240    }
241
242    public void deleteChain(final ExecutionErrorAccumulator eea, final Chain chain, final BasePK deletedBy) {
243        if(chainControl.countChainActionSetsByChain(chain) == 0) {
244            chainControl.deleteChain(chain, deletedBy);
245        } else {
246            var chainDetail = chain.getLastDetail();
247
248            handleExecutionError(CannotDeleteChainInUseException.class, eea, ExecutionErrors.CannotDeleteChainInUse.name(),
249                    chainDetail.getChainType().getLastDetail().getChainKind().getLastDetail().getChainKindName(),
250                    chainDetail.getChainType().getLastDetail().getChainTypeName(),
251                    chainDetail.getChainName());
252        }
253    }
254    
255    public Chain getChain(final ExecutionErrorAccumulator eea, final ChainType chainType, final Party party) {
256        var customer = customerControl.getCustomer(party);
257        var initialOfferUse = customer == null ? null : customer.getInitialOfferUse();
258        var offerChainType = initialOfferUse == null ? null : offerControl.getOfferChainType(initialOfferUse.getLastDetail().getOffer(), chainType);
259
260        return offerChainType == null ? chainControl.getDefaultChain(chainType) : offerChainType.getChain();
261    }
262
263}