the query of prepareQuery always returns the type, if doNotReturnFullEntities is set
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / taxon / TaxonDaoHibernateImpl.java
index 0a29bceb91c74f703dc46acd94a2912a5e84ba60..fe57c5371d3cc10548ad3adcf34780695efa3719 100644 (file)
 /**\r
-* Copyright (C) 2007 EDIT\r
-* European Distributed Institute of Taxonomy \r
-* http://www.e-taxonomy.eu\r
-* \r
-* The contents of this file are subject to the Mozilla Public License Version 1.1\r
-* See LICENSE.TXT at the top of this package for the full license terms.\r
-*/\r
+ * Copyright (C) 2007 EDIT\r
+ * European Distributed Institute of Taxonomy \r
+ * http://www.e-taxonomy.eu\r
+ \r
+ * The contents of this file are subject to the Mozilla Public License Version 1.1\r
+ * See LICENSE.TXT at the top of this package for the full license terms.\r
+ */\r
 package eu.etaxonomy.cdm.persistence.dao.hibernate.taxon;\r
 \r
 import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.Comparator;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.Iterator;\r
 import java.util.List;\r
 import java.util.Set;\r
+import java.util.SortedSet;\r
+import java.util.TreeSet;\r
 import java.util.UUID;\r
 \r
-import javax.persistence.FetchType;\r
-\r
 import org.apache.log4j.Logger;\r
+import org.apache.lucene.queryParser.ParseException;\r
 import org.hibernate.Criteria;\r
 import org.hibernate.FetchMode;\r
-import org.hibernate.LazyInitializationException;\r
+import org.hibernate.Hibernate;\r
 import org.hibernate.Query;\r
 import org.hibernate.Session;\r
 import org.hibernate.criterion.Criterion;\r
 import org.hibernate.criterion.Projections;\r
 import org.hibernate.criterion.Restrictions;\r
+import org.hibernate.envers.query.AuditEntity;\r
+import org.hibernate.envers.query.AuditQuery;\r
+import org.hibernate.search.FullTextSession;\r
+import org.hibernate.search.Search;\r
+import org.springframework.beans.factory.annotation.Autowired;\r
+import org.springframework.beans.factory.annotation.Qualifier;\r
 import org.springframework.dao.DataAccessException;\r
 import org.springframework.stereotype.Repository;\r
 \r
-import eu.etaxonomy.cdm.model.common.Annotation;\r
+import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
 import eu.etaxonomy.cdm.model.common.CdmBase;\r
-import eu.etaxonomy.cdm.model.common.DefinedTermBase;\r
-import eu.etaxonomy.cdm.model.common.Marker;\r
-import eu.etaxonomy.cdm.model.common.OriginalSource;\r
-import eu.etaxonomy.cdm.model.reference.ReferenceBase;\r
+import eu.etaxonomy.cdm.model.common.IdentifiableSource;\r
+import eu.etaxonomy.cdm.model.common.LSID;\r
+import eu.etaxonomy.cdm.model.common.OriginalSourceBase;\r
+import eu.etaxonomy.cdm.model.common.RelationshipBase;\r
+import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;\r
+import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;\r
+import eu.etaxonomy.cdm.model.location.NamedArea;\r
+import eu.etaxonomy.cdm.model.name.NonViralName;\r
+import eu.etaxonomy.cdm.model.name.Rank;\r
+import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
+import eu.etaxonomy.cdm.model.name.TaxonNameComparator;\r
+import eu.etaxonomy.cdm.model.name.ZoologicalName;\r
+import eu.etaxonomy.cdm.model.reference.Reference;\r
+import eu.etaxonomy.cdm.model.taxon.Classification;\r
 import eu.etaxonomy.cdm.model.taxon.Synonym;\r
 import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;\r
+import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;\r
 import eu.etaxonomy.cdm.model.taxon.Taxon;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
+import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;\r
-import eu.etaxonomy.cdm.persistence.dao.common.ITitledDao;\r
+import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;\r
+import eu.etaxonomy.cdm.model.view.AuditEvent;\r
+import eu.etaxonomy.cdm.persistence.dao.QueryParseException;\r
+import eu.etaxonomy.cdm.persistence.dao.hibernate.AlternativeSpellingSuggestionParser;\r
 import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;\r
+import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;\r
 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;\r
 import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;\r
+import eu.etaxonomy.cdm.persistence.query.MatchMode;\r
+import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
+import eu.etaxonomy.cdm.persistence.query.OrderHint.SortOrder;\r
+\r
 \r
 /**\r
  * @author a.mueller\r
- *\r
+ * @created 24.11.2008\r
+ * @version 1.0\r
  */\r
 @Repository\r
