fix #9567 unify HomotypicGroupTaxonComparator and HomotypicGroupNameComparator
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / compare / name / HomotypicalGroupNameComparator.java
index 7151d49c5baab79dbdce1dbd570e1d7a796f9dac..d5a1861a4fd33997ed8235acb187361faa1eda56 100755 (executable)
@@ -10,20 +10,11 @@ package eu.etaxonomy.cdm.compare.name;
 
 import java.io.Serializable;
 import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Set;
 
 import org.apache.log4j.Logger;
 
-import eu.etaxonomy.cdm.compare.taxon.TaxonComparator;
-import eu.etaxonomy.cdm.model.name.NameRelationship;
-import eu.etaxonomy.cdm.model.name.NameRelationshipType;
-import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
-import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
-import eu.etaxonomy.cdm.model.name.Rank;
+import eu.etaxonomy.cdm.compare.taxon.HomotypicGroupTaxonComparator;
 import eu.etaxonomy.cdm.model.name.TaxonName;
-import eu.etaxonomy.cdm.model.reference.Reference;
-import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 
 /**
  * This class orders synonyms of a homotypic group,
@@ -49,388 +40,18 @@ import eu.etaxonomy.cdm.model.taxon.TaxonBase;
  */
 public class HomotypicalGroupNameComparator implements Comparator<TaxonName>, Serializable{
 
+    private static final long serialVersionUID = 2306033011970230866L;
+    @SuppressWarnings("unused")
     private static final Logger logger = Logger.getLogger(HomotypicalGroupNameComparator.class);
 
+    private HomotypicGroupTaxonComparator taxonComparator;
 
-        private final TaxonName firstNameInGroup;
-        private boolean includeRanks = false;
+    public HomotypicalGroupNameComparator(TaxonName firstNameInGroup, boolean includeRanks) {
+        taxonComparator = new HomotypicGroupTaxonComparator(firstNameInGroup, includeRanks);
+    }
 
-        /**
-         * @param firstNameInGroup
-         */
-        public HomotypicalGroupNameComparator(@SuppressWarnings("rawtypes") TaxonName firstNameInGroup, boolean includeRanks) {
-            super();
-            this.firstNameInGroup = firstNameInGroup;
-            this.includeRanks = includeRanks;
-        }
-
-
-        /**
-         *
-         * @see TaxonComparator#compare(TaxonBase, TaxonBase)
-         * @see java.lang.String#compareTo(String)
-         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
-         */
-        @Override
-        public int compare(
-                @SuppressWarnings("rawtypes") TaxonName taxonName1,
-                @SuppressWarnings("rawtypes") TaxonName taxonName2) {
-
-
-            if (logger.isDebugEnabled()){logger.debug(taxonName1.getTitleCache() +" : "+ taxonName2.getTitleCache());}
-
-
-            int compareStatus = compareStatus(taxonName1, taxonName2);
-            if (compareStatus != 0){
-                return compareStatus;
-            }
-
-            //not same homotypical group -
-            //NOTE: this comparator should usually not be used
-            //      for comparing names of different homotypical groups.
-            //      The following is only to have a defined compare behavior
-            //      which follows the contract of Comparator#compare.
-            if (taxonName1 == null ||
-                    taxonName2 == null ||
-                ! taxonName1.getHomotypicalGroup().equals(taxonName2.getHomotypicalGroup())){
-
-                String compareString1 =
-                        taxonName1.getHomotypicalGroup().getUuid().toString() ;
-                String compareString2 =
-                        taxonName2.getHomotypicalGroup().getUuid().toString() ;
-                int result = compareString1.compareTo(compareString2);
-                return result;
-            }
-
-            //same homotypical group ...
-            //one taxon is first in group
-            if (taxonName1.equals(firstNameInGroup)){
-                return -1;
-            }else if (taxonName2.equals(firstNameInGroup)){
-                return 1;
-            }
-
-
-
-            TaxonName basionym1 = getPreferredInBasionymGroup(taxonName1);
-            TaxonName basionym2 = getPreferredInBasionymGroup(taxonName2);
-
-            int compareResult;
-            if (basionym1.equals(basionym2)){
-                //both names belong to same basionym sub-group
-                compareResult = handleSameBasionym(basionym1, taxonName1, taxonName2);
-            }else{
-                compareResult = compareBasionyms(basionym1, basionym2);
-            }
-
-           return compareResult;
-           }
-
-
-        /**
-         * Compare 2 names which have the same basionym.
-         * The names must not be equal to each other but may be equal
-         * to the basionym.
-         * @param basionym the basionym
-         * @param name1 first name to compare
-         * @param name2 second name to compare
-         * @return compare value according to the {@link Comparator#compare(Object, Object)} contract.
-         */
-        private int handleSameBasionym(TaxonName basionym,
-                TaxonName name1,
-                TaxonName name2) {
-
-            if (basionym.equals(name1)){
-                return -1;
-            }else if (basionym.equals(name2)){
-                return 1;
-            }else{
-                return this.compare(name1, name2, false);
-            }
-
-        }
-
-        /**
-         * @param basionym1
-         * @param basionym2
-         * @return
-         */
-        private int compareBasionyms(TaxonName basionym1Orig, TaxonName basionym2Orig) {
-            //one taxon is first in group
-            TaxonName basionym1 = getFirstNameInGroup(basionym1Orig);
-            TaxonName basionym2 = getFirstNameInGroup(basionym2Orig);
-
-            //handle accepted taxon case
-            if (basionym1.equals(firstNameInGroup)){
-                return -1;
-            }else if (basionym2.equals(firstNameInGroup)){
-                return 1;
-            }
-
-            //handle replaced synonyms
-            boolean basio2IsReplacedSynForBasio1 = getReplacedSynonymClosure(basionym1).contains(basionym2);
-            boolean basio1IsReplacedSynForBasio2 = getReplacedSynonymClosure(basionym2).contains(basionym1);
-
-            if (basio2IsReplacedSynForBasio1 && !basio1IsReplacedSynForBasio2){
-                return 1;
-            }else if (basio1IsReplacedSynForBasio2 && !basio2IsReplacedSynForBasio1){
-                return -1;
-            }
-
-            //compare by date, nom. illeg., rank and alphabetically
-            return this.compare(basionym1, basionym2, false);
-
-        }
-
-        /**
-         * @param basionym
-         * @return
-         */
-        private TaxonName getFirstNameInGroup(TaxonName basionym) {
-            for (NameRelationship nameRel : basionym.getRelationsFromThisName()){
-                if (nameRel.getType() != null && nameRel.getType().equals(NameRelationshipType.BASIONYM())){
-                    if (nameRel.getToName().equals(firstNameInGroup)){
-                        return firstNameInGroup;
-                    }
-                }
-            }
-            return basionym;
-        }
-
-        /**
-         * @param basionym1
-         * @return
-         */
-        @SuppressWarnings("rawtypes")
-        private Set<TaxonName> getReplacedSynonymClosure(TaxonName name) {
-            Set<TaxonName> set = name.getReplacedSynonyms();
-            if (set.isEmpty()){
-                return set;
-            }
-            Set<TaxonName> result = new HashSet<TaxonName>();
-            for (TaxonName replSyn : set){
-                boolean notYetContained = result.add(replSyn);
-                if (notYetContained){
-                    result.addAll(replSyn.getReplacedSynonyms());
-                }
-            }
-            return result;
-        }
-
-        /**
-         * @param name
-         * @return
-         */
-        private TaxonName getPreferredInBasionymGroup(TaxonName name) {
-            Set<TaxonName> candidates = new HashSet<>();
-            //get all final basionyms, except for those being part of a basionym circle
-            for (TaxonName candidate : name.getBasionyms()){
-                if (candidate != null
-                        && candidate.getHomotypicalGroup().equals(name.getHomotypicalGroup())
-                        && !hasBasionymCircle(candidate, null)){
-                    candidate = getPreferredInBasionymGroup(candidate);
-                    candidates.add(candidate);
-                }
-            }
-
-            if (candidates.isEmpty()){
-                return name;
-            }else if (candidates.size() == 1){
-                return candidates.iterator().next();
-            }else{
-                TaxonName result = candidates.iterator().next();
-                candidates.remove(result);
-                for(TaxonName candidate : candidates){
-                    if (this.compare(result, candidate) > 0){
-                        result = candidate;
-                    }
-                }
-                return result;
-            }
-        }
-
-        /**
-         * @param candidate
-         * @return
-         */
-        private boolean hasBasionymCircle(TaxonName name, Set<TaxonName> existing) {
-            if (existing == null){
-                existing = new HashSet<>();
-            }
-            if (existing.contains(name)){
-                return true;
-            }else{
-                Set<TaxonName> basionyms = name.getBasionyms();
-                if (basionyms.isEmpty()){
-                    return false;
-                }
-                existing.add(name);
-                for (TaxonName basionym : basionyms){
-                    if (hasBasionymCircle(basionym, existing)){
-                        return true;
-                    }
-                }
-                return false;
-            }
-        }
-
-
-    //  /**
-    //   * @param homotypicalGroup
-    //   * @return
-    //   */
-    //  private TaxonBase<?> getFirstInHomotypicalGroup(HomotypicalGroup homotypicalGroup, Collection<TaxonBase<?>> existing) {
-//          List<TaxonBase<?>> candidates =  new ArrayList<TaxonBase<?>>();
-//          for (TaxonBase<?> candidate : existing){
-//              if (homotypicalGroup.getTypifiedNames().contains(candidate.getName())){
-//                  candidates.add(candidate);
-//              }
-//          }
-//          Collections.sort(candidates, this);
-//          return candidates.isEmpty() ? null : candidates.get(0);
-    //  }
-
-        /**
-         * @param taxonName
-         * @param taxonName2
-         * @param statusCompareWeight
-         * @return
-         */
-        protected int compareStatus(TaxonName taxonName, TaxonName taxonName2) {
-            int statusCompareWeight = 0;
-            statusCompareWeight += computeStatusCompareWeight(taxonName);
-            statusCompareWeight -= computeStatusCompareWeight(taxonName2);
-            return statusCompareWeight;
-        }
-
-        /**
-         * @param taxonBase1
-         * @param statusCompareWeight
-         * @return
-         */
-        private int computeStatusCompareWeight(TaxonName taxonName) {
-            //NOTE: this represented an ordered list for different types of invalid designation status.
-            //      but not clear were this order came from, it is partly mentioned
-            //in #5794, it is unclear if it fits to the longer list mentioned in #9272
-            //With #9272 and finally #9566 we decided to handle all invalid status with same weight
-            if (taxonName != null && taxonName.isInvalid()){
-                return 1;
-            }else{
-                return 0;
-            }
-        }
-        /**
-        *
-        * @param name1
-        * @param name2
-        * @param includeNomIlleg if true and if both names have no date or same date, the only
-        * name having nom. illeg. state is handled as if the name was published later than the name
-        * without status nom. illeg.
-        * @return
-        */
-       protected int compare(TaxonName name1, TaxonName name2, boolean includeNomIlleg) {
-           int result;
-
-           //dates
-           Integer intDate1 = getIntegerDate(name1);
-           Integer intDate2 = getIntegerDate(name2);
-
-           if (intDate1 == null && intDate2 == null){
-               result = 0;
-           }else if (intDate1 == null){
-               return 1;
-           }else if (intDate2 == null){
-               return -1;
-           }else{
-               result = intDate1.compareTo(intDate2);
-           }
-
-           //nom. illeg.
-           if (result == 0 && includeNomIlleg){
-               result = compareNomIlleg(name1, name2);
-               if (result != 0){
-                   return result;
-               }
-           }
-
-           if (result == 0 && includeRanks){
-               Rank rank1 = name1 == null? null : name1.getRank();
-               Rank rank2 = name2 == null? null : name2.getRank();
-
-               if (rank1 == null && rank2 == null){
-                   result = 0;
-               }else if (rank1 == null){
-                   return 1;
-               }else if (rank2 == null){
-                   return -1;
-               }else{
-                   //for some strange reason compareTo for ranks returns 1 if rank2 is lower. So we add minus (-)
-                   result = - rank1.compareTo(rank2);
-               }
-           }
-
-           if (result == 0 && name1 != null && name2 != null){
-               result = name1.compareToName(name2);
-               if (result != 0){
-                   return result;
-               }
-           }
-           return result;
-       }
-
-       private Integer getIntegerDate(TaxonName name){
-           Integer result;
-
-          if (name == null){
-               result = null;
-           }else{
-               if (name.isZoological()){
-                   result = name.getPublicationYear();
-               }else{
-                   Reference ref = name.getNomenclaturalReference();
-                   if (ref == null){
-                       result = null;
-                   }else{
-                       if (ref.getDatePublished() == null){
-                           Reference inRef = ref.getInReference();
-                           if (inRef == null){
-                               result = null;
-                           }else{
-                               if (inRef.getDatePublished() == null){
-                                   result = null;
-                               }else{
-                                   result = ref.getInReference().getDatePublished().getStartYear();
-                               }
-                           }
-                       }else{
-                           result = ref.getDatePublished().getStartYear();
-                       }
-                   }
-               }
-           }
-
-           return result;
-       }
-
-       protected int compareNomIlleg(TaxonName taxonName1, TaxonName taxonName2) {
-           int isNomIlleg1 = isNomIlleg(taxonName1);
-           int isNomIlleg2 = isNomIlleg(taxonName2);
-           return isNomIlleg1 - isNomIlleg2;
-       }
-
-       private int isNomIlleg(TaxonName taxonName) {
-           if (taxonName == null || taxonName.getStatus() == null){
-               return 0;
-           }
-           Set<NomenclaturalStatus> status = taxonName.getStatus();
-           for (NomenclaturalStatus nomStatus : status){
-               if (nomStatus.getType() != null){
-                   if (nomStatus.getType().equals(NomenclaturalStatusType.ILLEGITIMATE())){
-                       return 1;
-                   }
-               }
-           }
-           return 0;
-       }
-
-}
+    @Override
+    public int compare(TaxonName taxonName1, TaxonName taxonName2) {
+        return taxonComparator.compareNames(taxonName1, taxonName2, null, null);
+    }
+}
\ No newline at end of file