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