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