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