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.party.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.IndexFields;
022import com.echothree.model.control.index.server.analysis.ItemAnalyzer;
023import com.echothree.model.control.index.server.analysis.PartyAnalyzer;
024import com.echothree.model.control.party.server.control.PartyControl;
025import com.echothree.model.control.party.server.logic.PartyLogic;
026import com.echothree.model.control.search.server.search.BaseSearchEvaluator;
027import com.echothree.model.control.search.server.search.EntityInstancePKHolder;
028import com.echothree.model.data.core.server.factory.EntityInstanceFactory;
029import com.echothree.model.data.geo.server.entity.GeoCode;
030import com.echothree.model.data.party.server.entity.Language;
031import com.echothree.model.data.party.server.entity.Party;
032import com.echothree.model.data.party.server.entity.PartyAliasType;
033import com.echothree.model.data.party.server.entity.PartyType;
034import com.echothree.model.data.search.server.entity.SearchDefaultOperator;
035import com.echothree.model.data.search.server.entity.SearchSortDirection;
036import com.echothree.model.data.search.server.entity.SearchSortOrder;
037import com.echothree.model.data.search.server.entity.SearchType;
038import com.echothree.model.data.user.server.entity.UserVisit;
039import com.echothree.util.server.message.ExecutionErrorAccumulator;
040import com.echothree.util.server.persistence.Session;
041import org.apache.lucene.analysis.Analyzer;
042
043public class PartySearchEvaluator
044        extends BaseSearchEvaluator {
045    
046    protected PartyType partyType;
047    protected String entityNameIndexField;
048    private String firstName;
049    private Boolean firstNameSoundex;
050    private String middleName;
051    private Boolean middleNameSoundex;
052    private String lastName;
053    private Boolean lastNameSoundex;
054    private GeoCode countryGeoCode;
055    private String areaCode;
056    private String telephoneNumber;
057    private String telephoneExtension;
058    private String emailAddress;
059    private String partyName;
060    private PartyAliasType partyAliasType;
061    private String alias;
062    
063    protected PartySearchEvaluator(UserVisit userVisit, SearchType searchType, SearchDefaultOperator searchDefaultOperator, SearchSortOrder searchSortOrder,
064            SearchSortDirection searchSortDirection, String partyTypeName, final String entityNameIndexField, String indexName) {
065        super(userVisit, searchDefaultOperator, searchType, searchSortOrder, searchSortDirection, null, ComponentVendors.ECHO_THREE.name(),
066                EntityTypes.Party.name(), null, null, indexName);
067        
068        this.partyType = PartyLogic.getInstance().getPartyTypeByName(null, partyTypeName);
069        this.entityNameIndexField = entityNameIndexField;
070        
071        setField(IndexFields.name.name());
072    }
073    
074    @Override
075    public EntityInstancePKHolder getEntityInstancePKHolderByCreatedTime(Long createdTime) {
076        // Custom version for PartySearchEvaluator that takes into account the PartyType.
077        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
078                "SELECT _PK_ "
079                + "FROM entityinstances, entitytimes, parties, partydetails "
080                + "WHERE par_activedetailid = pardt_partydetailid AND pardt_ptyp_partytypeid = ? "
081                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid "
082                + "AND eni_entityinstanceid = etim_eni_entityinstanceid AND etim_createdtime >= ?"),
083                partyType, entityType, createdTime);
084    }
085
086    @Override
087    public EntityInstancePKHolder getEntityInstancePKHolderByModifiedTime(Long modifiedTime) {
088        // Custom version for PartySearchEvaluator that takes into account the PartyType.
089        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
090                "SELECT _PK_ "
091                + "FROM entityinstances, entitytimes, parties, partydetails "
092                + "WHERE par_activedetailid = pardt_partydetailid AND pardt_ptyp_partytypeid = ? "
093                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid "
094                + "AND eni_entityinstanceid = etim_eni_entityinstanceid AND etim_modifiedtime >= ?"),
095                partyType, entityType, modifiedTime);
096    }
097
098    public EntityInstancePKHolder getEntityInstancePKHolderByFirstName(String firstName) {
099        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
100                "SELECT _PK_ "
101                + "FROM entityinstances, parties, partydetails, people "
102                + "WHERE par_activedetailid = pardt_partydetailid "
103                + "AND pardt_ptyp_partytypeid = ? "
104                + "AND par_partyid = peop_par_partyid AND peop_firstname = ? AND peop_thrutime = ? "
105                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid"),
106                partyType, firstName, Session.MAX_TIME, entityType);
107    }
108
109    public EntityInstancePKHolder getEntityInstancePKHolderByFirstNameSdx(String firstNameSdx) {
110        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
111                "SELECT _PK_ "
112                + "FROM entityinstances, parties, partydetails, people "
113                + "WHERE par_activedetailid = pardt_partydetailid "
114                + "AND pardt_ptyp_partytypeid = ? "
115                + "AND par_partyid = peop_par_partyid AND peop_firstnamesdx = ? AND peop_thrutime = ? "
116                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid"),
117                partyType, firstNameSdx, Session.MAX_TIME, entityType);
118    }
119
120    public EntityInstancePKHolder getEntityInstancePKHolderByMiddleName(String middleName) {
121        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
122                "SELECT _PK_ "
123                + "FROM entityinstances, parties, partydetails, people "
124                + "WHERE par_activedetailid = pardt_partydetailid "
125                + "AND pardt_ptyp_partytypeid = ? "
126                + "AND par_partyid = peop_par_partyid AND peop_middlename = ? AND peop_thrutime = ? "
127                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid"),
128                partyType, middleName, Session.MAX_TIME, entityType);
129    }
130
131    public EntityInstancePKHolder getEntityInstancePKHolderByMiddleNameSdx(String middleNameSdx) {
132        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
133                "SELECT _PK_ "
134                + "FROM entityinstances, parties, partydetails, people "
135                + "WHERE par_activedetailid = pardt_partydetailid "
136                + "AND pardt_ptyp_partytypeid = ? "
137                + "AND par_partyid = peop_par_partyid AND peop_middlenamesdx = ? AND peop_thrutime = ? "
138                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid"),
139                partyType, middleNameSdx, Session.MAX_TIME, entityType);
140    }
141
142    public EntityInstancePKHolder getEntityInstancePKHolderByLastName(String lastName) {
143        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
144                "SELECT _PK_ "
145                + "FROM entityinstances, parties, partydetails, people "
146                + "WHERE par_activedetailid = pardt_partydetailid "
147                + "AND pardt_ptyp_partytypeid = ? "
148                + "AND par_partyid = peop_par_partyid AND peop_lastname = ? AND peop_thrutime = ? "
149                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid"),
150                partyType, lastName, Session.MAX_TIME, entityType);
151    }
152
153    public EntityInstancePKHolder getEntityInstancePKHolderByLastNameSdx(String lastNameSdx) {
154        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
155                "SELECT _PK_ "
156                + "FROM entityinstances, parties, partydetails, people "
157                + "WHERE par_activedetailid = pardt_partydetailid "
158                + "AND pardt_ptyp_partytypeid = ? "
159                + "AND par_partyid = peop_par_partyid AND peop_lastnamesdx = ? AND peop_thrutime = ? "
160                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid"),
161                partyType, lastNameSdx, Session.MAX_TIME, entityType);
162    }
163
164    public EntityInstancePKHolder getEntityInstancePKHolderByAreaCode(GeoCode countryGeoCode, String areaCode) {
165        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
166                "SELECT _PK_ "
167                + "FROM entityinstances, parties, partydetails, partycontactmechanisms, partycontactmechanismdetails, contacttelephones "
168                + "WHERE par_activedetailid = pardt_partydetailid "
169                + "AND pardt_ptyp_partytypeid = ? "
170                + "AND pcm_activedetailid = pcmdt_partycontactmechanismdetailid "
171                + "AND par_partyid = pcmdt_par_partyid "
172                + "AND pcmdt_cmch_contactmechanismid = cttp_cmch_contactmechanismid AND cttp_thrutime = ? "
173                + "AND cttp_countrygeocodeid = ? AND cttp_areacode = ? "
174                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid"),
175                partyType, Session.MAX_TIME, countryGeoCode, areaCode, entityType);
176    }
177
178    public EntityInstancePKHolder getEntityInstancePKHolderByTelephoneNumber(GeoCode countryGeoCode, String telephoneNumber) {
179        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
180                "SELECT _PK_ "
181                + "FROM entityinstances, parties, partydetails, partycontactmechanisms, partycontactmechanismdetails, contacttelephones "
182                + "WHERE par_activedetailid = pardt_partydetailid "
183                + "AND pardt_ptyp_partytypeid = ? "
184                + "AND pcm_activedetailid = pcmdt_partycontactmechanismdetailid "
185                + "AND par_partyid = pcmdt_par_partyid "
186                + "AND pcmdt_cmch_contactmechanismid = cttp_cmch_contactmechanismid AND cttp_thrutime = ? "
187                + "AND cttp_countrygeocodeid = ? AND cttp_telephonenumber = ? "
188                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid"),
189                partyType, Session.MAX_TIME, countryGeoCode, telephoneNumber, entityType);
190    }
191
192    public EntityInstancePKHolder getEntityInstancePKHolderByTelephoneExtension(GeoCode countryGeoCode, String telephoneExtension) {
193        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
194                "SELECT _PK_ "
195                + "FROM entityinstances, parties, partydetails, partycontactmechanisms, partycontactmechanismdetails, contacttelephones "
196                + "WHERE par_activedetailid = pardt_partydetailid "
197                + "AND pardt_ptyp_partytypeid = ? "
198                + "AND pcm_activedetailid = pcmdt_partycontactmechanismdetailid "
199                + "AND par_partyid = pcmdt_par_partyid "
200                + "AND pcmdt_cmch_contactmechanismid = cttp_cmch_contactmechanismid AND cttp_thrutime = ? "
201                + "AND cttp_countrygeocodeid = ? AND cttp_telephoneextension = ? "
202                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid"),
203                partyType, Session.MAX_TIME, countryGeoCode, telephoneExtension, entityType);
204    }
205
206    public EntityInstancePKHolder getEntityInstancePKHolderByEmailAddress(String emailAddress) {
207        return getEntityInstancePKHolderFromQuery(EntityInstanceFactory.getInstance().prepareStatement(
208                "SELECT _PK_ "
209                + "FROM entityinstances, parties, partydetails, partycontactmechanisms, partycontactmechanismdetails, contactemailaddresses "
210                + "WHERE par_activedetailid = pardt_partydetailid "
211                + "AND pardt_ptyp_partytypeid = ? "
212                + "AND pcm_activedetailid = pcmdt_partycontactmechanismdetailid "
213                + "AND par_partyid = pcmdt_par_partyid "
214                + "AND pcmdt_cmch_contactmechanismid = ctea_cmch_contactmechanismid AND ctea_thrutime = ? "
215                + "AND ctea_emailaddress = ? "
216                + "AND eni_ent_entitytypeid = ? AND par_partyid = eni_entityuniqueid"),
217                partyType, Session.MAX_TIME, emailAddress, entityType);
218    }
219
220    public String getFirstName() {
221        return firstName;
222    }
223    
224    public void setFirstName(String firstName) {
225        this.firstName = firstName;
226    }
227    
228    public Boolean getFirstNameSoundex() {
229        return firstNameSoundex;
230    }
231    
232    public void setFirstNameSoundex(Boolean firstNameSoundex) {
233        this.firstNameSoundex = firstNameSoundex;
234    }
235    
236    public String getMiddleName() {
237        return middleName;
238    }
239    
240    public void setMiddleName(String middleName) {
241        this.middleName = middleName;
242    }
243    
244    public Boolean getMiddleNameSoundex() {
245        return middleNameSoundex;
246    }
247    
248    public void setMiddleNameSoundex(Boolean middleNameSoundex) {
249        this.middleNameSoundex = middleNameSoundex;
250    }
251    
252    public String getLastName() {
253        return lastName;
254    }
255    
256    public void setLastName(String lastName) {
257        this.lastName = lastName;
258    }
259    
260    public Boolean getLastNameSoundex() {
261        return lastNameSoundex;
262    }
263    
264    public void setLastNameSoundex(Boolean lastNameSoundex) {
265        this.lastNameSoundex = lastNameSoundex;
266    }
267    
268    public String getPartyName() {
269        return partyName;
270    }
271
272    public GeoCode getCountryGeoCode() {
273        return countryGeoCode;
274    }
275
276    public void setCountryGeoCode(GeoCode countryGeoCode) {
277        this.countryGeoCode = countryGeoCode;
278    }
279
280    public String getAreaCode() {
281        return areaCode;
282    }
283
284    public void setAreaCode(String areaCode) {
285        this.areaCode = areaCode;
286    }
287
288    public String getTelephoneNumber() {
289        return telephoneNumber;
290    }
291
292    public void setTelephoneNumber(String telephoneNumber) {
293        this.telephoneNumber = telephoneNumber;
294    }
295
296    public String getTelephoneExtension() {
297        return telephoneExtension;
298    }
299
300    public void setTelephoneExtension(String telephoneExtension) {
301        this.telephoneExtension = telephoneExtension;
302    }
303
304    public String getEmailAddress() {
305        return emailAddress;
306    }
307
308    public void setEmailAddress(String emailAddress) {
309        this.emailAddress = emailAddress;
310    }
311    
312    public void setPartyName(String partyName) {
313        this.partyName = partyName;
314    }
315
316    public PartyAliasType getPartyAliasType() {
317        return partyAliasType;
318    }
319
320    public void setPartyAliasType(PartyAliasType partyAliasType) {
321        this.partyAliasType = partyAliasType;
322    }
323
324    public String getAlias() {
325        return alias;
326    }
327
328    public void setAlias(String alias) {
329        this.alias = alias;
330    }
331
332    @Override
333    public Analyzer getAnalyzer(final ExecutionErrorAccumulator eea, final Language language) {
334        return new PartyAnalyzer(eea, language, entityType, partyType, entityNameIndexField);
335    }
336
337    /** Subclasses should override and always call their super's executeSearch() */
338    @Override
339    protected EntityInstancePKHolder executeSearch(final ExecutionErrorAccumulator eea) {
340        EntityInstancePKHolder resultSet = null;
341        var parameterCount = (partyName == null ? 0 : 1) + (alias == null ? 0 : 1);
342
343        if(parameterCount == 0) {
344            resultSet = super.executeSearch(eea);
345            
346            if(resultSet == null || resultSet.size() > 0) {
347                if(firstName != null) {
348                    if(firstNameSoundex) {
349                        String firstNameSdx;
350
351                        try {
352                            firstNameSdx = firstName == null? null: getSoundex().encode(firstName);
353                        } catch (IllegalArgumentException iae) {
354                            firstNameSdx = null;
355                        }
356
357                        if(firstNameSdx != null) {
358                            EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByFirstNameSdx(firstNameSdx);
359
360                            if(resultSet == null) {
361                                resultSet = entityInstancePKHolder;
362                            } else {
363                                resultSet.retainAll(entityInstancePKHolder);
364                            }
365                        } else {
366                            resultSet = null;
367                        }
368                    } else {
369                        EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByFirstName(firstName);
370
371                        if(resultSet == null) {
372                            resultSet = entityInstancePKHolder;
373                        } else {
374                            resultSet.retainAll(entityInstancePKHolder);
375                        }
376                    }
377                }
378            }
379
380            if(resultSet == null || resultSet.size() > 0) {
381                if(middleName != null) {
382                    if(middleNameSoundex) {
383                        String middleNameSdx;
384
385                        try {
386                            middleNameSdx = middleName == null? null: getSoundex().encode(middleName);
387                        } catch (IllegalArgumentException iae) {
388                            middleNameSdx = null;
389                        }
390
391                        if(middleNameSdx != null) {
392                            EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByMiddleNameSdx(middleNameSdx);
393
394                            if(resultSet == null) {
395                                resultSet = entityInstancePKHolder;
396                            } else {
397                                resultSet.retainAll(entityInstancePKHolder);
398                            }
399                        } else {
400                            resultSet = null;
401                        }
402                    } else {
403                        EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByMiddleName(middleName);
404
405                        if(resultSet == null) {
406                            resultSet = entityInstancePKHolder;
407                        } else {
408                            resultSet.retainAll(entityInstancePKHolder);
409                        }
410                    }
411                }
412            }
413
414            if(resultSet == null || resultSet.size() > 0) {
415                if(lastName != null) {
416                    if(lastNameSoundex) {
417                        String lastNameSdx;
418
419                        try {
420                            lastNameSdx = lastName == null? null: getSoundex().encode(lastName);
421                        } catch (IllegalArgumentException iae) {
422                            lastNameSdx = null;
423                        }
424
425                        if(lastNameSdx != null) {
426                            EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByLastNameSdx(lastNameSdx);
427
428                            if(resultSet == null) {
429                                resultSet = entityInstancePKHolder;
430                            } else {
431                                resultSet.retainAll(entityInstancePKHolder);
432                            }
433                        } else {
434                            resultSet = null;
435                        }
436                    } else {
437                        EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByLastName(lastName);
438
439                        if(resultSet == null) {
440                            resultSet = entityInstancePKHolder;
441                        } else {
442                            resultSet.retainAll(entityInstancePKHolder);
443                        }
444                    }
445                }
446            }
447
448            if(countryGeoCode != null && areaCode != null && (resultSet == null || resultSet.size() > 0)) {
449                EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByAreaCode(countryGeoCode, areaCode);
450
451                if(resultSet == null) {
452                    resultSet = entityInstancePKHolder;
453                } else {
454                    resultSet.retainAll(entityInstancePKHolder);
455                }
456            }
457            
458            if(countryGeoCode != null && telephoneNumber != null && (resultSet == null || resultSet.size() > 0)) {
459                EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByTelephoneNumber(countryGeoCode, telephoneNumber);
460
461                if(resultSet == null) {
462                    resultSet = entityInstancePKHolder;
463                } else {
464                    resultSet.retainAll(entityInstancePKHolder);
465                }
466            }
467            
468            if(countryGeoCode != null && telephoneExtension != null && (resultSet == null || resultSet.size() > 0)) {
469                EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByTelephoneExtension(countryGeoCode, telephoneExtension);
470
471                if(resultSet == null) {
472                    resultSet = entityInstancePKHolder;
473                } else {
474                    resultSet.retainAll(entityInstancePKHolder);
475                }
476            }
477            
478            if(emailAddress != null && (resultSet == null || resultSet.size() > 0)) {
479                EntityInstancePKHolder entityInstancePKHolder = getEntityInstancePKHolderByEmailAddress(emailAddress);
480
481                if(resultSet == null) {
482                    resultSet = entityInstancePKHolder;
483                } else {
484                    resultSet.retainAll(entityInstancePKHolder);
485                }
486            }
487            
488            if(resultSet == null || resultSet.size() > 0) {
489                if(q != null) {
490                    EntityInstancePKHolder entityInstancePKHolder = executeQuery(eea);
491                    
492                    if(resultSet == null) {
493                        resultSet = entityInstancePKHolder;
494                    } else {
495                        resultSet.retainAll(entityInstancePKHolder);
496                    }
497                }
498            }
499        } else {
500            if(parameterCount == 1) {
501                var partyControl = Session.getModelController(PartyControl.class);
502                Party party = null;
503
504                if(alias != null) {
505                    if(partyAliasType == null) {
506                        partyAliasType = partyControl.getDefaultPartyAliasType(partyType);
507                    }
508                    
509                    if(partyAliasType != null) {
510                        party = partyControl.getPartyByAlias(partyAliasType, alias);
511                    }
512                }
513
514                if(partyName != null) {
515                    party = partyControl.getPartyByName(partyName);
516
517                    // If it isn't the PartyType we're looking for, toss the Party away.
518                    if(!party.getLastDetail().getPartyType().equals(partyType)) {
519                        party = null;
520                    }
521                }
522
523                if(party != null) {
524                    resultSet = new EntityInstancePKHolder(1);
525                    resultSet.add(getCoreControl().getEntityInstanceByBasePK(party.getPrimaryKey()).getPrimaryKey(), null);
526                }
527            }
528        }
529        
530        return resultSet;
531    }
532
533}