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.ChainInstanceUniversalSpec;
020import com.echothree.model.control.chain.common.exception.UnknownChainInstanceNameException;
021import com.echothree.model.control.chain.server.control.ChainControl;
022import com.echothree.model.control.core.common.ComponentVendors;
023import com.echothree.model.control.core.common.EntityTypes;
024import com.echothree.model.control.core.common.exception.InvalidParameterCountException;
025import com.echothree.model.control.core.server.logic.EntityInstanceLogic;
026import com.echothree.model.control.sequence.common.SequenceTypes;
027import com.echothree.model.control.sequence.server.logic.SequenceGeneratorLogic;
028import com.echothree.model.data.chain.server.entity.Chain;
029import com.echothree.model.data.chain.server.entity.ChainEntityRoleType;
030import com.echothree.model.data.chain.server.entity.ChainInstance;
031import com.echothree.model.data.chain.server.entity.ChainType;
032import com.echothree.model.data.core.server.entity.EntityInstance;
033import com.echothree.model.data.party.server.entity.Party;
034import com.echothree.util.common.message.ExecutionErrors;
035import com.echothree.util.common.persistence.BasePK;
036import com.echothree.util.server.control.BaseLogic;
037import com.echothree.util.server.message.ExecutionErrorAccumulator;
038import com.echothree.util.server.persistence.EntityPermission;
039import java.util.HashSet;
040import java.util.Set;
041import javax.enterprise.context.ApplicationScoped;
042import javax.inject.Inject;
043
044@ApplicationScoped
045public class ChainInstanceLogic
046        extends BaseLogic {
047
048    @Inject
049    protected ChainControl chainControl;
050
051    @Inject
052    protected ChainLogic chainLogic;
053
054    @Inject
055    protected ChainTypeLogic chainTypeLogic;
056
057    @Inject
058    EntityInstanceLogic entityInstanceLogic;
059
060    @Inject
061    SequenceGeneratorLogic sequenceGeneratorLogic;
062
063    protected ChainInstanceLogic() {
064        super();
065    }
066
067    public ChainInstance createChainInstance(final ExecutionErrorAccumulator eea, final Chain chain, final BasePK createdBy) {
068        var defaultChainActionSet = chainControl.getDefaultChainActionSet(chain);
069        ChainInstance chainInstance = null;
070
071        // The lack of a defaultChainActionSet is not a reportable error - it just silently avoids creating a Chain Instance.
072        if(defaultChainActionSet != null) {
073            var sequence = chain.getLastDetail().getChainInstanceSequence();
074
075            if(sequence == null) {
076                sequence = sequenceGeneratorLogic.getDefaultSequence(eea, SequenceTypes.CHAIN_INSTANCE.name());
077            }
078
079            if(!hasExecutionErrors(eea)) {
080                chainInstance = chainControl.createChainInstance(sequenceGeneratorLogic.getNextSequenceValue(sequence), defaultChainActionSet, createdBy);
081            }
082        }
083
084        return chainInstance;
085    }
086
087    public ChainInstance createChainInstance(final ExecutionErrorAccumulator eea, final ChainType chainType, final Party party, final BasePK createdBy) {
088        var chain = chainLogic.getChain(eea, chainType, party);
089        ChainInstance chainInstance = null;
090
091        if(chain != null) {
092            chainInstance = createChainInstance(eea, chain, createdBy);
093        }
094
095        return chainInstance;
096    }
097
098    public ChainInstance createChainInstance(final ExecutionErrorAccumulator eea, final String chainKindName, final String chainTypeName, final Party party,
099            final BasePK createdBy) {
100        var chainType = chainTypeLogic.getChainTypeByName(eea, chainKindName, chainTypeName);
101        ChainInstance chainInstance = null;
102
103        if(!hasExecutionErrors(eea)) {
104            chainInstance = createChainInstance(eea, chainType, party, createdBy);
105        }
106
107        return chainInstance;
108    }
109
110    public ChainInstance getChainInstanceByName(final ExecutionErrorAccumulator eea, final String chainInstanceName,
111            final EntityPermission entityPermission) {
112        var chainInstance = chainControl.getChainInstanceByName(chainInstanceName, entityPermission);
113
114        if(chainInstance == null) {
115            handleExecutionError(UnknownChainInstanceNameException.class, eea, ExecutionErrors.UnknownChainInstanceName.name(), chainInstanceName);
116        }
117
118        return chainInstance;
119    }
120
121    public ChainInstance getChainInstanceByName(final ExecutionErrorAccumulator eea, final String chainInstanceName) {
122        return getChainInstanceByName(eea, chainInstanceName, EntityPermission.READ_ONLY);
123    }
124
125    public ChainInstance getChainInstanceByNameForUpdate(final ExecutionErrorAccumulator eea, final String chainInstanceName) {
126        return getChainInstanceByName(eea, chainInstanceName, EntityPermission.READ_WRITE);
127    }
128
129    public ChainInstance getChainInstanceByUniversalSpec(final ExecutionErrorAccumulator eea,
130            final ChainInstanceUniversalSpec universalSpec, final EntityPermission entityPermission) {
131        ChainInstance chainInstance = null;
132        var chainInstanceName = universalSpec.getChainInstanceName();
133        var parameterCount = (chainInstanceName == null ? 0 : 1) + entityInstanceLogic.countPossibleEntitySpecs(universalSpec);
134
135        switch(parameterCount) {
136            case 1 -> {
137                if(chainInstanceName == null) {
138                    var entityInstance = entityInstanceLogic.getEntityInstance(eea, universalSpec,
139                            ComponentVendors.ECHO_THREE.name(), EntityTypes.ChainInstance.name());
140
141                    if(eea == null || !eea.hasExecutionErrors()) {
142                        chainInstance = chainControl.getChainInstanceByEntityInstance(entityInstance, entityPermission);
143                    }
144                } else {
145                    chainInstance = getChainInstanceByName(eea, chainInstanceName, entityPermission);
146                }
147            }
148            default ->
149                    handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
150        }
151
152        return chainInstance;
153    }
154
155    public ChainInstance getChainInstanceByUniversalSpec(final ExecutionErrorAccumulator eea,
156            final ChainInstanceUniversalSpec universalSpec) {
157        return getChainInstanceByUniversalSpec(eea, universalSpec, EntityPermission.READ_ONLY);
158    }
159
160    public ChainInstance getChainInstanceByUniversalSpecForUpdate(final ExecutionErrorAccumulator eea,
161            final ChainInstanceUniversalSpec universalSpec) {
162        return getChainInstanceByUniversalSpec(eea, universalSpec, EntityPermission.READ_WRITE);
163    }
164
165    public void deleteChainInstanceByChainEntityRoleTypeAndEntityInstance(final ChainEntityRoleType chainEntityRoleType, final EntityInstance entityInstance,
166            final BasePK deletedBy) {
167        var chainInstanceEntityRoles = chainControl.getChainInstanceEntityRoles(chainEntityRoleType, entityInstance);
168        Set<ChainInstance> chainInstances = new HashSet<>();
169
170        chainInstanceEntityRoles.forEach((chainInstanceEntityRole) -> {
171            chainInstances.add(chainInstanceEntityRole.getChainInstanceForUpdate());
172        });
173
174        chainControl.deleteChainInstances(chainInstances, deletedBy);
175    }
176
177}