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.core.server.logic;
018
019import com.echothree.control.user.core.common.spec.EntityRefSpec;
020import com.echothree.control.user.core.common.spec.UniversalEntitySpec;
021import com.echothree.control.user.core.common.spec.UuidSpec;
022import com.echothree.model.control.core.common.ComponentVendors;
023import com.echothree.model.control.core.common.EventTypes;
024import com.echothree.model.control.core.common.exception.DeletedEntityRefException;
025import com.echothree.model.control.core.common.exception.DeletedUuidException;
026import com.echothree.model.control.core.common.exception.InvalidComponentVendorException;
027import com.echothree.model.control.core.common.exception.InvalidEntityTypeException;
028import com.echothree.model.control.core.common.exception.InvalidParameterCountException;
029import com.echothree.model.control.core.common.exception.UnknownEntityRefException;
030import com.echothree.model.control.core.common.exception.UnknownUuidException;
031import com.echothree.model.control.core.server.control.EntityInstanceControl;
032import com.echothree.model.control.core.server.control.EventControl;
033import com.echothree.model.data.core.server.entity.EntityInstance;
034import com.echothree.model.data.core.server.entity.EntityType;
035import com.echothree.util.common.message.ExecutionErrors;
036import com.echothree.util.common.persistence.BasePK;
037import com.echothree.util.server.control.BaseLogic;
038import com.echothree.util.server.message.ExecutionErrorAccumulator;
039import com.echothree.util.server.persistence.EntityIdGenerator;
040import javax.enterprise.context.ApplicationScoped;
041import javax.inject.Inject;
042
043@ApplicationScoped
044public class EntityInstanceLogic
045        extends BaseLogic {
046
047    @Inject
048    protected EntityInstanceControl entityInstanceControl;
049
050    @Inject
051    protected EventControl eventControl;
052
053    protected EntityInstanceLogic() {
054        super();
055    }
056
057    public EntityInstance createEntityInstance(final ExecutionErrorAccumulator eea, final EntityType entityType,
058            final BasePK createdBy) {
059        var entityTypeDetail = entityType.getLastDetail();
060        var componentVendorName = entityTypeDetail.getComponentVendor().getLastDetail().getComponentVendorName();
061        EntityInstance entityInstance = null;
062
063        if(!ComponentVendors.ECHO_THREE.name().equals(componentVendorName)) {
064            var entityTypeName = entityTypeDetail.getEntityTypeName();
065            var entityIdGenerator = new EntityIdGenerator(componentVendorName, entityTypeName, 1); // TODO
066            var entityId = entityIdGenerator.getNextEntityId();
067            var basePK = new BasePK(componentVendorName, entityTypeName, entityId);
068            var event = eventControl.sendEvent(basePK, EventTypes.CREATE, null, null, createdBy);
069
070            entityInstance = event.getEntityInstance();
071        } else {
072            handleExecutionError(InvalidComponentVendorException.class, eea, ExecutionErrors.InvalidComponentVendor.name(), componentVendorName);
073        }
074
075        return entityInstance;
076    }
077
078    private boolean checkEntityTimeForDeletion(EntityInstance entityInstance) {
079        boolean wasDeleted = false;
080        var entityTime = eventControl.getEntityTime(entityInstance);
081
082        // If the EntityTime is null, then we're not going to find a DeletedTime, which means it must exist...
083        // do not mark it as having been deleted.
084        if(entityTime != null) {
085            // Check the DeletedTime...
086            if(entityTime.getDeletedTime() != null) {
087                // It's been deleted.
088                wasDeleted = true;
089            }
090        }
091
092        return wasDeleted;
093    }
094    
095    public EntityInstance getEntityInstanceByEntityRef(final ExecutionErrorAccumulator eea, final String entityRef) {
096        var entityInstance = entityInstanceControl.getEntityInstanceByEntityRef(entityRef);
097
098        if(entityInstance == null) {
099            handleExecutionError(UnknownEntityRefException.class, eea, ExecutionErrors.UnknownEntityRef.name(), entityRef);
100        } else {
101            var wasDeleted = checkEntityTimeForDeletion(entityInstance);
102
103            if(wasDeleted) {
104                entityInstance = null;
105                handleExecutionError(DeletedEntityRefException.class, eea, ExecutionErrors.DeletedEntityRef.name(), entityRef);
106            }
107        }
108
109
110        return entityInstance;
111    }
112
113    public EntityInstance getEntityInstanceByEntityRef(final ExecutionErrorAccumulator eea, final EntityRefSpec spec) {
114        return getEntityInstanceByEntityRef(eea, spec.getEntityRef());
115    }
116    
117    public EntityInstance getEntityInstanceByUuid(final ExecutionErrorAccumulator eea, final String uuid) {
118        var entityInstance = entityInstanceControl.getEntityInstanceByUuid(uuid);
119
120        if(entityInstance == null) {
121            handleExecutionError(UnknownUuidException.class, eea, ExecutionErrors.UnknownUuid.name(), uuid);
122        } else {
123            var wasDeleted = checkEntityTimeForDeletion(entityInstanceControl.getEntityInstanceByUuid(uuid));
124
125            if(wasDeleted) {
126                entityInstance = null;
127                handleExecutionError(DeletedUuidException.class, eea, ExecutionErrors.DeletedUuid.name(), uuid);
128            }
129        }
130
131        return entityInstance;
132    }
133
134    public EntityInstance getEntityInstanceByUuid(final ExecutionErrorAccumulator eea, final UuidSpec spec) {
135        return getEntityInstanceByUuid(eea, spec.getUuid());
136    }
137    
138    public EntityInstance getEntityInstance(final ExecutionErrorAccumulator eea, final String entityRef,
139            final String uuid, final String componentVendorName, final String... entityTypeNames) {
140        var parameterCount = countPossibleEntitySpecs(entityRef, uuid);
141        EntityInstance entityInstance = null;
142        
143        if(parameterCount == 1) {
144            if(entityRef != null) {
145                entityInstance = getEntityInstanceByEntityRef(eea, entityRef);
146            } else if(uuid != null) {
147                entityInstance = getEntityInstanceByUuid(eea, uuid);
148            }
149        } else {
150            handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
151        }
152        
153        if((eea == null || !eea.hasExecutionErrors()) && componentVendorName != null && entityTypeNames.length > 0) {
154            var entityTypeDetail = entityInstance.getEntityType().getLastDetail();
155            var foundComponentVendorName = entityTypeDetail.getComponentVendor().getLastDetail().getComponentVendorName();
156            var foundEntityTypeName = entityTypeDetail.getEntityTypeName();
157            var found = false;
158            
159            if(foundComponentVendorName.equals(componentVendorName)) {
160                for(var entityTypeName : entityTypeNames) {
161                    if(entityTypeName.equals(foundEntityTypeName)) {
162                        found = true;
163                        break;
164                    }
165                }
166            }
167            
168            if(!found) {
169                handleExecutionError(InvalidEntityTypeException.class, eea, ExecutionErrors.InvalidEntityType.name(), foundComponentVendorName, foundEntityTypeName);
170                entityInstance = null;
171            }
172        }
173        
174        return entityInstance;
175    }
176    
177    public EntityInstance getEntityInstance(final ExecutionErrorAccumulator eea, final EntityRefSpec entityRefSpec,
178            final UuidSpec uuidSpec, final String componentVendorName, final String... entityTypeNames) {
179        return getEntityInstance(eea, entityRefSpec.getEntityRef(), uuidSpec.getUuid(),
180                componentVendorName, entityTypeNames);
181    }
182    
183    public EntityInstance getEntityInstance(final ExecutionErrorAccumulator eea, final UniversalEntitySpec universalEntitySpec) {
184        return getEntityInstance(eea, universalEntitySpec.getEntityRef(),
185                universalEntitySpec.getUuid(), null);
186    }
187    
188    public EntityInstance getEntityInstance(final ExecutionErrorAccumulator eea, final UniversalEntitySpec universalEntitySpec,
189            final String componentVendorName, final String... entityTypeNames) {
190        return getEntityInstance(eea, universalEntitySpec.getEntityRef(),
191                universalEntitySpec.getUuid(), componentVendorName, entityTypeNames);
192    }
193    
194    public int countPossibleEntitySpecs(final String entityRef, final String uuid) {
195        return (entityRef == null ? 0 : 1) + (uuid == null ? 0 : 1);
196    }
197    
198    public int countPossibleEntitySpecs(final EntityRefSpec entityRefSpec, final UuidSpec uuidSpec) {
199        return countPossibleEntitySpecs(entityRefSpec == null ? null : entityRefSpec.getEntityRef(),
200                uuidSpec == null ? null : uuidSpec.getUuid());
201    }
202    
203    public int countPossibleEntitySpecs(final UniversalEntitySpec universalEntitySpec) {
204        return universalEntitySpec == null ? 0 : countPossibleEntitySpecs(universalEntitySpec.getEntityRef(),
205                universalEntitySpec.getUuid());
206    }
207    
208    public String getEntityRefFromEntityInstance(EntityInstance entityInstance) {
209        var entityTypeDetail = entityInstance.getEntityType().getLastDetail();
210        var componentVendorDetail = entityTypeDetail.getComponentVendor().getLastDetail();
211        
212        return componentVendorDetail.getComponentVendorName() + '.' +
213                entityTypeDetail.getEntityTypeName() + '.' +
214                entityInstance.getEntityUniqueId();
215    }
216
217    public void deleteEntityInstance(final ExecutionErrorAccumulator eea, final EntityInstance entityInstance, final BasePK deletedBy) {
218        var componentVendorName = entityInstance.getEntityType().getLastDetail().getComponentVendor().getLastDetail().getComponentVendorName();
219
220        if(!ComponentVendors.ECHO_THREE.name().equals(componentVendorName)) {
221            entityInstanceControl.deleteEntityInstance(entityInstance, deletedBy);
222        } else {
223            handleExecutionError(InvalidComponentVendorException.class, eea, ExecutionErrors.InvalidComponentVendor.name(), componentVendorName);
224        }
225    }
226
227    public void removeEntityInstance(final ExecutionErrorAccumulator eea, final EntityInstance entityInstance) {
228        var componentVendorName = entityInstance.getEntityType().getLastDetail().getComponentVendor().getLastDetail().getComponentVendorName();
229
230        if(!ComponentVendors.ECHO_THREE.name().equals(componentVendorName)) {
231            entityInstanceControl.removeEntityInstance(entityInstance);
232        } else {
233            handleExecutionError(InvalidComponentVendorException.class, eea, ExecutionErrors.InvalidComponentVendor.name(), componentVendorName);
234        }
235    }
236
237}