001// --------------------------------------------------------------------------------
002// Copyright 2002-2024 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.item.server.search;
018
019import com.echothree.model.control.core.common.ComponentVendors;
020import com.echothree.model.control.core.common.EntityTypes;
021import com.echothree.model.control.index.common.IndexConstants;
022import com.echothree.model.control.index.common.IndexFieldVariations;
023import com.echothree.model.control.index.common.IndexFields;
024import com.echothree.model.control.index.common.IndexTypes;
025import com.echothree.model.control.index.server.analysis.ItemAnalyzer;
026import com.echothree.model.control.item.common.ItemConstants;
027import com.echothree.model.control.item.server.control.ItemControl;
028import com.echothree.model.control.item.server.logic.ItemDescriptionLogic;
029import com.echothree.model.control.search.common.SearchSortOrders;
030import com.echothree.model.control.search.common.SearchSortDirections;
031import com.echothree.model.control.search.server.search.BaseSearchEvaluator;
032import com.echothree.model.control.search.server.search.EntityInstancePKHolder;
033import com.echothree.model.data.core.server.factory.EntityInstanceFactory;
034import com.echothree.model.data.item.server.entity.Item;
035import com.echothree.model.data.item.server.entity.ItemType;
036import com.echothree.model.data.item.server.entity.ItemUseType;
037import com.echothree.model.data.party.server.entity.Language;
038import com.echothree.model.data.search.server.entity.SearchDefaultOperator;
039import com.echothree.model.data.search.server.entity.SearchSortDirection;
040import com.echothree.model.data.search.server.entity.SearchSortOrder;
041import com.echothree.model.data.search.server.entity.SearchType;
042import com.echothree.model.data.search.server.entity.SearchUseType;
043import com.echothree.model.data.user.server.entity.UserVisit;
044import com.echothree.model.data.workflow.server.entity.WorkflowStep;
045import com.echothree.util.server.message.ExecutionErrorAccumulator;
046import com.echothree.util.server.persistence.Session;
047import java.util.List;
048import org.apache.lucene.analysis.Analyzer;
049import org.apache.lucene.search.SortField;
050
051public class ItemSearchEvaluator
052        extends BaseSearchEvaluator {
053    
054    private String itemNameOrAlias;
055    private ItemType itemType;
056    private ItemUseType itemUseType;
057    private WorkflowStep itemStatusWorkflowStep;
058    List<WorkflowStep> itemStatusWorkflowSteps;
059    
060    /** Creates a new instance of ItemSearchEvaluator */
061    public ItemSearchEvaluator(UserVisit userVisit, Language language, SearchType searchType, SearchDefaultOperator searchDefaultOperator, SearchSortOrder searchSortOrder,
062            SearchSortDirection searchSortDirection, SearchUseType searchUseType) {
063        super(userVisit, searchDefaultOperator, searchType, searchSortOrder, searchSortDirection, searchUseType, ComponentVendors.ECHO_THREE.name(),
064                EntityTypes.Item.name(), IndexTypes.ITEM.name(), language, null);
065        
066        setField(ItemDescriptionLogic.getInstance().getIndexDefaultItemDescriptionTypeName());
067    }
068
069    /** Counts the number of search parameters. */
070    @Override
071    protected int countParameters() {
072        return super.countParameters() + (itemNameOrAlias == null ? 0 : 1) + (itemType == null ? 0 : 1)
073                + (itemUseType == null ? 0 : 1) + (itemStatusWorkflowStep == null ? 0 : 1) + (itemStatusWorkflowSteps == null ? 0 : 1);
074    }
075
076    /** Determines if the result of the search may be cached. For Items, the only field that may be used is the description, "q." If any
077     * others are utilized, the result may not be cached.
078     */
079    @Override
080    protected boolean isResultCachable() {
081        return countParameters() == 1 && q != null;
082    }
083    
084    public EntityInstancePKHolder getEntityInstancePKHolderByItemType(ItemType itemType) {
085            return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
086                    "SELECT _PK_ " +
087                    "FROM entityinstances, items, itemdetails " +
088                    "WHERE itm_activedetailid = itmdt_itemdetailid AND itmdt_ityp_itemtypeid = ? " +
089                    "AND eni_ent_entitytypeid = ? AND itm_itemid = eni_entityuniqueid"),
090                    itemType, entityType);
091    }
092    
093    public EntityInstancePKHolder getEntityInstancePKHolderByItemUseType(ItemUseType itemUseType) {
094            return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
095                    "SELECT _PK_ " +
096                    "FROM entityinstances, items, itemdetails " +
097                    "WHERE itm_activedetailid = itmdt_itemdetailid AND itmdt_iutyp_itemusetypeid = ? " +
098                    "AND eni_ent_entitytypeid = ? AND itm_itemid = eni_entityuniqueid"),
099                    itemUseType, entityType);
100    }
101    
102    public EntityInstancePKHolder getEntityInstancePKHolderByItemStatusWorkflowStep(WorkflowStep itemStatusWorkflowStep) {
103            return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
104                    "SELECT _PK_ " +
105                    "FROM entityinstances, items, itemdetails, workflowentitystatuses " +
106                    "WHERE itm_activedetailid = itmdt_itemdetailid " +
107                    "AND eni_ent_entitytypeid = ? AND itm_itemid = eni_entityuniqueid " +
108                    "AND eni_entityinstanceid = wkfles_eni_entityinstanceid AND wkfles_wkfls_workflowstepid = ? AND wkfles_thrutime = ?"),
109                    entityType, itemStatusWorkflowStep, Session.MAX_TIME);
110    }
111 
112    /**
113     * Returns the itemNameOrAlias.
114     * @return the itemNameOrAlias
115     */
116    public String getItemNameOrAlias() {
117        return itemNameOrAlias;
118    }
119
120    /**
121     * Sets the itemNameOrAlias.
122     * @param itemNameOrAlias the itemNameOrAlias to set
123     */
124    public void setItemNameOrAlias(String itemNameOrAlias) {
125        this.itemNameOrAlias = itemNameOrAlias;
126    }
127
128    /**
129     * Returns the itemType.
130     * @return the itemType
131     */
132    public ItemType getItemType() {
133        return itemType;
134    }
135
136    /**
137     * Sets the itemType.
138     * @param itemType the itemType to set
139     */
140    public void setItemType(ItemType itemType) {
141        this.itemType = itemType;
142    }
143
144    /**
145     * Returns the itemUseType.
146     * @return the itemUseType
147     */
148    public ItemUseType getItemUseType() {
149        return itemUseType;
150    }
151
152    /**
153     * Sets the itemUseType.
154     * @param itemUseType the itemUseType to set
155     */
156    public void setItemUseType(ItemUseType itemUseType) {
157        this.itemUseType = itemUseType;
158    }
159
160    /**
161     * Returns the itemStatusWorkflowStep.
162     * @return the itemStatusWorkflowStep
163     */
164    public WorkflowStep getItemStatusWorkflowStep() {
165        return itemStatusWorkflowStep;
166    }
167
168    /**
169     * Sets the itemStatusWorkflowStep.
170     * @param itemStatusWorkflowStep the itemStatusWorkflowStep to set
171     */
172    public void setItemStatusWorkflowStep(WorkflowStep itemStatusWorkflowStep) {
173        this.itemStatusWorkflowStep = itemStatusWorkflowStep;
174    }
175
176    /**
177     * Sets the itemStatusWorkflowSteps.
178     * @param itemStatusWorkflowSteps the itemStatusWorkflowSteps to set
179     */
180    public void setItemStatusWorkflowSteps(List<WorkflowStep> itemStatusWorkflowSteps) {
181        this.itemStatusWorkflowSteps = itemStatusWorkflowSteps;
182    }
183
184    @Override
185    public SortField[] getSortFields(String searchSortOrderName) {
186        SortField[] sortFields = null;
187        boolean reverse = searchSortDirection.getLastDetail().getSearchSortDirectionName().equals(SearchSortDirections.DESCENDING.name());
188        
189        if(searchSortOrderName.equals(SearchSortOrders.SCORE.name())) {
190            sortFields = new SortField[]{
191                new SortField(null, SortField.Type.SCORE, reverse),
192                new SortField(ItemConstants.ItemDescriptionType_DEFAULT_DESCRIPTION + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(), SortField.Type.STRING, reverse)
193            };
194        } else if(searchSortOrderName.equals(SearchSortOrders.DEFAULT_DESCRIPTION.name())) {
195            sortFields = new SortField[]{new SortField(ItemConstants.ItemDescriptionType_DEFAULT_DESCRIPTION + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(), SortField.Type.STRING, reverse)};
196        } else if(searchSortOrderName.equals(SearchSortOrders.ITEM_NAME.name())) {
197            sortFields = new SortField[]{new SortField(IndexFields.itemName.name() + IndexConstants.INDEX_FIELD_VARIATION_SEPARATOR + IndexFieldVariations.sortable.name(), SortField.Type.STRING, reverse)};
198        } else if(searchSortOrderName.equals(SearchSortOrders.CREATED_TIME.name())) {
199            sortFields = new SortField[]{new SortField(IndexFields.createdTime.name(), SortField.Type.LONG, reverse)};
200        } else if(searchSortOrderName.equals(SearchSortOrders.MODIFIED_TIME.name())) {
201            sortFields = new SortField[]{new SortField(IndexFields.modifiedTime.name(), SortField.Type.LONG, reverse)};
202        }
203        
204        return sortFields;
205    }
206    
207    @Override
208    public Analyzer getAnalyzer(final ExecutionErrorAccumulator eea, final Language language) {
209        return new ItemAnalyzer(eea, language, entityType);
210    }
211    
212    @Override
213    protected EntityInstancePKHolder executeSearch(final ExecutionErrorAccumulator eea) {
214        EntityInstancePKHolder resultSet = null;
215        
216        if(itemNameOrAlias == null) {
217            resultSet = super.executeSearch(eea);
218            
219            if(resultSet == null || resultSet.size() > 0) {
220                if(q != null) {
221                    if(resultSet == null || resultSet.size() > 0) {
222                        EntityInstancePKHolder entityInstancePKHolder = executeQuery(eea);
223                        
224                        if(resultSet == null) {
225                            resultSet = entityInstancePKHolder;
226                        } else {
227                            resultSet.retainAll(entityInstancePKHolder);
228                        }
229                    }
230                }
231            }
232            
233            if(resultSet == null || resultSet.size() > 0) {
234                if(itemType != null) {
235                    EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByItemType(itemType);
236                    
237                    if(resultSet == null) {
238                        resultSet = entityInstancePKHolder;
239                    } else {
240                        resultSet.retainAll(entityInstancePKHolder);
241                    }
242                }
243            }
244            
245            if(resultSet == null || resultSet.size() > 0) {
246                if(itemUseType != null) {
247                    EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByItemUseType(itemUseType);
248                    
249                    if(resultSet == null) {
250                        resultSet = entityInstancePKHolder;
251                    } else {
252                        resultSet.retainAll(entityInstancePKHolder);
253                    }
254                }
255            }
256
257            if(resultSet == null || resultSet.size() > 0) {
258                if(itemStatusWorkflowStep != null) {
259                    EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByItemStatusWorkflowStep(itemStatusWorkflowStep);
260
261                    if(resultSet == null) {
262                        resultSet = entityInstancePKHolder;
263                    } else {
264                        resultSet.retainAll(entityInstancePKHolder);
265                    }
266                }
267            }
268
269            if(resultSet == null || resultSet.size() > 0) {
270                if(itemStatusWorkflowSteps != null) {
271                    EntityInstancePKHolder entityInstancePKHolder = null;
272                    
273                    for(var workflowStep : itemStatusWorkflowSteps) {
274                        EntityInstancePKHolder individualPKHolder = getEntityInstancePKHolderByItemStatusWorkflowStep(workflowStep);
275                        
276                        if(entityInstancePKHolder == null) {
277                            entityInstancePKHolder = individualPKHolder;
278                        } else {
279                            entityInstancePKHolder.addAll(individualPKHolder);
280                        }
281                    }
282                    
283                    if(resultSet == null) {
284                        resultSet = entityInstancePKHolder;
285                    } else {
286                        resultSet.retainAll(entityInstancePKHolder);
287                    }
288                }
289            }
290        } else {
291            var itemControl = Session.getModelController(ItemControl.class);
292            Item item = itemControl.getItemByNameThenAlias(itemNameOrAlias);
293            
294            if(item != null) {
295                resultSet = new EntityInstancePKHolder(1);
296                resultSet.add(getCoreControl().getEntityInstanceByBasePK(item.getPrimaryKey()).getPrimaryKey(), null);
297            }
298        }
299        
300        return resultSet;
301    }
302
303}