-public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implements ITaxonDao {\r
-       static Logger logger = Logger.getLogger(TaxonDaoHibernateImpl.class);\r
+@Qualifier("taxonDaoHibernateImpl")\r
+public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implements ITaxonDao {       \r
+       private AlternativeSpellingSuggestionParser<TaxonBase> alternativeSpellingSuggestionParser;\r
+       private static final Logger logger = Logger.getLogger(TaxonDaoHibernateImpl.class);\r
 \r
        public TaxonDaoHibernateImpl() {\r
                super(TaxonBase.class);\r
+               indexedClasses = new Class[2];\r
+               indexedClasses[0] = Taxon.class;\r
+               indexedClasses[1] = Synonym.class;\r
+               super.defaultField = "name.titleCache_tokenized";\r
+       }\r
+       \r
+       @Autowired\r
+       private ITaxonNameDao taxonNameDao;\r
+       \r
+       @Autowired(required = false)   //TODO switched of because it caused problems when starting CdmApplicationController\r
+       public void setAlternativeSpellingSuggestionParser(AlternativeSpellingSuggestionParser<TaxonBase> alternativeSpellingSuggestionParser) {\r
+               this.alternativeSpellingSuggestionParser = alternativeSpellingSuggestionParser; \r
        }\r
+       \r
 \r
        /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getRootTaxa(eu.etaxonomy.cdm.model.reference.ReferenceBase)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference)\r
         */\r
-       public List<Taxon> getRootTaxa(ReferenceBase sec) {\r
-               return getRootTaxa(sec, CdmFetch.FETCH_CHILDTAXA(), true);\r
+       public List<Taxon> getRootTaxa(Reference sec) {\r
+               return getRootTaxa(sec, CdmFetch.FETCH_CHILDTAXA(), true, false);\r
        }\r
-\r
+               \r
        /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getRootTaxa(eu.etaxonomy.cdm.model.reference.ReferenceBase, boolean)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, eu.etaxonomy.cdm.persistence.fetch.CdmFetch, java.lang.Boolean, java.lang.Boolean)\r
         */\r
-       public List<Taxon> getRootTaxa(ReferenceBase sec, CdmFetch cdmFetch, Boolean onlyWithChildren) {\r
+       public List<Taxon> getRootTaxa(Rank rank, Reference sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications, List<String> propertyPaths) {\r
+               checkNotInPriorView("TaxonDaoHibernateImpl.getRootTaxa(Rank rank, Reference sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications)");\r
                if (onlyWithChildren == null){\r
                        onlyWithChildren = true;\r
                }\r
+               if (withMisapplications == null){\r
+                       withMisapplications = true;\r
+               }\r
                if (cdmFetch == null){\r
                        cdmFetch = CdmFetch.NO_FETCH();\r
                }\r
+\r
+               Criteria crit = getSession().createCriteria(Taxon.class);\r
                \r
+               crit.setFetchMode("name", FetchMode.JOIN);\r
+               crit.createAlias("name", "name");\r
                \r
-//             String query = "from Taxon root ";\r
-//             query += " where root.taxonomicParentCache is NULL ";\r
-//             if (sec != null){\r
-//                     query += " AND root.sec.id = :sec "; \r
-//             }               \r
-//             Query q = getSession().createQuery(query);\r
-//             if (sec != null){\r
-//                     q.setInteger("sec", sec.getId());\r
-//             }\r
-               \r
-               \r
-               Criteria crit = getSession().createCriteria(Taxon.class);\r
-               crit.add(Restrictions.isNull("taxonomicParentCache"));\r
+               if (rank != null) {\r
+                       crit.add(Restrictions.eq("name.rank", rank));\r
+               }else{\r
+                       crit.add(Restrictions.isNull("taxonomicParentCache"));\r
+               }\r
+\r
                if (sec != null){\r
                        crit.add(Restrictions.eq("sec", sec) );\r
                }\r
-               \r
-               \r
+\r
                if (! cdmFetch.includes(CdmFetch.FETCH_CHILDTAXA())){\r
-                       logger.warn("no child taxa fetch qq");\r
+                       logger.info("Not fetching child taxa");\r
                        //TODO overwrite LAZY (SELECT) does not work (bug in hibernate?)\r
                        crit.setFetchMode("relationsToThisTaxon.fromTaxon", FetchMode.LAZY);\r
                }\r
-               \r
+\r
                List<Taxon> results = new ArrayList<Taxon>();\r
-               for(Taxon taxon : (List<Taxon>) crit.list()){\r
+               List<Taxon> taxa = crit.list();\r
+               for(Taxon taxon : taxa){\r
+                       \r
+                       \r
+                       //childTaxa\r
+                       //TODO create restriction instead\r
+                       // (a) not using cache fields\r
+                       /*Hibernate.initialize(taxon.getRelationsFromThisTaxon());\r
+                       if (onlyWithChildren == false || taxon.getRelationsFromThisTaxon().size() > 0){\r
+                               if (withMisapplications == true || ! taxon.isMisappliedName()){\r
+                                       defaultBeanInitializer.initialize(taxon, propertyPaths);\r
+                                       results.add(taxon);\r
+                               }\r
+                       }*/\r
+                       // (b) using cache fields\r
                        if (onlyWithChildren == false || taxon.hasTaxonomicChildren()){\r
-                               results.add(taxon);\r
+                               if (withMisapplications == true || ! taxon.isMisapplication()){\r
+                                       defaultBeanInitializer.initialize(taxon, propertyPaths);\r
+                                       results.add(taxon);\r
+                               }\r
                        }\r
                }\r
                return results;\r
        }\r
 \r
-       public List<TaxonBase> getTaxaByName(String name, ReferenceBase sec) {\r
-               Criteria crit = getSession().createCriteria(Taxon.class);\r
-               if (sec != null){\r
-                       crit.add(Restrictions.eq("sec", sec ) );\r
+       /* (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, eu.etaxonomy.cdm.persistence.fetch.CdmFetch, java.lang.Boolean, java.lang.Boolean)\r
+        */\r
+       public List<Taxon> getRootTaxa(Reference sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications) {\r
+               return getRootTaxa(null, sec, cdmFetch, onlyWithChildren, withMisapplications, null);\r
+       }\r
+       \r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getTaxaByName(java.lang.String, eu.etaxonomy.cdm.model.reference.Reference)\r
+        */\r
+       public List<TaxonBase> getTaxaByName(String queryString, Reference sec) {\r
+               \r
+               return getTaxaByName(queryString, true, sec);\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getTaxaByName(java.lang.String, java.lang.Boolean, eu.etaxonomy.cdm.model.reference.Reference)\r
+        */\r
+       public List<TaxonBase> getTaxaByName(String queryString, Boolean accepted, Reference sec) {\r
+               checkNotInPriorView("TaxonDaoHibernateImpl.getTaxaByName(String name, Reference sec)");\r
+               \r
+        Criteria criteria = null;\r
+               if (accepted == true) {\r
+                       criteria = getSession().createCriteria(Taxon.class);\r
+               } else {\r
+                       criteria = getSession().createCriteria(Synonym.class);\r
                }\r
-               crit.createCriteria("name").add(Restrictions.eq("titleCache", name));\r
-               List<TaxonBase> results = crit.list();\r
-               return results;\r
+               \r
+               criteria.setFetchMode( "name", FetchMode.JOIN );\r
+               criteria.createAlias("name", "name");\r
+               \r
+               if (sec != null && sec.getId() != 0) {\r
+                       criteria.add(Restrictions.eq("sec", sec ) );\r
+               }\r
+\r
+               if (queryString != null) {\r
+                       criteria.add(Restrictions.ilike("name.nameCache", queryString));\r
+               }\r
+\r
+               return (List<TaxonBase>)criteria.list();\r
        }\r
 \r
-       public List<TaxonBase> getAllTaxa(Integer pagesize, Integer page) {\r
-               Criteria crit = getSession().createCriteria(TaxonBase.class);\r
-               List<TaxonBase> results = crit.list();\r
-               // TODO add page & pagesize criteria\r
-               return results;\r
+       public List<TaxonBase> getTaxaByName(Class<? extends TaxonBase> clazz, String queryString, MatchMode matchMode,\r
+                       Integer pageSize, Integer pageNumber) {\r
+               \r
+               return getTaxaByName(clazz, queryString, null, matchMode, null, pageSize, pageNumber, null);\r
        }\r
        \r
-       @Override\r
-       public UUID delete(TaxonBase taxonBase) throws DataAccessException{\r
-               //getSession().update(taxonBase); doesn't work with lazy collections\r
-               //annotations\r
-               try {\r
-                       Set<Annotation> annotations = taxonBase.getAnnotations();\r
-                       for (Annotation annotation: annotations){\r
-                               taxonBase.removeAnnotation(annotation);\r
-                       }\r
-               } catch (LazyInitializationException e) {\r
-                       logger.warn("LazyInitializationException: " + e);\r
-               }\r
-               //markers\r
-               try {\r
-                       Set<Marker> markers = taxonBase.getMarkers();\r
-                       for (Marker marker: markers){\r
-                               taxonBase.removeMarker(marker);\r
-                       }\r
-               } catch (LazyInitializationException e) {\r
-                       logger.warn("LazyInitializationException: " + e);\r
-               }\r
-               //originalSource\r
-               try {\r
-                       Set<OriginalSource> origSources = taxonBase.getSources();\r
-                       for (OriginalSource source: origSources){\r
-                               taxonBase.removeSource(source);\r
-                       }\r
-               } catch (LazyInitializationException e) {\r
-                       logger.warn("LazyInitializationException: " + e);\r
-               }\r
-               //is Taxon\r
-               taxonBase.getName().removeTaxonBase(taxonBase);\r
-               if (taxonBase instanceof Taxon){\r
-                       //taxonRelationships\r
-                       Taxon taxon = (Taxon)taxonBase;\r
-                       Set<TaxonRelationship> taxRels = taxon.getTaxonRelations();\r
-                       for (TaxonRelationship taxRel: taxRels){\r
-                               taxon.removeTaxonRelation(taxRel);\r
-                       } ;\r
-                       //SynonymRelationships\r
-                       Set<SynonymRelationship> synRels = taxon.getSynonymRelations();\r
-                       for (SynonymRelationship synRel: synRels){\r
-                               taxon.removeSynonymRelation(synRel);\r
-                       } ;\r
-               }//is Synonym\r
-               else if (taxonBase instanceof Synonym){\r
-                       Synonym synonym = (Synonym)taxonBase;\r
-                       Set<SynonymRelationship> synRels = synonym.getSynonymRelations();\r
-                       for (SynonymRelationship synRel: synRels){\r
-                               synonym.removeSynonymRelation(synRel);\r
-                       } ;\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getTaxaByName(java.lang.String, eu.etaxonomy.cdm.persistence.query.MatchMode, java.lang.Boolean, java.lang.Integer, java.lang.Integer)\r
+        */\r
+       public List<TaxonBase> getTaxaByName(String queryString, MatchMode matchMode, \r
+                       Boolean accepted, Integer pageSize, Integer pageNumber) {\r
+               \r
+               if (accepted == true) {\r
+                       return getTaxaByName(Taxon.class, queryString, matchMode, pageSize, pageNumber);\r
+               } else {\r
+                       return getTaxaByName(Synonym.class, queryString, matchMode, pageSize, pageNumber);\r
+               }\r
+       }\r
+       \r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getTaxaByName(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.persistence.query.MatchMode, java.util.Set, java.lang.Integer, java.lang.Integer, java.util.List)\r
+        */\r
+       public List<TaxonBase> getTaxaByName(Class<? extends TaxonBase> clazz, String queryString, Classification classification,\r
+                       MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize, \r
+                       Integer pageNumber, List<String> propertyPaths) {\r
+                               \r
+               boolean doCount = false;\r
+                       \r
+               Query query = prepareTaxaByName(clazz, "nameCache", queryString, classification, matchMode, namedAreas, pageSize, pageNumber, doCount);\r
+               \r
+               if (query != null){\r
+                       List<TaxonBase> results = query.list();\r
+                       \r
+                       defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+                       //TaxonComparatorSearch comp = new TaxonComparatorSearch();\r
+                       //Collections.sort(results, comp);\r
+                       return results;\r
+               }\r
+               \r
+               return new ArrayList<TaxonBase>();\r
+               \r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getTaxaByName(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.persistence.query.MatchMode, java.util.Set, java.lang.Integer, java.lang.Integer, java.util.List)\r
+        */\r
+       //new search for the editor, for performance issues the return values are only uuid and titleCache, to avoid the initialisation of all objects\r
+       @SuppressWarnings("unchecked")\r
+       public List<UuidAndTitleCache<TaxonBase>> getTaxaByNameForEditor(Class<? extends TaxonBase> clazz, String queryString, Classification classification,\r
+                       MatchMode matchMode, Set<NamedArea> namedAreas) {\r
+               long zstVorher;\r
+               long zstNachher;\r
+                               \r
+               boolean doCount = false;\r
+               Query query = prepareTaxaByNameForEditor(clazz, "nameCache", queryString, classification, matchMode, namedAreas, doCount);\r
+               \r
+               \r
+               if (query != null){\r
+                       List<Object[]> results = query.list();\r
+                       \r
+                       List<UuidAndTitleCache<TaxonBase>> resultObjects = new ArrayList<UuidAndTitleCache<TaxonBase>>();\r
+                       Object[] result;\r
+                       for(int i = 0; i<results.size();i++){\r
+                               result = results.get(i);\r
+                               \r
+                               //unterscheiden von taxa und synonymen\r
+                               if (clazz.equals(Taxon.class)){\r
+                                               resultObjects.add( new UuidAndTitleCache(Taxon.class, (UUID) result[0], (String)result[1]));\r
+                               }else if (clazz.equals(Synonym.class)){\r
+                                       resultObjects.add( new UuidAndTitleCache(Synonym.class, (UUID) result[0], (String)result[1]));\r
+                               } else{\r
+                                       if (result[2].equals("synonym")) {\r
+                                               resultObjects.add( new UuidAndTitleCache(Synonym.class, (UUID) result[0], (String)result[1]));\r
+                                       }\r
+                                       else {\r
+                                               resultObjects.add( new UuidAndTitleCache(Taxon.class, (UUID) result[0], (String)result[1]));\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       return resultObjects;\r
+                       \r
+               }\r
+               return new ArrayList<UuidAndTitleCache<TaxonBase>>();\r
+               \r
+       }\r
+       \r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getTaxaByCommonName(java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.persistence.query.MatchMode, java.util.Set, java.lang.Integer, java.lang.Integer, java.util.List)\r
+        */\r
+       public List<TaxonBase> getTaxaByCommonName(String queryString, Classification classification,\r
+                       MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize, \r
+                       Integer pageNumber, List<String> propertyPaths) {\r
+                       boolean doCount = false;        \r
+                       Query query = prepareTaxaByCommonName(queryString, classification, matchMode, namedAreas, pageSize, pageNumber, doCount);\r
+                       if (query != null){\r
+                               List<TaxonBase> results = query.list();\r
+                               defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+                               return results;\r
+                       }\r
+                       return new ArrayList<TaxonBase>();\r
+               \r
+       }\r
+       \r
+       /**\r
+        * @param clazz\r
+        * @param searchField the field in TaxonNameBase to be searched through usually either <code>nameCache</code> or <code>titleCache</code>\r
+        * @param queryString\r
+        * @param classification TODO\r
+        * @param matchMode\r
+        * @param namedAreas\r
+        * @param pageSize\r
+        * @param pageNumber\r
+        * @param doCount\r
+        * @return\r
+        * \r
+        *\r
+        */\r
+       private Query prepareTaxaByNameForEditor(Class<? extends TaxonBase> clazz, String searchField, String queryString, Classification classification,\r
+                       MatchMode matchMode, Set<NamedArea> namedAreas, boolean doCount) {\r
+               return prepareQuery(clazz, searchField, queryString, classification,\r
+                               matchMode, namedAreas, doCount, true);\r
+       }\r
+       \r
+       /**\r
+        * @param clazz\r
+        * @param searchField\r
+        * @param queryString\r
+        * @param classification\r
+        * @param matchMode\r
+        * @param namedAreas\r
+        * @param doCount\r
+        * @param doNotReturnFullEntities\r
+        *            if set true the seach method will not return synonym and taxon\r
+        *            entities but an array containing the uuid, titleCache, and the\r
+        *            DTYPE in lowercase letters.\r
+        * @return\r
+        */\r
+       private Query prepareQuery(Class<? extends TaxonBase> clazz, String searchField, String queryString, Classification classification,\r
+                       MatchMode matchMode, Set<NamedArea> namedAreas, boolean doCount, boolean doNotReturnFullEntities){\r
+               \r
+               String hqlQueryString = matchMode.queryStringFrom(queryString);\r
+               String selectWhat;\r
+               if (doNotReturnFullEntities){\r
+                       selectWhat = "t.uuid, t.titleCache ";\r
+               }else {\r
+                       selectWhat = (doCount ? "count(t)": "t");\r
+               }\r
+               \r
+               String hql = "";\r
+               Set<NamedArea> areasExpanded = new HashSet<NamedArea>();\r
+               if(namedAreas != null && namedAreas.size() > 0){\r
+                       // expand areas and restrict by distribution area\r
+                       List<NamedArea> childAreas;\r
+                       Query areaQuery = getSession().createQuery("select childArea from NamedArea as childArea left join childArea.partOf as parentArea where parentArea = :area");\r
+                       expandNamedAreas(namedAreas, areasExpanded, areaQuery);\r
+               }\r
+               boolean doAreaRestriction = areasExpanded.size() > 0;\r
+               \r
+               Set<UUID> namedAreasUuids = new HashSet<UUID>();\r
+               for (NamedArea area:areasExpanded){\r
+                       namedAreasUuids.add(area.getUuid());\r
+               }\r
+               \r
+               String taxonSubselect = null;\r
+               String synonymSubselect = null;\r
+               \r
+               if(classification != null){\r
+                       \r
+                       if(doAreaRestriction){\r
+                               \r
+                               taxonSubselect = "select t.id from" +\r
+                                       " Distribution e" +\r
+                                       " join e.inDescription d" +\r
+                                       " join d.taxon t" +\r
+                                       " join t.name n " +\r
+                                       " join t.taxonNodes as tn "+\r
+                                       " where" +\r
+                                       " e.area.uuid in (:namedAreasUuids) AND" +\r
+                                       " tn.classification = :classification" +\r
+                                       " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString";\r
+                               \r
+                               \r
+                               synonymSubselect = "select s.id from" +\r
+                                       " Distribution e" +\r
+                                       " join e.inDescription d" +\r
+                                       " join d.taxon t" + // the taxa\r
+                                       " join t.taxonNodes as tn "+\r
+                                       " join t.synonymRelations sr" +\r
+                                       " join sr.relatedFrom s" + // the synonyms\r
+                                       " join s.name sn"+ \r
+                                       " where" +\r
+                                       " e.area.uuid in (:namedAreasUuids) AND" +\r
+                                       " tn.classification = :classification" +\r
+                                       " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                               \r
+                       } else {\r
+                               \r
+                               taxonSubselect = "select t.id from" +\r
+                                       " Taxon t" +\r
+                                       " join t.name n " +\r
+                                       " join t.taxonNodes as tn "+\r
+                                       " where" +\r
+                                       " tn.classification = :classification" +\r
+                                       " AND n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                               \r
+                               synonymSubselect = "select s.id from" +\r
+                                       " Taxon t" + // the taxa\r
+                                       " join t.taxonNodes as tn "+\r
+                                       " join t.synonymRelations sr" +\r
+                                       " join sr.relatedFrom s" + // the synonyms\r
+                                       " join s.name sn"+ \r
+                                       " where" +\r
+                                       " tn.classification = :classification" +\r
+                                       " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                       }       \r
+               } else {\r
+                       \r
+                       if(doAreaRestriction){\r
+                               \r
+                               taxonSubselect = "select t.id from " +\r
+                                       " Distribution e" +\r
+                                       " join e.inDescription d" +\r
+                                       " join d.taxon t" +\r
+                                       " join t.name n "+\r
+                                       " where" +\r
+                                       (doAreaRestriction ? " e.area.uuid in (:namedAreasUuids) AND" : "") +\r
+                                       " n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                               \r
+                               synonymSubselect = "select s.id from" +\r
+                                       " Distribution e" +\r
+                                       " join e.inDescription d" +\r
+                                       " join d.taxon t" + // the taxa\r
+                                       " join t.synonymRelations sr" +\r
+                                       " join sr.relatedFrom s" + // the synonyms\r
+                                       " join s.name sn"+ \r
+                                       " where" +\r
+                                       (doAreaRestriction ? " e.area.uuid in (:namedAreasUuids) AND" : "") +\r
+                                       " sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                               \r
+                       } else {\r
+                               \r
+                               taxonSubselect = "select t.id from " +\r
+                                       " Taxon t" +\r
+                                       " join t.name n "+\r
+                                       " where" +\r
+                                       " n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+\r
+                               synonymSubselect = "select s.id from" +\r
+                                       " Taxon t" + // the taxa\r
+                                       " join t.synonymRelations sr" +\r
+                                       " join sr.relatedFrom s" + // the synonyms\r
+                                       " join s.name sn"+ \r
+                                       " where" +\r
+                                       " sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                       }\r
+                       \r
+               }\r
+               \r
+               Query subTaxon = null;\r
+               Query subSynonym = null;\r
+               if(clazz.equals(Taxon.class)){\r
+                       // find Taxa\r
+                       subTaxon = getSession().createQuery(taxonSubselect).setParameter("queryString", hqlQueryString);\r
+                       //subTaxon = getSession().createQuery(taxonSubselect);\r
+                       \r
+                       if(doAreaRestriction){\r
+                               subTaxon.setParameterList("namedAreasUuids", namedAreasUuids);\r
+                       }       \r
+                       if(classification != null){\r
+                               subTaxon.setParameter("classification", classification);\r
+                       }\r
+               } else if(clazz.equals(Synonym.class)){\r
+                       // find synonyms\r
+                       subSynonym = getSession().createQuery(synonymSubselect).setParameter("queryString", hqlQueryString);\r
+                       \r
+                       if(doAreaRestriction){\r
+                               subSynonym.setParameterList("namedAreasUuids", namedAreasUuids);\r
+                       }               \r
+                       if(classification != null){\r
+                               subSynonym.setParameter("classification", classification);\r
+                       }\r
+               } else {\r
+                       // find taxa and synonyms\r
+                       subSynonym = getSession().createQuery(synonymSubselect).setParameter("queryString", hqlQueryString);\r
+                       subTaxon = getSession().createQuery(taxonSubselect).setParameter("queryString", hqlQueryString);\r
+                       if(doAreaRestriction){\r
+                               subTaxon.setParameterList("namedAreasUuids", namedAreasUuids);\r
+                               subSynonym.setParameterList("namedAreasUuids", namedAreasUuids);\r
+                       }\r
+                       if(classification != null){\r
+                               subTaxon.setParameter("classification", classification);\r
+                               subSynonym.setParameter("classification", classification);\r
+                       }\r
+               }\r
+               \r
+               List<Integer> taxa = new ArrayList<Integer>();\r
+               List<Integer> synonyms = new ArrayList<Integer>();\r
+               if(clazz.equals(Taxon.class)){\r
+                       taxa = subTaxon.list();\r
+                       \r
+               }else if (clazz.equals(Synonym.class)){\r
+                       synonyms = subSynonym.list();\r
+               }else {\r
+                       taxa = subTaxon.list();\r
+                       synonyms = subSynonym.list();\r
+               }\r
+               if(clazz.equals(Taxon.class)){\r
+                       if  (taxa.size()>0){\r
+                               if (doNotReturnFullEntities){\r
+                                       hql = "select " + selectWhat + ", 'taxon' from " + clazz.getSimpleName() + " t" + " where t.id in (:taxa)";\r
+                               }else{\r
+                                       hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t" + " where t.id in (:taxa)";\r
+                               }\r
+                       }else{\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t";\r
+                       }\r
+               } else if(clazz.equals(Synonym.class) ){\r
+                       if (synonyms.size()>0){\r
+                               if (doNotReturnFullEntities){\r
+                                       hql = "select " + selectWhat + ", 'synonym' from " + clazz.getSimpleName() + " t" + " where t.id in (:synonyms)";\r
+                               }else{\r
+                                       hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t" + " where t.id in (:synonyms)";          \r
+                               }\r
+                       }else{\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t";\r
+                       }\r
+               } else {\r
+                       \r
+                       if(synonyms.size()>0 && taxa.size()>0){\r
+                               if (doNotReturnFullEntities &&  !doCount ){\r
+                                       // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:\r
+                                       hql = "select " + selectWhat + ", case when t.id in (:taxa) then 'taxon' else 'synonym' end" + " from " + clazz.getSimpleName() + " t" + " where t.id in (:taxa) OR t.id in (:synonyms)";\r
+                               }else{\r
+                                       hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t" + " where t.id in (:taxa) OR t.id in (:synonyms)";\r
+                               }\r
+                       }else if (synonyms.size()>0 ){\r
+                               if (doNotReturnFullEntities &&  !doCount ){\r
+                                       // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:\r
+                                       hql = "select " + selectWhat + ", 'synonym' from " + clazz.getSimpleName() + " t" + " where t.id in (:synonyms)";       \r
+                               } else {\r
+                                       hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t" + " where t.id in (:synonyms)";          \r
+                               }\r
+                       } else if (taxa.size()>0 ){\r
+                               if (doNotReturnFullEntities &&  !doCount ){\r
+                                       // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:\r
+                                       hql = "select " + selectWhat + ", 'taxon' from " + clazz.getSimpleName() + " t" + " where t.id in (:taxa) ";\r
+                               } else {\r
+                                       hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t" + " where t.id in (:taxa) ";\r
+                               }\r
+                       } else{\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t";\r
+                       }\r
+               }\r
+               \r
+               if (hql == "") return null;\r
+               if(!doCount){\r
+                       hql += " order by t.name.genusOrUninomial, case when t.name.specificEpithet like '\"%\"' then 1 else 0 end, t.name.specificEpithet, t.name.rank desc, t.name.nameCache";\r
+               }\r
+       \r
+               Query query = getSession().createQuery(hql);\r
+                               \r
+               if(clazz.equals(Taxon.class) && taxa.size()>0){\r
+                       //find taxa\r
+                       query.setParameterList("taxa", taxa );\r
+               } else if(clazz.equals(Synonym.class) && synonyms.size()>0){\r
+                       // find synonyms\r
+                       query.setParameterList("synonyms", synonyms);\r
+                       \r
+               \r
+               } else {\r
+                       // find taxa and synonyms\r
+                       if (taxa.size()>0){\r
+                               query.setParameterList("taxa", taxa);\r
+                       }\r
+                       if (synonyms.size()>0){\r
+                               query.setParameterList("synonyms",synonyms);\r
+                       }\r
+                       if (taxa.size()== 0 && synonyms.size() == 0){\r
+                               return null;\r
+                       }\r
+               }\r
+               return query;\r
+               \r
+       }\r
+       \r
+       \r
+       /**\r
+        * @param clazz\r
+        * @param searchField the field in TaxonNameBase to be searched through usually either <code>nameCache</code> or <code>titleCache</code>\r
+        * @param queryString\r
+        * @param classification TODO\r
+        * @param matchMode\r
+        * @param namedAreas\r
+        * @param pageSize\r
+        * @param pageNumber\r
+        * @param doCount\r
+        * @return\r
+        * \r
+        * FIXME implement classification restriction & implement test: see {@link TaxonDaoHibernateImplTest#testCountTaxaByName()}\r
+        */\r
+       private Query prepareTaxaByName(Class<? extends TaxonBase> clazz, String searchField, String queryString, Classification classification,\r
+                       MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize, Integer pageNumber, boolean doCount) {\r
+\r
+               //TODO ? checkNotInPriorView("TaxonDaoHibernateImpl.countTaxaByName(String queryString, Boolean accepted, Reference sec)");\r
+\r
+               /*String hqlQueryString = matchMode.queryStringFrom(queryString);\r
+               \r
+               String selectWhat = (doCount ? "count(t)": "t");\r
+               \r
+               String hql = "";\r
+               Set<NamedArea> areasExpanded = new HashSet<NamedArea>();\r
+               if(namedAreas != null && namedAreas.size() > 0){\r
+                       // expand areas and restrict by distribution area\r
+                       List<NamedArea> childAreas;\r
+                       Query areaQuery = getSession().createQuery("select childArea from NamedArea as childArea left join childArea.partOf as parentArea where parentArea = :area");\r
+                       expandNamedAreas(namedAreas, areasExpanded, areaQuery);\r
+               }\r
+               boolean doAreaRestriction = areasExpanded.size() > 0;\r
+               \r
+               Set<UUID> namedAreasUuids = new HashSet<UUID>();\r
+               for (NamedArea area:areasExpanded){\r
+                       namedAreasUuids.add(area.getUuid());\r
+               }\r
+               \r
+               String taxonSubselect = null;\r
+               String synonymSubselect = null;\r
+               \r
+               if(classification != null){\r
+                       \r
+                       if(doAreaRestriction){\r
+                               \r
+                               taxonSubselect = "select t.id from" +\r
+                                       " Distribution e" +\r
+                                       " join e.inDescription d" +\r
+                                       " join d.taxon t" +\r
+                                       " join t.name n " +\r
+                                       " join t.taxonNodes as tn "+\r
+                                       " where" +\r
+                                       " e.area.uuid in (:namedAreasUuids) AND" +\r
+                                       " tn.classification = :classification" +\r
+                                       " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString";\r
+                               \r
+                               \r
+                               synonymSubselect = "select s.id from" +\r
+                                       " Distribution e" +\r
+                                       " join e.inDescription d" +\r
+                                       " join d.taxon t" + // the taxa\r
+                                       " join t.taxonNodes as tn "+\r
+                                       " join t.synonymRelations sr" +\r
+                                       " join sr.relatedFrom s" + // the synonyms\r
+                                       " join s.name sn"+ \r
+                                       " where" +\r
+                                       " e.area.uuid in (:namedAreasUuids) AND" +\r
+                                       " tn.classification = :classification" +\r
+                                       " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                               \r
+                       } else {\r
+                               \r
+                               taxonSubselect = "select t.id from" +\r
+                                       " Taxon t" +\r
+                                       " join t.name n " +\r
+                                       " join t.taxonNodes as tn "+\r
+                                       " where" +\r
+                                       " tn.classification = :classification" +\r
+                                       " AND n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                               \r
+                               synonymSubselect = "select s.id from" +\r
+                                       " Taxon t" + // the taxa\r
+                                       " join t.taxonNodes as tn "+\r
+                                       " join t.synonymRelations sr" +\r
+                                       " join sr.relatedFrom s" + // the synonyms\r
+                                       " join s.name sn"+ \r
+                                       " where" +\r
+                                       " tn.classification = :classification" +\r
+                                       " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                       }       \r
+               } else {\r
+                       \r
+                       if(doAreaRestriction){\r
+                               \r
+                               taxonSubselect = "select t.id from " +\r
+                                       " Distribution e" +\r
+                                       " join e.inDescription d" +\r
+                                       " join d.taxon t" +\r
+                                       " join t.name n "+\r
+                                       " where" +\r
+                                       (doAreaRestriction ? " e.area.uuid in (:namedAreasUuids) AND" : "") +\r
+                                       " n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                               \r
+                               synonymSubselect = "select s.id from" +\r
+                                       " Distribution e" +\r
+                                       " join e.inDescription d" +\r
+                                       " join d.taxon t" + // the taxa\r
+                                       " join t.synonymRelations sr" +\r
+                                       " join sr.relatedFrom s" + // the synonyms\r
+                                       " join s.name sn"+ \r
+                                       " where" +\r
+                                       (doAreaRestriction ? " e.area.uuid in (:namedAreasUuids) AND" : "") +\r
+                                       " sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                               \r
+                       } else {\r
+                               \r
+                               taxonSubselect = "select t.id from " +\r
+                                       " Taxon t" +\r
+                                       " join t.name n "+\r
+                                       " where" +\r
+                                       " n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+\r
+                               synonymSubselect = "select s.id from" +\r
+                                       " Taxon t" + // the taxa\r
+                                       " join t.synonymRelations sr" +\r
+                                       " join sr.relatedFrom s" + // the synonyms\r
+                                       " join s.name sn"+ \r
+                                       " where" +\r
+                                       " sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";\r
+                       }\r
+                       \r
+               \r
+               }\r
+               \r
+               \r
+               \r
+               \r
+               Query subTaxon = null;\r
+               Query subSynonym = null;\r
+               if(clazz.equals(Taxon.class)){\r
+                       // find Taxa\r
+                       subTaxon = getSession().createQuery(taxonSubselect).setParameter("queryString", hqlQueryString);\r
+                       //subTaxon = getSession().createQuery(taxonSubselect);\r
+                       \r
+                       if(doAreaRestriction){\r
+                               subTaxon.setParameterList("namedAreasUuids", namedAreasUuids);\r
+                       }       \r
+                       if(classification != null){\r
+                               subTaxon.setParameter("classification", classification);\r
+                       }\r
+               } else if(clazz.equals(Synonym.class)){\r
+                       // find synonyms\r
+                       subSynonym = getSession().createQuery(synonymSubselect).setParameter("queryString", hqlQueryString);\r
+                       \r
+                       if(doAreaRestriction){\r
+                               subSynonym.setParameterList("namedAreasUuids", namedAreasUuids);\r
+                       }               \r
+                       if(classification != null){\r
+                               subSynonym.setParameter("classification", classification);\r
+                       }\r
+               } else {\r
+                       // find taxa and synonyms\r
+                       subSynonym = getSession().createQuery(synonymSubselect).setParameter("queryString", hqlQueryString);\r
+                       subTaxon = getSession().createQuery(taxonSubselect).setParameter("queryString", hqlQueryString);\r
+                       if(doAreaRestriction){\r
+                               subTaxon.setParameterList("namedAreasUuids", namedAreasUuids);\r
+                               subSynonym.setParameterList("namedAreasUuids", namedAreasUuids);\r
+                       }\r
+                       if(classification != null){\r
+                               subTaxon.setParameter("classification", classification);\r
+                               subSynonym.setParameter("classification", classification);\r
+                       }\r
+               }\r
+               \r
+               List<Integer> taxa = new ArrayList<Integer>();\r
+               List<Integer> synonyms = new ArrayList<Integer>();\r
+               if(clazz.equals(Taxon.class)){\r
+                       taxa = subTaxon.list();\r
+                       \r
+               }else if (clazz.equals(Synonym.class)){\r
+                       synonyms = subSynonym.list();\r
+               }else {\r
+                       taxa = subTaxon.list();\r
+                       synonyms = subSynonym.list();\r
+               }\r
+               if(clazz.equals(Taxon.class)){\r
+                       if  (taxa.size()>0){\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t" + " where t.id in (:taxa)";\r
+                       }else{\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t";\r
+                       }\r
+               } else if(clazz.equals(Synonym.class) ){\r
+                       if (synonyms.size()>0){\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t" + " where t.id in (:synonyms)";          \r
+                       }else{\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t";\r
+                       }\r
+               } else {\r
+                       if(synonyms.size()>0 && taxa.size()>0){\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t" + " where t.id in (:taxa) OR t.id in (:synonyms)";\r
+                       }else if (synonyms.size()>0 ){\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t" + " where t.id in (:synonyms)";  \r
+                       } else if (taxa.size()>0 ){\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t" + " where t.id in (:taxa) ";\r
+                       } else{\r
+                               hql = "select " + selectWhat + " from " + clazz.getSimpleName() + " t";\r
+                       }\r
+               }\r
+               \r
+               if (hql == "") return null;\r
+               if(!doCount){\r
+                       //hql += " order by t.titleCache"; //" order by t.name.nameCache";\r
+                       hql += " order by t.name.genusOrUninomial, case when t.name.specificEpithet like '\"%\"' then 1 else 0 end, t.name.specificEpithet, t.name.rank desc, t.name.nameCache";\r
+                       \r
+    \r
+               }\r
+       \r
+               Query query = getSession().createQuery(hql);\r
+               \r
+                               \r
+               if(clazz.equals(Taxon.class) && taxa.size()>0){\r
+                       //find taxa\r
+                       query.setParameterList("taxa", taxa );\r
+               } else if(clazz.equals(Synonym.class) && synonyms.size()>0){\r
+                       // find synonyms\r
+                       query.setParameterList("synonyms", synonyms);\r
+                       \r
+               \r
+               } else {\r
+                       // find taxa and synonyms\r
+                       if (taxa.size()>0){\r
+                               query.setParameterList("taxa", taxa);\r
+                       }\r
+                       if (synonyms.size()>0){\r
+                               query.setParameterList("synonyms",synonyms);\r
+                       }\r
+                       if (taxa.size()== 0 && synonyms.size() == 0){\r
+                               return null;\r
+                       }\r
+               }*/\r
+               Query query = prepareQuery(clazz, searchField, queryString, classification,\r
+                               matchMode, namedAreas, doCount, false);\r
+               \r
+               if(pageSize != null &&  !doCount) {\r
+                       query.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                               query.setFirstResult(pageNumber * pageSize);\r
+                       }\r
+               }\r
+               \r
+               return query;\r
+       }\r
+\r
+       private Query prepareTaxaByCommonName(String queryString, Classification classification,\r
+                       MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize, Integer pageNumber, boolean doCount){\r
+                               \r
+               String hql= "from Taxon t " +\r
+               "join t.descriptions d "+\r
+               "join d.descriptionElements e " +\r
+               "join e.feature f " +\r
+               "where f.supportsCommonTaxonName = true and e.name "+matchMode.getMatchOperator()+" :queryString";//and ls.text like 'common%'";\r
+               \r
+               Query query = getSession().createQuery(hql);\r
+               \r
+               query.setParameter("queryString", queryString);\r
+               \r
+               if(pageSize != null &&  !doCount) {\r
+                       query.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                               query.setFirstResult(pageNumber * pageSize);\r
+                       }\r
+               }\r
+               return query;\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countTaxaByName(java.lang.String, eu.etaxonomy.cdm.persistence.query.MatchMode, eu.etaxonomy.cdm.persistence.query.SelectMode, eu.etaxonomy.cdm.model.reference.Reference, java.util.Set)\r
+        */\r
+       public long countTaxaByName(Class<? extends TaxonBase> clazz, String queryString, Classification classification,\r
+               MatchMode matchMode, Set<NamedArea> namedAreas) {\r
+               \r
+               boolean doCount = true;\r
+               Query query = prepareTaxaByName(clazz, "nameCache", queryString, classification, matchMode, namedAreas, null, null, doCount);\r
+               if (query != null) {\r
+                       return (Long)query.uniqueResult();\r
+               }else{\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * @param namedAreas\r
+        * @param areasExpanded\r
+        * @param areaQuery\r
+        */\r
+       private void expandNamedAreas(Collection<NamedArea> namedAreas, Set<NamedArea> areasExpanded, Query areaQuery) {\r
+               List<NamedArea> childAreas;\r
+               for(NamedArea a : namedAreas){\r
+                       areasExpanded.add(a);\r
+                       areaQuery.setParameter("area", a);\r
+                       childAreas = areaQuery.list();\r
+                       if(childAreas.size() > 0){\r
+                               areasExpanded.addAll(childAreas);\r
+                               expandNamedAreas(childAreas, areasExpanded, areaQuery);\r
+                       }\r
                }\r
-               return super.delete(taxonBase);\r
        }\r
+       \r
+//     /* (non-Javadoc)\r
+//      * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countTaxaByName(java.lang.String, eu.etaxonomy.cdm.persistence.query.MatchMode, eu.etaxonomy.cdm.persistence.query.SelectMode)\r
+//      */\r
+//     public Integer countTaxaByName(String queryString, MatchMode matchMode, SelectMode selectMode) {                \r
+//             return countTaxaByName(queryString, matchMode, selectMode, null);\r
+//     }\r
 \r
+//     /* (non-Javadoc)\r
+//      * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countTaxaByName(java.lang.String, eu.etaxonomy.cdm.persistence.query.MatchMode, eu.etaxonomy.cdm.persistence.query.SelectMode, eu.etaxonomy.cdm.model.reference.Reference)\r
+//      */\r
+//     public Integer countTaxaByName(String queryString, \r
+//                     MatchMode matchMode, SelectMode selectMode, Reference sec) {\r
+//\r
+//             Long count = countTaxaByName(queryString, matchMode, selectMode, sec, null);\r
+//             return count.intValue();\r
+//\r
+//     }\r
+       \r
+//     public Integer countTaxaByName(String queryString, MatchMode matchMode, Boolean accepted) {\r
+//             \r
+//             SelectMode selectMode = (accepted ? SelectMode.TAXA : SelectMode.SYNONYMS);\r
+//             Long count = countTaxaByName(queryString, matchMode, selectMode, null, null);\r
+//             return count.intValue();\r
+//     }\r
        \r
-       // TODO add generic return type !!\r
-       public List findByName(String queryString, ITitledDao.MATCH_MODE matchMode, int page, int pagesize, boolean onlyAcccepted) {\r
-                       ArrayList<Criterion> criteria = new ArrayList<Criterion>();\r
-                       //TODO ... Restrictions.eq(propertyName, value)\r
-                       return super.findByTitle(queryString, matchMode, page, pagesize, criteria);\r
+       public List<TaxonBase> getAllTaxonBases(Integer pagesize, Integer page) {\r
+               return super.list(pagesize, page);\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getAllSynonyms(java.lang.Integer, java.lang.Integer)\r
+        */\r
+       public List<Synonym> getAllSynonyms(Integer limit, Integer start) {\r
+               Criteria criteria = getSession().createCriteria(Synonym.class);\r
+               \r
+               if(limit != null) {\r
+                       criteria.setFirstResult(start);\r
+                       criteria.setMaxResults(limit);\r
+               }\r
+               \r
+               return criteria.list();\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getAllTaxa(java.lang.Integer, java.lang.Integer)\r
+        */\r
+       public List<Taxon> getAllTaxa(Integer limit, Integer start) {\r
+        Criteria criteria = getSession().createCriteria(Taxon.class);\r
                \r
+               if(limit != null) {\r
+                       criteria.setFirstResult(start);\r
+                       criteria.setMaxResults(limit);\r
+               }\r
+               \r
+               return criteria.list();\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getAllRelationships(java.lang.Integer, java.lang.Integer)\r
+        */\r
+       public List<RelationshipBase> getAllRelationships(Integer limit, Integer start) {\r
+               AuditEvent auditEvent = getAuditEventFromContext();\r
+               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+                   Criteria criteria = getSession().createCriteria(RelationshipBase.class);\r
+                   criteria.setFirstResult(start);\r
+                   criteria.setMaxResults(limit);\r
+                   return (List<RelationshipBase>)criteria.list();\r
+               } else {\r
+                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(RelationshipBase.class,auditEvent.getRevisionNumber());\r
+                       return (List<RelationshipBase>)query.getResultList();\r
+               }\r
        }\r
        \r
-       public int countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted) {\r
+       /** Sets the taxonomic parent to null. Does not handle taxonomic relationships. */\r
+//     private boolean nullifyTaxonomicParent(Taxon taxon) {\r
+//\r
+//             try {\r
+//                     Method nullifyTaxonomicParent = taxon.getClass().getMethod("nullifyTaxonomicParent");\r
+//                     nullifyTaxonomicParent.invoke(taxon);\r
+//             } catch (NoSuchMethodException ex) {\r
+//                     logger.error("NoSuchMethod: " + ex.getMessage());\r
+//                     return false;\r
+//             } catch (IllegalArgumentException ex) {\r
+//                     logger.error("IllegalArgumentException: " + ex.getMessage());\r
+//                     return false;\r
+//             } catch (IllegalAccessException ex) {\r
+//                     logger.error("IllegalAccessException: " + ex.getMessage());\r
+//                     return false;\r
+//             } catch (InvocationTargetException ex) {\r
+//                     logger.error("IllegalAccessException: " + ex.getMessage());\r
+//                     return false;\r
+//             }\r
+//             return true;\r
+//     }\r
+       \r
+       @Override\r
+       public UUID delete(TaxonBase taxonBase) throws DataAccessException{\r
+               if (taxonBase == null){\r
+                       logger.warn("TaxonBase was 'null'");\r
+                       return null;\r
+               }\r
+               \r
+               // Merge the object in if it is detached\r
+               //\r
+               // I think this is preferable to catching lazy initialization errors \r
+               // as that solution only swallows and hides the exception, but doesn't \r
+               // actually solve it.\r
+               getSession().merge(taxonBase);\r
+               \r
+               if (taxonBase instanceof Taxon){ //     is Taxon\r
+                       for (Iterator<TaxonRelationship> iterator = ((Taxon)taxonBase).getRelationsFromThisTaxon().iterator(); iterator.hasNext();){\r
+                               TaxonRelationship relationFromThisTaxon = iterator.next();\r
+                               \r
+                               // decrease children count of taxonomic parent by one\r
+                               if (relationFromThisTaxon.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())) {\r
+                                       Taxon toTaxon = relationFromThisTaxon.getToTaxon(); // parent\r
+                                       if (toTaxon != null) {\r
+                                               toTaxon.setTaxonomicChildrenCount(toTaxon.getTaxonomicChildrenCount() - 1);     \r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
                \r
+               return super.delete(taxonBase);\r
+       }\r
+\r
+\r
+       /* (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#findByName(java.lang.String, eu.etaxonomy.cdm.persistence.query.MatchMode, int, int, boolean)\r
+        */\r
+       public List<TaxonBase> findByNameTitleCache(Class<? extends TaxonBase>clazz, String queryString, Classification classification, MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageNumber, Integer pageSize, List<String> propertyPaths) {\r
+       \r
+               boolean doCount = false;\r
+               Query query = prepareTaxaByName(clazz, "titleCache", queryString, classification, matchMode, namedAreas, pageSize, pageNumber, doCount);\r
+               if (query != null){\r
+                       List<TaxonBase> results = query.list();\r
+                       defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+                       return results;\r
+               }\r
+               return new ArrayList<TaxonBase>();\r
+\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countMatchesByName(java.lang.String, eu.etaxonomy.cdm.persistence.query.MatchMode, boolean)\r
+        */\r
+       public int countMatchesByName(String queryString, MatchMode matchMode, boolean onlyAcccepted) {\r
+               checkNotInPriorView("TaxonDaoHibernateImpl.countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted)");\r
+               Criteria crit = getSession().createCriteria(type);\r
+               crit.add(Restrictions.ilike("titleCache", matchMode.queryStringFrom(queryString)));\r
+               crit.setProjection(Projections.rowCount());\r
+               int result = ((Integer)crit.list().get(0)).intValue();\r
+               return result;\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countMatchesByName(java.lang.String, eu.etaxonomy.cdm.persistence.query.MatchMode, boolean, java.util.List)\r
+        */\r
+       public int countMatchesByName(String queryString, MatchMode matchMode, boolean onlyAcccepted, List<Criterion> criteria) {\r
+               checkNotInPriorView("TaxonDaoHibernateImpl.countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted, List<Criterion> criteria)");\r
                Criteria crit = getSession().createCriteria(type);\r
-               crit.add(Restrictions.ilike("persistentTitleCache", matchMode.queryStringFrom(queryString)));\r
+               crit.add(Restrictions.ilike("titleCache", matchMode.queryStringFrom(queryString)));\r
+               if(criteria != null){\r
+                       for (Criterion criterion : criteria) {\r
+                               crit.add(criterion);\r
+                       }\r
+               }\r
                crit.setProjection(Projections.rowCount());\r
                int result = ((Integer)crit.list().get(0)).intValue();\r
                return result;\r
        }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, eu.etaxonomy.cdm.model.common.RelationshipBase.Direction)\r
+        */\r
+       public int countTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Direction direction) {\r
+               AuditEvent auditEvent = getAuditEventFromContext();\r
+               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+                   Query query = null;\r
+               \r
+                   if(type == null) {\r
+                           query = getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship."+direction+" = :relatedTaxon");\r
+                   } else {\r
+                           query = getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship."+direction+" = :relatedTaxon and taxonRelationship.type = :type");\r
+                           query.setParameter("type",type);\r
+                   }\r
+                   query.setParameter("relatedTaxon", taxon);\r
+               \r
+                   return ((Long)query.uniqueResult()).intValue();\r
+               } else {\r
+                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());\r
+                       query.add(AuditEntity.relatedId(direction.toString()).eq(taxon.getId()));\r
+                       query.addProjection(AuditEntity.id().count("id"));\r
+                       \r
+                       if(type != null) {\r
+                               query.add(AuditEntity.relatedId("type").eq(type.getId()));\r
+                   }\r
+                       \r
+                       return ((Long)query.getSingleResult()).intValue();\r
+               }\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countSynonyms(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType)\r
+        */\r
+       public int countSynonyms(Taxon taxon, SynonymRelationshipType type) {\r
+               AuditEvent auditEvent = getAuditEventFromContext();\r
+               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+                       Criteria criteria = getSession().createCriteria(SynonymRelationship.class);\r
+\r
+                       criteria.add(Restrictions.eq("relatedTo", taxon));\r
+                   if(type != null) {\r
+                       criteria.add(Restrictions.eq("type", type));\r
+                   } \r
+                   criteria.setProjection(Projections.rowCount());\r
+                       return (Integer)criteria.uniqueResult();\r
+               } else {\r
+                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());\r
+                       query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));\r
+                       query.addProjection(AuditEntity.id().count("id"));\r
+                       \r
+                       if(type != null) {\r
+                               query.add(AuditEntity.relatedId("type").eq(type.getId()));\r
+                   }\r
+                       \r
+                       return ((Long)query.getSingleResult()).intValue();\r
+               }\r
+       }\r
+       \r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countSynonyms(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType)\r
+        */\r
+       public int countSynonyms(Synonym synonym, SynonymRelationshipType type) {\r
+               AuditEvent auditEvent = getAuditEventFromContext();\r
+               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+                       Criteria criteria = getSession().createCriteria(SynonymRelationship.class);\r
+\r
+                       criteria.add(Restrictions.eq("relatedFrom", synonym));\r
+                   if(type != null) {\r
+                       criteria.add(Restrictions.eq("type", type));\r
+                   } \r
+                   \r
+                   criteria.setProjection(Projections.rowCount());\r
+                       return (Integer)criteria.uniqueResult();\r
+               } else {\r
+                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());\r
+                       query.add(AuditEntity.relatedId("relatedFrom").eq(synonym.getId()));\r
+                       query.addProjection(AuditEntity.id().count("id"));\r
+                       \r
+                       if(type != null) {\r
+                               query.add(AuditEntity.relatedId("type").eq(type.getId()));\r
+                   }\r
+                       \r
+                       return ((Long)query.getSingleResult()).intValue();\r
+               }\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank)\r
+        */\r
+       public int countTaxaByName(Class<? extends TaxonBase> clazz, String genusOrUninomial, String infraGenericEpithet, String specificEpithet,       String infraSpecificEpithet, Rank rank) {\r
+               checkNotInPriorView("TaxonDaoHibernateImpl.countTaxaByName(Boolean accepted, String genusOrUninomial,   String infraGenericEpithet, String specificEpithet,     String infraSpecificEpithet, Rank rank)");\r
+        Criteria criteria = null;\r
+               \r
+               if(clazz == null) {\r
+                       criteria = getSession().createCriteria(TaxonBase.class);\r
+               } else {\r
+                       criteria = getSession().createCriteria(clazz);          \r
+               }\r
+               \r
+               criteria.setFetchMode( "name", FetchMode.JOIN );\r
+               criteria.createAlias("name", "name");\r
+               \r
+               if(genusOrUninomial == null) {\r
+                       criteria.add(Restrictions.isNull("name.genusOrUninomial"));\r
+               } else if(!genusOrUninomial.equals("*")) {\r
+                       criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));\r
+               }\r
+               \r
+               if(infraGenericEpithet == null) {\r
+                       criteria.add(Restrictions.isNull("name.infraGenericEpithet"));\r
+               } else if(!infraGenericEpithet.equals("*")) {\r
+                       criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));\r
+               } \r
+               \r
+               if(specificEpithet == null) {\r
+                       criteria.add(Restrictions.isNull("name.specificEpithet"));\r
+               } else if(!specificEpithet.equals("*")) {\r
+                       criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));\r
+                       \r
+               }\r
+               \r
+               if(infraSpecificEpithet == null) {\r
+                       criteria.add(Restrictions.isNull("name.infraSpecificEpithet"));\r
+               } else if(!infraSpecificEpithet.equals("*")) {\r
+                       criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));\r
+               }\r
+\r
+               if(rank != null) {\r
+                       criteria.add(Restrictions.eq("name.rank", rank));\r
+               }\r
+               \r
+               criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));\r
+       \r
+               return (Integer)criteria.uniqueResult();\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#findTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)\r
+        */\r
+       public List<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, Rank rank, Integer pageSize,  Integer pageNumber) {\r
+               checkNotInPriorView("TaxonDaoHibernateImpl.findTaxaByName(Boolean accepted, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, Rank rank, Integer pageSize,      Integer pageNumber)");\r
+               Criteria criteria = null;\r
+               \r
+               if(clazz == null) {\r
+                       criteria = getSession().createCriteria(TaxonBase.class);\r
+               } else {\r
+                       criteria = getSession().createCriteria(clazz);\r
+               }\r
+               \r
+               criteria.setFetchMode( "name", FetchMode.JOIN );\r
+               criteria.createAlias("name", "name");\r
+               \r
+               if(genusOrUninomial == null) {\r
+                       criteria.add(Restrictions.isNull("name.genusOrUninomial"));\r
+               } else if(!genusOrUninomial.equals("*")) {\r
+                       criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));\r
+               }\r
+               \r
+               if(infraGenericEpithet == null) {\r
+                       criteria.add(Restrictions.isNull("name.infraGenericEpithet"));\r
+               } else if(!infraGenericEpithet.equals("*")) {\r
+                       criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));\r
+               } \r
+               \r
+               if(specificEpithet == null) {\r
+                       criteria.add(Restrictions.isNull("name.specificEpithet"));\r
+               } else if(!specificEpithet.equals("*")) {\r
+                       criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));\r
+                       \r
+               }\r
+               \r
+               if(infraSpecificEpithet == null) {\r
+                       criteria.add(Restrictions.isNull("name.infraSpecificEpithet"));\r
+               } else if(!infraSpecificEpithet.equals("*")) {\r
+                       criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));\r
+               }\r
+               \r
+               if(rank != null) {\r
+                       criteria.add(Restrictions.eq("name.rank", rank));\r
+               }\r
+               \r
+               if(pageSize != null) {\r
+               criteria.setMaxResults(pageSize);\r
+                   if(pageNumber != null) {\r
+                       criteria.setFirstResult(pageNumber * pageSize);\r
+                   } else {\r
+                       criteria.setFirstResult(0);\r
+                   }\r
+               }\r
+       \r
+               return (List<TaxonBase>)criteria.list();\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List, eu.etaxonomy.cdm.model.common.RelationshipBase.Direction)\r
+        */\r
+       public List<TaxonRelationship> getTaxonRelationships(Taxon taxon,       TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths, Direction direction) {\r
+               AuditEvent auditEvent = getAuditEventFromContext();\r
+               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+                       Criteria criteria = getSession().createCriteria(TaxonRelationship.class);\r
+            \r
+                       criteria.add(Restrictions.eq("relatedTo", taxon));\r
+                   if(type != null) {\r
+                       criteria.add(Restrictions.eq("type", type));\r
+                   } \r
+               \r
+            addOrder(criteria,orderHints);\r
+               \r
+                   if(pageSize != null) {\r
+                       criteria.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                               criteria.setFirstResult(pageNumber * pageSize);\r
+                       } else {\r
+                               criteria.setFirstResult(0);\r
+                       }\r
+                   }\r
+               \r
+                   List<TaxonRelationship> result = (List<TaxonRelationship>)criteria.list();\r
+                   defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                   \r
+                   return result;\r
+               } else {\r
+                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());\r
+                       query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));\r
+                       \r
+                       if(type != null) {\r
+                               query.add(AuditEntity.relatedId("type").eq(type.getId()));\r
+                   }\r
+                       \r
+                       if(pageSize != null) {\r
+                       query.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                           query.setFirstResult(pageNumber * pageSize);\r
+                       } else {\r
+                           query.setFirstResult(0);\r
+                       }\r
+                   }\r
+                       \r
+                       List<TaxonRelationship> result = (List<TaxonRelationship>)query.getResultList();\r
+                       defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                       \r
+                       // Ugly, but for now, there is no way to sort on a related entity property in Envers,\r
+                       // and we can't live without this functionality in CATE as it screws up the whole \r
+                       // taxon tree thing\r
+                       if(orderHints != null && !orderHints.isEmpty()) {\r
+                           SortedSet<TaxonRelationship> sortedList = new TreeSet<TaxonRelationship>(new TaxonRelationshipFromTaxonComparator());\r
+                           sortedList.addAll(result);\r
+                           return new ArrayList<TaxonRelationship>(sortedList);\r
+                       }\r
+                       \r
+                       return result;\r
+               }\r
+       }\r
+       \r
+       class TaxonRelationshipFromTaxonComparator implements Comparator<TaxonRelationship> {\r
+\r
+               public int compare(TaxonRelationship o1, TaxonRelationship o2) {\r
+                       return o1.getFromTaxon().getTitleCache().compareTo(o2.getFromTaxon().getTitleCache());\r
+               }\r
+               \r
+       }\r
+       \r
+       class SynonymRelationshipFromTaxonComparator implements Comparator<SynonymRelationship> {\r
+\r
+               public int compare(SynonymRelationship o1, SynonymRelationship o2) {\r
+                       return o1.getSynonym().getTitleCache().compareTo(o2.getSynonym().getTitleCache());\r
+               }\r
+               \r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getSynonyms(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
+        */\r
+       public List<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+               AuditEvent auditEvent = getAuditEventFromContext();\r
+               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);\r
+            \r
+                       criteria.add(Restrictions.eq("relatedTo", taxon));\r
+                   if(type != null) {\r
+                       criteria.add(Restrictions.eq("type", type));\r
+                   } \r
+               \r
+            addOrder(criteria,orderHints);\r
+               \r
+                   if(pageSize != null) {\r
+                       criteria.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                               criteria.setFirstResult(pageNumber * pageSize);\r
+                       } else {\r
+                               criteria.setFirstResult(0);\r
+                       }\r
+                   }\r
+               \r
+                   List<SynonymRelationship> result = (List<SynonymRelationship>)criteria.list();\r
+                   defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                   \r
+                   return result;\r
+               } else {\r
+                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());\r
+                       query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));\r
+                       \r
+                       if(type != null) {\r
+                               query.add(AuditEntity.relatedId("type").eq(type.getId()));\r
+                   }\r
+                       \r
+                       if(pageSize != null) {\r
+                       query.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                           query.setFirstResult(pageNumber * pageSize);\r
+                       } else {\r
+                           query.setFirstResult(0);\r
+                       }\r
+                   }\r
+                       \r
+                       List<SynonymRelationship> result = (List<SynonymRelationship>)query.getResultList();\r
+                       defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                       \r
+                       return result;\r
+               }\r
+       }\r
+       \r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getSynonyms(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
+        */\r
+       public List<SynonymRelationship> getSynonyms(Synonym synonym, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+               AuditEvent auditEvent = getAuditEventFromContext();\r
+               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);\r
+            \r
+                       criteria.add(Restrictions.eq("relatedFrom", synonym));\r
+                   if(type != null) {\r
+                       criteria.add(Restrictions.eq("type", type));\r
+                   } \r
+               \r
+            addOrder(criteria,orderHints);\r
+               \r
+                   if(pageSize != null) {\r
+                       criteria.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                               criteria.setFirstResult(pageNumber * pageSize);\r
+                       } else {\r
+                               criteria.setFirstResult(0);\r
+                       }\r
+                   }\r
+               \r
+                   List<SynonymRelationship> result = (List<SynonymRelationship>)criteria.list();\r
+                   defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                   \r
+                   return result;\r
+               } else {\r
+                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());\r
+                       query.add(AuditEntity.relatedId("relatedFrom").eq(synonym.getId()));\r
+                       \r
+                       if(type != null) {\r
+                               query.add(AuditEntity.relatedId("type").eq(type.getId()));\r
+                   }\r
+                       \r
+                       if(pageSize != null) {\r
+                       query.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                           query.setFirstResult(pageNumber * pageSize);\r
+                       } else {\r
+                           query.setFirstResult(0);\r
+                       }\r
+                   }\r
+                       \r
+                       List<SynonymRelationship> result = (List<SynonymRelationship>)query.getResultList();\r
+                       defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                       \r
+                       return result;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void rebuildIndex() {\r
+               FullTextSession fullTextSession = Search.getFullTextSession(getSession());\r
+               \r
+               for(TaxonBase taxonBase : list(null,null)) { // re-index all taxon base\r
+                       Hibernate.initialize(taxonBase.getName());\r
+                       fullTextSession.index(taxonBase);\r
+               }\r
+               fullTextSession.flushToIndexes();\r
+       }\r
+       \r
+       @Override\r
+       public String suggestQuery(String queryString) {\r
+               checkNotInPriorView("TaxonDaoHibernateImpl.suggestQuery(String queryString)");\r
+               String alternativeQueryString = null;\r
+               if (alternativeSpellingSuggestionParser != null) {\r
+                       try {\r
+\r
+                               alternativeSpellingSuggestionParser.parse(queryString);\r
+                               org.apache.lucene.search.Query alternativeQuery = alternativeSpellingSuggestionParser.suggest(queryString);\r
+                               if (alternativeQuery != null) {\r
+                                       alternativeQueryString = alternativeQuery\r
+                                                       .toString("name.titleCache");\r
+                               }\r
+\r
+                       } catch (ParseException e) {\r
+                               throw new QueryParseException(e, queryString);\r
+                       }\r
+               }\r
+               return alternativeQueryString;\r
+       }\r
+       \r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheOfAcceptedTaxa(eu.etaxonomy.cdm.model.taxon.Classification)\r
+        */\r
+       public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification) {\r
+\r
+               int classificationId = classification.getId();\r
+               \r
+               String queryString = "SELECT nodes.uuid, taxa.titleCache FROM TaxonNode AS nodes LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id WHERE taxa.DTYPE = 'Taxon' AND nodes.classification_id = " + classificationId;\r
+               \r
+               List<Object[]> result = getSession().createSQLQuery(queryString).list();\r
+                               \r
+               if(result.size() == 0){\r
+                       return null;\r
+               }else{\r
+                       List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<UuidAndTitleCache<TaxonNode>>(result.size()); \r
+                       \r
+                       for (Object object : result){\r
+                               \r
+                               Object[] objectArray = (Object[]) object;\r
+                               \r
+                               UUID uuid = UUID.fromString((String) objectArray[0]);\r
+                               String titleCache = (String) objectArray[1];\r
+                               \r
+                               list.add(new UuidAndTitleCache(TaxonNode.class, uuid, titleCache));\r
+                       }\r
+                       \r
+                       return list;    \r
+               }\r
+       }\r
+       \r
+       \r
+       public class UuidAndTitleCacheOfAcceptedTaxon{\r
+               UUID uuid;\r
+               \r
+               String titleCache;\r
+\r
+               public UuidAndTitleCacheOfAcceptedTaxon(UUID uuid, String titleCache){\r
+                       this.uuid = uuid;\r
+                       this.titleCache = titleCache;\r
+               }\r
+               \r
+               public UUID getUuid() {\r
+                       return uuid;\r
+               }\r
+\r
+               public void setUuid(UUID uuid) {\r
+                       this.uuid = uuid;\r
+               }\r
+\r
+               public String getTitleCache() {\r
+                       return titleCache;\r
+               }\r
+\r
+               public void setTitleCache(String titleCache) {\r
+                       this.titleCache = titleCache;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public TaxonBase find(LSID lsid) {\r
+               TaxonBase taxonBase = super.find(lsid);\r
+               if(taxonBase != null) {\r
+                       List<String> propertyPaths = new ArrayList<String>();\r
+                       propertyPaths.add("createdBy");\r
+                       propertyPaths.add("updatedBy");\r
+                       propertyPaths.add("name");\r
+                       propertyPaths.add("sec");\r
+                       propertyPaths.add("relationsToThisTaxon");\r
+                       propertyPaths.add("relationsToThisTaxon.fromTaxon");\r
+                       propertyPaths.add("relationsToThisTaxon.toTaxon");\r
+                       propertyPaths.add("relationsFromThisTaxon");\r
+                       propertyPaths.add("relationsFromThisTaxon.toTaxon");                    \r
+                       propertyPaths.add("relationsToThisTaxon.type");\r
+                       propertyPaths.add("synonymRelations");\r
+                       propertyPaths.add("synonymRelations.synonym");\r
+                       propertyPaths.add("synonymRelations.type");\r
+                       propertyPaths.add("descriptions");\r
+                       \r
+                       defaultBeanInitializer.initialize(taxonBase, propertyPaths);\r
+               }\r
+               return taxonBase;\r
+       }\r
+\r
+       public List<TaxonBase> getTaxaByCommonName(String queryString,\r
+                       Classification classification, MatchMode matchMode,\r
+                       Set<NamedArea> namedAreas, Integer pageSize, Integer pageNumber) {\r
+               // TODO Auto-generated method stub\r
+               return null;\r
+       }\r
+       \r
+       \r
+       public List<Synonym>  createAllInferredSynonyms(Taxon taxon, Classification tree){\r
+               List <Synonym> inferredSynonyms = new ArrayList<Synonym>();\r
+               \r
+               inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_EPITHET_OF()));\r
+               inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_GENUS_OF()));\r
+               inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.POTENTIAL_COMBINATION_OF()));\r
+               \r
+               return inferredSynonyms;\r
+       }\r
+       \r
+\r
+       /**\r
+        * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.\r
+        * Very likely only useful for createInferredSynonyms().\r
+        * @param uuid\r
+        * @param zooHashMap\r
+        * @return\r
+        */\r
+       private ZoologicalName getZoologicalName(UUID uuid, HashMap <UUID, ZoologicalName> zooHashMap) {\r
+               ZoologicalName taxonName = this.taxonNameDao.findZoologicalNameByUUID(uuid);\r
+               if (taxonName == null) {\r
+                       taxonName = zooHashMap.get(uuid);\r
+               }\r
+               return taxonName;\r
+       }\r
+\r
+       public List<Synonym> createInferredSynonyms(Taxon taxon, Classification tree, SynonymRelationshipType type){\r
+               List <Synonym> inferredSynonyms = new ArrayList<Synonym>();\r
+               List<Synonym> inferredSynonymsToBeRemoved = new ArrayList<Synonym>();\r
+\r
+               HashMap <UUID, ZoologicalName> zooHashMap = new HashMap<UUID, ZoologicalName>();\r
+               UUID uuid;\r
+               \r
+               uuid= taxon.getName().getUuid();\r
+               ZoologicalName taxonName = getZoologicalName(uuid, zooHashMap);\r
+               String epithetOfTaxon = taxonName.getSpecificEpithet();\r
+               String genusOfTaxon = taxonName.getGenusOrUninomial();\r
+               Set<TaxonNode> nodes = taxon.getTaxonNodes();\r
+               List<String> taxonNames = new ArrayList<String>();\r
+               \r
+               for (TaxonNode node: nodes){\r
+                       HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName\r
+                       List<String> synonymsEpithet = new ArrayList<String>();\r
+                       \r
+                       if (node.getClassification().equals(tree)){\r
+                               if (!node.isTopmostNode()){\r
+                               TaxonNode parent = (TaxonNode)node.getParent();\r
+                               parent = (TaxonNode)HibernateProxyHelper.deproxy(parent);\r
+                               TaxonNameBase parentName = parent.getTaxon().getName();\r
+                               parentName = (TaxonNameBase)HibernateProxyHelper.deproxy(parentName);\r
+                               \r
+                               //create inferred synonyms for species, subspecies or subgenus\r
+                               if (parentName.isGenus() || parentName.isSpecies() || parentName.getRank().equals(Rank.SUBGENUS())){\r
+                                       \r
+                                       Synonym inferredEpithet;\r
+                                       Synonym inferredGenus = null;\r
+                                       Synonym potentialCombination;\r
+                                       \r
+                                       List<String> propertyPaths = new ArrayList<String>();\r
+                                       propertyPaths.add("synonym");\r
+                                       propertyPaths.add("synonym.name");\r
+                                       List<OrderHint> orderHints = new ArrayList<OrderHint>();\r
+                                       orderHints.add(new OrderHint("relatedFrom.titleCache", SortOrder.ASCENDING));\r
+                               \r
+                                       List<SynonymRelationship> synonymRelationshipsOfGenus = getSynonyms(parent.getTaxon(), SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);\r
+                                       List<SynonymRelationship> synonymRelationshipsOfTaxon= getSynonyms(taxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);                                                                       \r
+                                       \r
+                                       if (type.equals(SynonymRelationshipType.INFERRED_EPITHET_OF())){\r
+                                                                                               \r
+                                               for (SynonymRelationship synonymRelationOfGenus:synonymRelationshipsOfGenus){\r
+                                                       TaxonNameBase synName;\r
+                                                       ZoologicalName inferredSynName;\r
+                                                       Synonym syn = synonymRelationOfGenus.getSynonym();\r
+                                                       HibernateProxyHelper.deproxy(syn);\r
+                                                       \r
+                                                       // Determine the idInSource\r
+                                                       String idInSource = getIdInSource(syn);\r
+                                                       \r
+                                                       // Determine the sourceReference\r
+                                                       Reference sourceReference = syn.getSec();\r
+                                                       \r
+                                                       synName = syn.getName();\r
+                                                       ZoologicalName zooName = getZoologicalName(synName.getUuid(), zooHashMap);\r
+                                                       String synGenusName = zooName.getGenusOrUninomial();\r
+                                                       if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){\r
+                                                               synonymsGenus.put(synGenusName, idInSource);\r
+                                                       }\r
+                                                       inferredSynName = ZoologicalName.NewInstance(Rank.SPECIES());\r
+                                                       \r
+                                                       // DEBUG\r
+                                                       if (epithetOfTaxon == null) {\r
+                                                               logger.error("This specificEpithet is NULL");\r
+                                                       }\r
+                                                       \r
+                                                       inferredSynName.setSpecificEpithet(epithetOfTaxon);\r
+                                                       inferredSynName.setGenusOrUninomial(synGenusName);\r
+                                                       inferredEpithet = Synonym.NewInstance(inferredSynName, null);\r
+                                                       \r
+                                                       // Set the sourceReference\r
+                                                       inferredEpithet.setSec(sourceReference);\r
+\r
+                                                       // Add the original source\r
+                                                       if (idInSource != null) {\r
+                                                               IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);\r
+                                                               \r
+                                                               // Add the citation\r
+                                                               Reference citation = getCitation(syn);\r
+                                                               if (citation != null) {\r
+                                                                       originalSource.setCitation(citation);\r
+                                                                       inferredEpithet.addSource(originalSource);\r
+                                                               }\r
+                                                       }\r
+                                                       \r
+                                                       taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_GENUS_OF());\r
+                                                       inferredSynonyms.add(inferredEpithet);\r
+                                                       inferredSynName.generateTitle();\r
+                                                       zooHashMap.put(inferredSynName.getUuid(), inferredSynName);\r
+                                                       taxonNames.add(inferredSynName.getNameCache());\r
+                                               }\r
+                                               \r
+                                               if (!taxonNames.isEmpty()){\r
+                                               List<String> synNotInCDM = this.taxaByNameNotInDB(taxonNames);\r
+                                               ZoologicalName name;\r
+                                               if (!synNotInCDM.isEmpty()){\r
+                                                       inferredSynonymsToBeRemoved.clear();\r
+                                                       \r
+                                                       for (Synonym syn :inferredSynonyms){\r
+                                                               name = getZoologicalName(syn.getName().getUuid(), zooHashMap);\r
+                                                               if (!synNotInCDM.contains(name.getNameCache())){\r
+                                                                       inferredSynonymsToBeRemoved.add(syn);\r
+                                                               }\r
+                                                       }\r
+                                                       \r
+                                                       // Remove identified Synonyms from inferredSynonyms\r
+                                                       for (Synonym synonym : inferredSynonymsToBeRemoved) {\r
+                                                               inferredSynonyms.remove(synonym);\r
+                                                       }\r
+                                               }\r
+                                               }\r
+                                               \r
+                                       }else if (type.equals(SynonymRelationshipType.INFERRED_GENUS_OF())){\r
+                                               \r
+                                               \r
+                                               for (SynonymRelationship synonymRelationOfTaxon:synonymRelationshipsOfTaxon){\r
+                                                       TaxonNameBase synName;\r
+                                                       ZoologicalName inferredSynName;\r
+                                                       \r
+                                                       Synonym syn = synonymRelationOfTaxon.getSynonym();\r
+                                                       synName =syn.getName();\r
+                                                       HibernateProxyHelper.deproxy(syn);\r
+                                                       \r
+                                                       // Determine the idInSource\r
+                                                       String idInSource = getIdInSource(syn);\r
+                                                       \r
+                                                       // Determine the sourceReference\r
+                                                       Reference sourceReference = syn.getSec();\r
+\r
+                                                       synName = syn.getName();\r
+                                                       ZoologicalName zooName = getZoologicalName(synName.getUuid(), zooHashMap);\r
+                                                       String speciesEpithetName = zooName.getSpecificEpithet();\r
+                                                       if (synonymsEpithet != null && !synonymsEpithet.contains(speciesEpithetName)){\r
+                                                               synonymsEpithet.add(speciesEpithetName);\r
+                                                       }\r
+                                                       inferredSynName = ZoologicalName.NewInstance(Rank.SPECIES());\r
+                                                       inferredSynName.setSpecificEpithet(speciesEpithetName);\r
+                                                       inferredSynName.setGenusOrUninomial(genusOfTaxon);\r
+                                                       inferredGenus = Synonym.NewInstance(inferredSynName, null);\r
+                                                       \r
+                                                       // Set the sourceReference\r
+                                                       inferredGenus.setSec(sourceReference);\r
+                                                       \r
+                                                       // Add the original source\r
+                                                       if (idInSource != null) {\r
+                                                               IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredGenusOf", syn.getSec(), null);\r
+                                                               \r
+                                                               // Add the citation\r
+                                                               Reference citation = getCitation(syn);\r
+                                                               if (citation != null) {\r
+                                                                       originalSource.setCitation(citation);\r
+                                                                       inferredGenus.addSource(originalSource);\r
+                                                               }\r
+                                                       }\r
+\r
+                                                       taxon.addSynonym(inferredGenus, SynonymRelationshipType.INFERRED_EPITHET_OF());\r
+                                                       inferredSynonyms.add(inferredGenus);\r
+                                                       inferredSynName.generateTitle();\r
+                                                       zooHashMap.put(inferredSynName.getUuid(), inferredSynName);\r
+                                                       taxonNames.add(inferredSynName.getNameCache());\r
+                                               }\r
+                                               \r
+                                               if (!taxonNames.isEmpty()){\r
+                                                       List<String> synNotInCDM = this.taxaByNameNotInDB(taxonNames);\r
+                                                       ZoologicalName name;\r
+                                                       if (!synNotInCDM.isEmpty()){\r
+                                                               inferredSynonymsToBeRemoved.clear();\r
+                                                               \r
+                                                               for (Synonym syn :inferredSynonyms){\r
+                                                                       name = getZoologicalName(syn.getName().getUuid(), zooHashMap);\r
+                                                                       if (!synNotInCDM.contains(name.getNameCache())){\r
+                                                                               inferredSynonymsToBeRemoved.add(syn);\r
+                                                                       }\r
+                                                               }\r
+                                                               \r
+                                                               // Remove identified Synonyms from inferredSynonyms\r
+                                                               for (Synonym synonym : inferredSynonymsToBeRemoved) {\r
+                                                                       inferredSynonyms.remove(synonym);\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                               \r
+                                       }else if (type.equals(SynonymRelationshipType.POTENTIAL_COMBINATION_OF())){\r
+                                               \r
+                                               Reference sourceReference = null; // TODO: Determination of sourceReference is redundant\r
+                                               \r
+                                               for (SynonymRelationship synonymRelationOfGenus:synonymRelationshipsOfGenus){\r
+                                                       TaxonNameBase synName;\r
+                                                       Synonym syn = synonymRelationOfGenus.getSynonym();\r
+                                                       synName =syn.getName();\r
+                                                       \r
+                                                       HibernateProxyHelper.deproxy(syn);\r
+                                                       \r
+                                                       // Set the sourceReference\r
+                                                       sourceReference = syn.getSec();\r
+\r
+                                                       // Determine the idInSource\r
+                                                       String idInSource = getIdInSource(syn);\r
+\r
+                                                       ZoologicalName zooName = getZoologicalName(synName.getUuid(), zooHashMap);\r
+                                                       String synGenusName = zooName.getGenusOrUninomial();\r
+                                                       if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){\r
+                                                               synonymsGenus.put(synGenusName, idInSource);\r
+                                                       }\r
+                                               }\r
+                                               \r
+                                               ZoologicalName inferredSynName;\r
+                                               for (SynonymRelationship synonymRelationOfTaxon:synonymRelationshipsOfTaxon){\r
+                                                       \r
+                                                       Synonym syn = synonymRelationOfTaxon.getSynonym();\r
+                                                       HibernateProxyHelper.deproxy(syn);\r
+                                                       \r
+                                                       // Set sourceReference\r
+                                                       sourceReference = syn.getSec();\r
+                                                       \r
+                                                       ZoologicalName zooName = getZoologicalName(syn.getName().getUuid(), zooHashMap);\r
+                                                       String epithetName = zooName.getSpecificEpithet();\r
+                                                       if (epithetName != null && !synonymsEpithet.contains(epithetName)){\r
+                                                               synonymsEpithet.add(epithetName);\r
+                                                       }\r
+                                               }\r
+                                               for (String epithetName:synonymsEpithet){\r
+                                                       for (String genusName: synonymsGenus.keySet()){\r
+                                                               inferredSynName = ZoologicalName.NewInstance(Rank.SPECIES());\r
+                                                               inferredSynName.setSpecificEpithet(epithetName);\r
+                                                               inferredSynName.setGenusOrUninomial(genusName);\r
+                                                               potentialCombination = Synonym.NewInstance(inferredSynName, null);\r
+                                                               \r
+                                                               // Set the sourceReference\r
+                                                               potentialCombination.setSec(sourceReference);\r
+                                                               \r
+                                                               // Add the original source\r
+                                                               String idInSource = synonymsGenus.get(genusName);\r
+                                                               if (idInSource != null) {\r
+                                                                       IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "PotentialCombinationOf", sourceReference, null);\r
+                                                                       \r
+                                                                       // Add the citation\r
+                                                                       if (sourceReference != null) {\r
+                                                                               originalSource.setCitation(sourceReference);\r
+                                                                               potentialCombination.addSource(originalSource);\r
+                                                                       }\r
+                                                               }\r
+\r
+                                                               inferredSynonyms.add(potentialCombination);\r
+                                                               inferredSynName.generateTitle();\r
+                                                               zooHashMap.put(inferredSynName.getUuid(), inferredSynName);\r
+                                                               taxonNames.add(inferredSynName.getNameCache());\r
+                                                       }\r
+                                                       \r
+                                                       if (!taxonNames.isEmpty()){\r
+                                                               List<String> synNotInCDM = this.taxaByNameNotInDB(taxonNames);\r
+                                                               ZoologicalName name;\r
+                                                               if (!synNotInCDM.isEmpty()){\r
+                                                                       inferredSynonymsToBeRemoved.clear();\r
+                                                                       \r
+                                                                       for (Synonym syn :inferredSynonyms){\r
+                                                                               try{\r
+                                                                                       name = (ZoologicalName) syn.getName();\r
+                                                                               }catch (ClassCastException e){\r
+                                                                                       name = getZoologicalName(syn.getName().getUuid(), zooHashMap);\r
+                                                                               }\r
+                                                                               if (!synNotInCDM.contains(name.getNameCache())){\r
+                                                                                       inferredSynonymsToBeRemoved.add(syn);\r
+                                                                               }\r
+                                                                       }\r
+                                                                       \r
+                                                                       // Remove identified Synonyms from inferredSynonyms\r
+                                                                       for (Synonym synonym : inferredSynonymsToBeRemoved) {\r
+                                                                               inferredSynonyms.remove(synonym);\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }else {\r
+                                               logger.info("The synonymrelationship type is not defined.");\r
+                                               return null;\r
+                                       }\r
+                               }\r
+                       }\r
+                       }\r
+                       }\r
+                       \r
+               \r
+               return inferredSynonyms;\r
+       }\r
+\r
+\r
+       /**\r
+        * Returns the idInSource for a given Synonym.\r
+        * @param syn\r
+        */\r
+       private String getIdInSource(Synonym syn) {\r
+               String idInSource = null;\r
+               Set<IdentifiableSource> sources = syn.getSources();\r
+               if (sources.size() == 1) {\r
+                       IdentifiableSource source = sources.iterator().next();\r
+                       if (source != null) {\r
+                               idInSource  = source.getIdInSource();\r
+                       }\r
+               } else if (sources.size() > 1) {\r
+                       int count = 1;\r
+                       idInSource = "";\r
+                       for (IdentifiableSource source : sources) {\r
+                               idInSource += source.getIdInSource();\r
+                               if (count < sources.size()) {\r
+                                       idInSource += "; ";\r
+                               }\r
+                               count++;\r
+                       }\r
+               }\r
+               \r
+               return idInSource;\r
+       }\r
+       \r
+       /**\r
+        * Returns the citation for a given Synonym.\r
+        * @param syn\r
+        */\r
+       private Reference getCitation(Synonym syn) {\r
+               Reference citation = null;\r
+               Set<IdentifiableSource> sources = syn.getSources();\r
+               if (sources.size() == 1) {\r
+                       IdentifiableSource source = sources.iterator().next();\r
+                       if (source != null) {\r
+                               citation = source.getCitation();\r
+                       }\r
+               } else if (sources.size() > 1) {\r
+                       logger.warn("This Synonym has more than one source: " + syn.getUuid() + " (" + syn.getTitleCache() +")");\r
+               }\r
+               \r
+               return citation;\r
+       }\r
+       \r
+/*     private void xxx(List<SynonymRelationship> synonymRelationships, HashMap <UUID, ZoologicalName> zooHashMap, SynonymRelationshipType type, String addString){\r
+               \r
+               for (SynonymRelationship synonymRelation:synonymRelationships){\r
+                       TaxonNameBase synName;\r
+                       NonViralName inferredSynName;\r
+                       Synonym syn = synonymRelation.getSynonym();\r
+                       HibernateProxyHelper.deproxy(syn);\r
+                       \r
+                       synName = syn.getName();\r
+                       ZoologicalName zooName = zooHashMap.get(synName.getUuid());\r
+                       String synGenusName = zooName.getGenusOrUninomial();\r
+                       \r
+                       switch(type.getId()){\r
+                       case SynonymRelationshipType.INFERRED_EPITHET_OF().getId():\r
+                               inferredSynName.setSpecificEpithet(addString);\r
+                               break;\r
+                       case SynonymRelationshipType.INFERRED_GENUS_OF().getId():\r
+                               break;\r
+                       case SynonymRelationshipType.POTENTIAL_COMBINATION_OF().getId():\r
+                               break;\r
+                       default:\r
+                       }\r
+                       if (!synonymsGenus.contains(synGenusName)){\r
+                               synonymsGenus.add(synGenusName);\r
+                       }\r
+                       inferredSynName = NonViralName.NewInstance(Rank.SPECIES());\r
+                       inferredSynName.setSpecificEpithet(epithetOfTaxon);\r
+                       inferredSynName.setGenusOrUninomial(synGenusName);\r
+                       inferredEpithet = Synonym.NewInstance(inferredSynName, null);\r
+                       taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_GENUS_OF());\r
+                       inferredSynonyms.add(inferredEpithet);\r
+                       inferredSynName.generateTitle();\r
+                       taxonNames.add(inferredSynName.getNameCache());\r
+               }\r
+                       \r
+               \r
+               if (!taxonNames.isEmpty()){\r
+               List<String> synNotInCDM = this.taxaByNameNotInDB(taxonNames);\r
+               ZoologicalName name;\r
+               if (!synNotInCDM.isEmpty()){\r
+                       for (Synonym syn :inferredSynonyms){\r
+                               name =zooHashMap.get(syn.getName().getUuid());\r
+                               if (!synNotInCDM.contains(name.getNameCache())){\r
+                                       inferredSynonyms.remove(syn);\r
+                               }\r
+                       }\r
+               }\r
+               }\r
+       }*/\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countAllRelationships()\r
+        */\r
+       public int countAllRelationships() {\r
+               List<RelationshipBase> relationships = this.getAllRelationships(null, 0);\r
+               return relationships.size();\r
+       }\r
+       \r
+       \r
+       public List<String> taxaByNameNotInDB(List<String> taxonNames){\r
+               List<TaxonBase> notInDB = new ArrayList<TaxonBase>();\r
+               //get all taxa, already in db\r
+               Query query = getSession().createQuery("from TaxonNameBase t where t.nameCache IN (:taxonList)");\r
+               query.setParameterList("taxonList", taxonNames);\r
+               List<TaxonNameBase> taxaInDB = query.list();\r
+               //compare the original list with the result of the query\r
+               for (TaxonNameBase taxonName: taxaInDB){\r
+                       if (taxonName.isInstanceOf(NonViralName.class)) {\r
+                               NonViralName nonViralName = CdmBase.deproxy(taxonName, NonViralName.class);\r
+                               String nameCache = nonViralName.getNameCache();\r
+                               if (taxonNames.contains(nameCache)){\r
+                                       taxonNames.remove(nameCache);\r
+                               }\r
+                       }\r
+               }\r
+                               \r
+               return taxonNames;\r
+       }\r
+\r
+       //TODO: mal nur mit UUID probieren (ohne fetch all properties), vielleicht geht das schneller?\r
+       public List<UUID> findIdenticalTaxonNameIds(List<String> propertyPaths){\r
+               Query query=getSession().createQuery("select tmb2 from ZoologicalName tmb, ZoologicalName tmb2 fetch all properties where tmb.id != tmb2.id and tmb.nameCache = tmb2.nameCache");\r
+               List<UUID> zooNames = query.list();\r
+                                                               \r
+               return zooNames;\r
+               \r
+       }\r
+       \r
+       public List<TaxonNameBase> findIdenticalTaxonNames(List<String> propertyPaths) {\r
+               \r
+               Query query=getSession().createQuery("select tmb2 from ZoologicalName tmb, ZoologicalName tmb2 fetch all properties where tmb.id != tmb2.id and tmb.nameCache = tmb2.nameCache");\r
+               \r
+               List<TaxonNameBase> zooNames = query.list();\r
+               \r
+               TaxonNameComparator taxComp = new TaxonNameComparator();\r
+               Collections.sort(zooNames, taxComp);\r
+               \r
+               for (TaxonNameBase taxonNameBase: zooNames){\r
+                       defaultBeanInitializer.initialize(taxonNameBase, propertyPaths);\r
+               }\r
+               \r
+               return zooNames;\r
+       }\r
+       \r
+       public List<TaxonNameBase> findIdenticalNamesNew(List<String> propertyPaths){\r
+               \r
+               //Hole die beiden Source_ids von "Fauna Europaea" und "Erms" und in sources der names darf jeweils nur das entgegengesetzte auftreten (i member of tmb.taxonBases)\r
+               Query query = getSession().createQuery("Select id from Reference where titleCache like 'Fauna Europaea database'");\r
+               List<String> secRefFauna = query.list();\r
+               query = getSession().createQuery("Select id from Reference where titleCache like 'ERMS'");\r
+               List<String> secRefErms = query.list();\r
+               //Query query = getSession().createQuery("select tmb2.nameCache from ZoologicalName tmb, TaxonBase tb1, ZoologicalName tmb2, TaxonBase tb2 where tmb.id != tmb2.id and tb1.name = tmb and tb2.name = tmb2 and tmb.nameCache = tmb2.nameCache and tb1.sec != tb2.sec");\r
+               //Get all names of fauna europaea\r
+               query = getSession().createQuery("select zn.nameCache from ZoologicalName zn, TaxonBase tb where tb.name = zn and tb.sec.id = :secRefFauna");\r
+               query.setParameter("secRefFauna", secRefFauna.get(0));\r
+               List<String> namesFauna= query.list();\r
+               \r
+               //Get all names of erms\r
+               \r
+               query = getSession().createQuery("select zn.nameCache from ZoologicalName zn, TaxonBase tb where tb.name = zn and tb.sec.id = :secRefErms");\r
+               query.setParameter("secRefErms", secRefErms.get(0));\r
+               \r
+               List<String> namesErms = query.list();\r
+               /*TaxonNameComparator comp = new TaxonNameComparator();\r
+               Collections.sort(namesFauna);\r
+               Collections.sort(namesErms);\r
+               */\r
+               List <String> identicalNames = new ArrayList<String>();\r
+               String predecessor = "";\r
+               \r
+               for (String nameFauna: namesFauna){\r
+                       if (namesErms.contains(nameFauna)){\r
+                               identicalNames.add(nameFauna);\r
+                       }\r
+               }\r
+               \r
+               \r
+               query = getSession().createQuery("from ZoologicalName zn where zn.nameCache IN (:identicalNames)");\r
+               query.setParameterList("identicalNames", identicalNames);\r
+               List<TaxonNameBase> result = query.list();\r
+               TaxonNameBase temp = result.get(0);\r
+               \r
+               Iterator<OriginalSourceBase> sources = temp.getSources().iterator();\r
+                               \r
+               TaxonNameComparator taxComp = new TaxonNameComparator();\r
+               Collections.sort(result, taxComp);\r
+               defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+               return result;\r
+               \r
+               }\r
+       \r
+       \r
+       \r
+       public String getPhylumName(TaxonNameBase name){\r
+               List results = new ArrayList();\r
+               try{\r
+               Query query = getSession().createSQLQuery("select getPhylum("+ name.getId()+");");\r
+               results = query.list();\r
+               }catch(Exception e){\r
+                       System.err.println(name.getUuid());\r
+                       return null;\r
+               }\r
+               System.err.println("phylum of "+ name.getTitleCache() );\r
+               return (String)results.get(0);\r
+       }\r
+\r
+\r
+       public long countTaxaByCommonName(String searchString,\r
+                       Classification classification, MatchMode matchMode,\r
+                       Set<NamedArea> namedAreas) {\r
+               boolean doCount = true;\r
+               Query query = prepareTaxaByCommonName(searchString, classification, matchMode, namedAreas, null, null, doCount);\r
+               if (query != null && !query.list().isEmpty()) {\r
+                       Object o = query.uniqueResult();\r
+                       if(o != null) {\r
+                               return (Long)o;\r
+                       }\r
+               }\r
+               return 0;\r
+               \r
+       }\r
+\r
+\r
+       public long deleteSynonymRelationships(Synonym syn) {\r
+               \r
+               /*\r
+                * DELETE RT\r
+FROM         RelTaxon AS RT INNER JOIN\r
+                      Taxon AS FaEuSyn ON RT.TaxonFk1 = FaEuSyn.TaxonId INNER JOIN\r
+                      Taxon AS ERMSAcc ON FaEuSyn.RankFk = ERMSAcc.RankFk AND FaEuSyn.FullName = ERMSAcc.FullName AND ISNULL(FaEuSyn.TaxonStatusFk, 0)\r
+                      <> ERMSAcc.TaxonStatusFk\r
+WHERE     (FaEuSyn.OriginalDB = N'FaEu') AND (ERMSAcc.OriginalDB = N'ERMS') AND (ERMSAcc.TaxonStatusFk = 1) AND (ERMSAcc.KingdomFk = 2) AND\r
+                      (RT.RelTaxonQualifierFk > 100)\r
+                */\r
+               Session session = this.getSession();\r
+               Query q = session.createQuery("delete SynonymRelationship sr where sr.relatedFrom = :syn");\r
+               q.setParameter("syn", syn);\r
+               return q.executeUpdate();\r
+       }\r
+\r
+\r
+       @Override\r
+       public Integer countSynonymRelationships(TaxonBase taxonBase,\r
+                       SynonymRelationshipType type, Direction relatedfrom) {\r
+               AuditEvent auditEvent = getAuditEventFromContext();\r
+               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+                   Query query = null;\r
+               \r
+                   if(type == null) {\r
+                           query = getSession().createQuery("select count(synonymRelationship) from SynonymRelationship synonymRelationship where synonymRelationship."+relatedfrom+" = :relatedSynonym");\r
+                   } else {\r
+                           query = getSession().createQuery("select count(synonymRelationship) from SynonymRelationship synonymRelationship where synonymRelationship."+relatedfrom+" = :relatedSynonym and synonymRelationship.type = :type");\r
+                           query.setParameter("type",type);\r
+                   }\r
+                   query.setParameter("relatedTaxon", taxonBase);\r
+               \r
+                   return ((Long)query.uniqueResult()).intValue();\r
+               } else {\r
+                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());\r
+                       query.add(AuditEntity.relatedId(relatedfrom.toString()).eq(taxonBase.getId()));\r
+                       query.addProjection(AuditEntity.id().count("id"));\r
+                       \r
+                       if(type != null) {\r
+                               query.add(AuditEntity.relatedId("type").eq(type.getId()));\r
+                   }\r
+                       \r
+                       return ((Long)query.getSingleResult()).intValue();\r
+               }\r
+       }\r
+\r
+\r
+       @Override\r
+       public List<SynonymRelationship> getSynonymRelationships(TaxonBase taxonBase,\r
+                       SynonymRelationshipType type, Integer pageSize, Integer pageNumber,\r
+                       List<OrderHint> orderHints, List<String> propertyPaths,\r
+                       Direction direction) {\r
+               \r
+               AuditEvent auditEvent = getAuditEventFromContext();\r
+               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+                       Criteria criteria = getSession().createCriteria(SynonymRelationship.class);\r
+            \r
+                       if (direction.equals(Direction.relatedTo)){\r
+                               criteria.add(Restrictions.eq("relatedTo", taxonBase));\r
+                       }else{\r
+                               criteria.add(Restrictions.eq("relatedFrom", taxonBase));\r
+                       }\r
+                   if(type != null) {\r
+                       criteria.add(Restrictions.eq("type", type));\r
+                   } \r
+               \r
+            addOrder(criteria,orderHints);\r
+               \r
+                   if(pageSize != null) {\r
+                       criteria.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                               criteria.setFirstResult(pageNumber * pageSize);\r
+                       } else {\r
+                               criteria.setFirstResult(0);\r
+                       }\r
+                   }\r
+               \r
+                   List<SynonymRelationship> result = (List<SynonymRelationship>)criteria.list();\r
+                   defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                   \r
+                   return result;\r
+               } else {\r
+                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());\r
+                       \r
+                       if (direction.equals(Direction.relatedTo)){\r
+                               query.add(AuditEntity.relatedId("relatedTo").eq(taxonBase.getId()));\r
+                       }else{\r
+                               query.add(AuditEntity.relatedId("relatedFrom").eq(taxonBase.getId()));\r
+                       }\r
+                       \r
+                       if(type != null) {\r
+                               query.add(AuditEntity.relatedId("type").eq(type.getId()));\r
+                   }\r
+                       \r
+                       if(pageSize != null) {\r
+                       query.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                           query.setFirstResult(pageNumber * pageSize);\r
+                       } else {\r
+                           query.setFirstResult(0);\r
+                       }\r
+                   }\r
+                       \r
+                       List<SynonymRelationship> result = (List<SynonymRelationship>)query.getResultList();\r
+                       defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                       \r
+                       // Ugly, but for now, there is no way to sort on a related entity property in Envers,\r
+                       // and we can't live without this functionality in CATE as it screws up the whole \r
+                       // taxon tree thing\r
+                       if(orderHints != null && !orderHints.isEmpty()) {\r
+                           SortedSet<SynonymRelationship> sortedList = new TreeSet<SynonymRelationship>(new SynonymRelationshipFromTaxonComparator());\r
+                           sortedList.addAll(result);\r
+                           return new ArrayList<SynonymRelationship>(sortedList);\r
+                       }\r
+                       \r
+                       return result;\r
+               }\r
+       }\r
+\r
+\r
+       /* (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getUuidAndTitleCacheTaxon()\r
+        */\r
+       @Override\r
+       public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheTaxon() {\r
+               String queryString = String.format("select uuid, titleCache from %s where DTYPE = '%s'", type.getSimpleName(), Taxon.class.getSimpleName());\r
+               Query query = getSession().createQuery(queryString);\r
+               \r
+               List<UuidAndTitleCache<TaxonBase>> result = getUuidAndTitleCache(query);\r
+               \r
+               return result;\r
+       }\r
+\r
+\r
+       /* (non-Javadoc)\r
+        * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getUuidAndTitleCacheSynonym()\r
+        */\r
+       @Override\r
+       public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheSynonym() {\r
+               String queryString = String.format("select uuid, titleCache from %s where DTYPE = '%s'", type.getSimpleName(), Synonym.class.getSimpleName());\r
+               Query query = getSession().createQuery(queryString);\r
+               \r
+               List<UuidAndTitleCache<TaxonBase>> result = getUuidAndTitleCache(query);\r
+               \r
+               return result;\r
+       }\r
+\r
+\r
+\r
+\r
+       \r
+       \r
+       \r
+\r
+       \r
        \r
-}
\ No newline at end of file
+}\r