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.sequence.server.logic;
018
019import com.echothree.control.user.sequence.common.spec.SequenceUniversalSpec;
020import com.echothree.model.control.core.common.ComponentVendors;
021import com.echothree.model.control.core.common.EntityTypes;
022import com.echothree.model.control.core.common.exception.InvalidParameterCountException;
023import com.echothree.model.control.core.server.logic.EntityInstanceLogic;
024import com.echothree.model.control.sequence.common.SequenceTypes;
025import com.echothree.model.control.sequence.common.exception.DuplicateSequenceNameException;
026import com.echothree.model.control.sequence.common.exception.InvalidValueLengthException;
027import com.echothree.model.control.sequence.common.exception.UnknownDefaultSequenceException;
028import com.echothree.model.control.sequence.common.exception.UnknownDefaultSequenceTypeException;
029import com.echothree.model.control.sequence.common.exception.UnknownSequenceNameException;
030import com.echothree.model.control.sequence.server.control.SequenceControl;
031import com.echothree.model.data.party.server.entity.Language;
032import com.echothree.model.data.sequence.server.entity.Sequence;
033import com.echothree.model.data.sequence.server.entity.SequenceType;
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 com.echothree.util.server.validation.ParameterUtils;
040import javax.enterprise.context.ApplicationScoped;
041import javax.inject.Inject;
042
043@ApplicationScoped
044public class SequenceLogic
045        extends BaseLogic {
046
047    @Inject
048    SequenceControl sequenceControl;
049
050    @Inject
051    EntityInstanceLogic entityInstanceLogic;
052
053    @Inject
054    SequenceGeneratorLogic sequenceGeneratorLogic;
055
056    @Inject
057    SequenceTypeLogic sequenceTypeLogic;
058
059    protected SequenceLogic() {
060        super();
061    }
062    
063    public Sequence createSequence(final ExecutionErrorAccumulator eea, final String sequenceTypeName, final String sequenceName,
064            final String value, final String mask, final Integer chunkSize, final Boolean isDefault, final Integer sortOrder,
065            final String description, final Language language, final BasePK createdBy) {
066        var sequenceType = sequenceTypeLogic.getSequenceTypeByName(eea, sequenceTypeName);
067        Sequence sequence = null;
068        
069        if(eea == null || !eea.hasExecutionErrors()) {
070            sequence = createSequence(eea, sequenceType, sequenceName, value, mask, chunkSize, isDefault, sortOrder, description,
071                    language, createdBy);
072        }
073        
074        return sequence;
075    }    
076    
077    public Sequence createSequence(final ExecutionErrorAccumulator eea, final SequenceType sequenceType, String sequenceName,
078            String value, final String mask, final Integer chunkSize, final Boolean isDefault, final Integer sortOrder,
079            final String description, final Language language, final BasePK createdBy) {
080        Sequence sequence = null;
081        
082        if(sequenceName == null) {
083            sequenceName = sequenceGeneratorLogic.getNextSequenceValue(eea, SequenceTypes.SEQUENCE.name());
084        }
085        
086        if(eea == null || !eea.hasExecutionErrors()) {
087            sequence = sequenceControl.getSequenceByName(sequenceType, sequenceName);
088    
089            if(sequence == null) {
090                if(value == null || value.length() == mask.length()) {
091                    sequence = sequenceControl.createSequence(sequenceType, sequenceName, mask, chunkSize, isDefault, sortOrder, createdBy);
092
093                    if(value == null) {
094                        var maskChars = mask.toCharArray();
095                        var maskLength = mask.length();
096                        var valueBuilder = new StringBuilder(maskLength);
097
098                        for(var index = 0; index < maskLength; index++) {
099                            var maskChar = maskChars[index];
100
101                            switch(maskChar) {
102                                case '9', 'Z' -> valueBuilder.append('0');
103                                case 'A' -> valueBuilder.append('A');
104                            }
105                        }
106
107                        value = valueBuilder.toString();
108                    }
109
110                    sequenceControl.createSequenceValue(sequence, value);
111
112                    if(description != null) {
113                        sequenceControl.createSequenceDescription(sequence, language, description, createdBy);
114                    }
115                } else {
116                    handleExecutionError(InvalidValueLengthException.class, eea, ExecutionErrors.InvalidValueLength.name());
117                }
118            } else {
119                handleExecutionError(DuplicateSequenceNameException.class, eea, ExecutionErrors.DuplicateSequenceName.name(),
120                        sequenceType.getLastDetail().getSequenceTypeName(), sequenceName);
121            }
122        }
123        
124        return sequence;
125    }
126
127    public Sequence getSequenceByName(final ExecutionErrorAccumulator eea, final SequenceType sequenceType, final String sequenceName,
128            final EntityPermission entityPermission) {
129        var sequence = sequenceControl.getSequenceByName(sequenceType, sequenceName, entityPermission);
130
131        if(sequence == null) {
132            handleExecutionError(UnknownSequenceNameException.class, eea, ExecutionErrors.UnknownSequenceName.name(),
133                    sequenceType.getLastDetail().getSequenceTypeName(), sequenceName);
134        }
135
136        return sequence;
137    }
138
139    public Sequence getSequenceByName(final ExecutionErrorAccumulator eea, final SequenceType sequenceType, final String sequenceName) {
140        return getSequenceByName(eea, sequenceType, sequenceName, EntityPermission.READ_ONLY);
141    }
142
143    public Sequence getSequenceByNameForUpdate(final ExecutionErrorAccumulator eea, final SequenceType sequenceType, final String sequenceName) {
144        return getSequenceByName(eea, sequenceType, sequenceName, EntityPermission.READ_WRITE);
145    }
146
147    public Sequence getSequenceByName(final ExecutionErrorAccumulator eea, final String sequenceTypeName, final String sequenceName,
148            final EntityPermission entityPermission) {
149        var sequenceType = sequenceTypeLogic.getSequenceTypeByName(eea, sequenceTypeName);
150        Sequence sequence = null;
151
152        if(eea == null || !eea.hasExecutionErrors()) {
153            sequence = getSequenceByName(eea, sequenceType, sequenceName, entityPermission);
154        }
155
156        return sequence;
157    }
158
159    public Sequence getSequenceByName(final ExecutionErrorAccumulator eea, final String sequenceTypeName, final String sequenceName) {
160        return getSequenceByName(eea, sequenceTypeName, sequenceName, EntityPermission.READ_ONLY);
161    }
162
163    public Sequence getSequenceByNameForUpdate(final ExecutionErrorAccumulator eea, final String sequenceTypeName, final String sequenceName) {
164        return getSequenceByName(eea, sequenceTypeName, sequenceName, EntityPermission.READ_WRITE);
165    }
166
167    public Sequence getSequenceByUniversalSpec(final ExecutionErrorAccumulator eea, final SequenceUniversalSpec universalSpec,
168            final boolean allowDefault, final EntityPermission entityPermission) {
169        var sequenceTypeName = universalSpec.getSequenceTypeName();
170        var sequenceName = universalSpec.getSequenceName();
171        var nameParameterCount= ParameterUtils.getInstance().countNonNullParameters(sequenceTypeName, sequenceName);
172        var possibleEntitySpecs= entityInstanceLogic.countPossibleEntitySpecs(universalSpec);
173        Sequence sequence = null;
174
175        if(nameParameterCount < 3 && possibleEntitySpecs == 0) {
176            SequenceType sequenceType = null;
177            
178            if(sequenceTypeName == null) {
179                if(allowDefault) {
180                    sequenceType = sequenceControl.getDefaultSequenceType();
181
182                    if(sequenceType == null) {
183                        handleExecutionError(UnknownDefaultSequenceTypeException.class, eea, ExecutionErrors.UnknownDefaultSequenceType.name());
184                    }
185                } else {
186                    handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
187                }
188            } else {
189                sequenceType = sequenceTypeLogic.getSequenceTypeByName(eea, sequenceTypeName);
190            }
191
192            if(eea == null || !eea.hasExecutionErrors()) {
193                if(sequenceName == null) {
194                    if(allowDefault) {
195                        sequence = sequenceControl.getDefaultSequence(sequenceType, entityPermission);
196
197                        if(sequence == null) {
198                            handleExecutionError(UnknownDefaultSequenceException.class, eea, ExecutionErrors.UnknownDefaultSequence.name());
199                        }
200                    } else {
201                        handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
202                    }
203                } else {
204                    sequence = getSequenceByName(eea, sequenceType, sequenceName, entityPermission);
205                }
206            }
207        } else if(nameParameterCount == 0 && possibleEntitySpecs == 1) {
208            var entityInstance = entityInstanceLogic.getEntityInstance(eea, universalSpec,
209                    ComponentVendors.ECHO_THREE.name(), EntityTypes.Sequence.name());
210
211            if(eea == null || !eea.hasExecutionErrors()) {
212                sequence = sequenceControl.getSequenceByEntityInstance(entityInstance, entityPermission);
213            }
214        } else {
215            handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
216        }
217
218        return sequence;
219    }
220
221    public Sequence getSequenceByUniversalSpec(final ExecutionErrorAccumulator eea, final SequenceUniversalSpec universalSpec,
222            boolean allowDefault) {
223        return getSequenceByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_ONLY);
224    }
225
226    public Sequence getSequenceByUniversalSpecForUpdate(final ExecutionErrorAccumulator eea, final SequenceUniversalSpec universalSpec,
227            boolean allowDefault) {
228        return getSequenceByUniversalSpec(eea, universalSpec, allowDefault, EntityPermission.READ_WRITE);
229    }
230
231}