fix #6799: add totalCount of ticks as totalwork and start the progress monitor when...
[cdmlib.git] / cdmlib-io / src / main / java / eu / etaxonomy / cdm / io / markup / MarkupDocumentImportNoComponent.java
index 449805c9b811cf48e65a00e0ce5f2cd2785a8134..69b0263f16dcf6abf5689185317c156b8f3a2b37 100644 (file)
-/**\r
- * Copyright (C) 2009 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
-\r
-package eu.etaxonomy.cdm.io.markup;\r
-\r
-import java.net.MalformedURLException;\r
-import java.net.URL;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.UUID;\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
-\r
-import javax.xml.stream.Location;\r
-import javax.xml.stream.XMLEventReader;\r
-import javax.xml.stream.XMLStreamException;\r
-import javax.xml.stream.events.Attribute;\r
-import javax.xml.stream.events.StartElement;\r
-import javax.xml.stream.events.XMLEvent;\r
-\r
-import org.apache.commons.lang.StringUtils;\r
-import org.apache.commons.lang.WordUtils;\r
-import org.apache.log4j.Logger;\r
-\r
-import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;\r
-import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade.DerivedUnitType;\r
-import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeCacheStrategy;\r
-import eu.etaxonomy.cdm.common.CdmUtils;\r
-import eu.etaxonomy.cdm.ext.geo.GeoServiceArea;\r
-import eu.etaxonomy.cdm.ext.geo.IEditGeoService;\r
-import eu.etaxonomy.cdm.io.common.CdmImportBase;\r
-import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;\r
-import eu.etaxonomy.cdm.io.markup.UnmatchedLeads.UnmatchedLeadsKey;\r
-import eu.etaxonomy.cdm.model.agent.AgentBase;\r
-import eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor;\r
-import eu.etaxonomy.cdm.model.agent.Team;\r
-import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;\r
-import eu.etaxonomy.cdm.model.common.AnnotatableEntity;\r
-import eu.etaxonomy.cdm.model.common.Annotation;\r
-import eu.etaxonomy.cdm.model.common.AnnotationType;\r
-import eu.etaxonomy.cdm.model.common.CdmBase;\r
-import eu.etaxonomy.cdm.model.common.Extension;\r
-import eu.etaxonomy.cdm.model.common.ExtensionType;\r
-import eu.etaxonomy.cdm.model.common.Language;\r
-import eu.etaxonomy.cdm.model.common.TermVocabulary;\r
-import eu.etaxonomy.cdm.model.common.TimePeriod;\r
-import eu.etaxonomy.cdm.model.description.CommonTaxonName;\r
-import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
-import eu.etaxonomy.cdm.model.description.Distribution;\r
-import eu.etaxonomy.cdm.model.description.Feature;\r
-import eu.etaxonomy.cdm.model.description.IndividualsAssociation;\r
-import eu.etaxonomy.cdm.model.description.KeyStatement;\r
-import eu.etaxonomy.cdm.model.description.PolytomousKey;\r
-import eu.etaxonomy.cdm.model.description.PolytomousKeyNode;\r
-import eu.etaxonomy.cdm.model.description.PresenceAbsenceTermBase;\r
-import eu.etaxonomy.cdm.model.description.PresenceTerm;\r
-import eu.etaxonomy.cdm.model.description.TaxonDescription;\r
-import eu.etaxonomy.cdm.model.description.TextData;\r
-import eu.etaxonomy.cdm.model.location.NamedArea;\r
-import eu.etaxonomy.cdm.model.location.NamedAreaLevel;\r
-import eu.etaxonomy.cdm.model.location.NamedAreaType;\r
-import eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity;\r
-import eu.etaxonomy.cdm.model.media.Media;\r
-import eu.etaxonomy.cdm.model.name.CultivarPlantName;\r
-import eu.etaxonomy.cdm.model.name.HomotypicalGroup;\r
-import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;\r
-import eu.etaxonomy.cdm.model.name.NomenclaturalCode;\r
-import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;\r
-import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;\r
-import eu.etaxonomy.cdm.model.name.NonViralName;\r
-import eu.etaxonomy.cdm.model.name.Rank;\r
-import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;\r
-import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
-import eu.etaxonomy.cdm.model.occurrence.Collection;\r
-import eu.etaxonomy.cdm.model.occurrence.DerivedUnitBase;\r
-import eu.etaxonomy.cdm.model.occurrence.FieldObservation;\r
-import eu.etaxonomy.cdm.model.occurrence.Specimen;\r
-import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;\r
-import eu.etaxonomy.cdm.model.reference.IArticle;\r
-import eu.etaxonomy.cdm.model.reference.IJournal;\r
-import eu.etaxonomy.cdm.model.reference.Reference;\r
-import eu.etaxonomy.cdm.model.reference.ReferenceFactory;\r
-import eu.etaxonomy.cdm.model.reference.ReferenceType;\r
-import eu.etaxonomy.cdm.model.taxon.Classification;\r
-import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;\r
-import eu.etaxonomy.cdm.model.taxon.Taxon;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
-import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;\r
-import eu.etaxonomy.cdm.strategy.parser.NameTypeParser;\r
-import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;\r
-import eu.etaxonomy.cdm.strategy.parser.SpecimenTypeParser;\r
-import eu.etaxonomy.cdm.strategy.parser.SpecimenTypeParser.TypeInfo;\r
-\r
-/**\r
- * @author a.mueller\r
- * \r
- */\r
-public class MarkupDocumentImportNoComponent extends MarkupImportBase {\r
-       private static final Logger logger = Logger.getLogger(MarkupDocumentImportNoComponent.class);\r
-\r
-       private static final boolean CREATE_NEW = true;\r
-       private static final boolean IS_IMAGE_GALLERY = true;\r
-       private static final boolean NO_IMAGE_GALLERY = false;\r
-\r
-\r
-       private static final String ACCEPTED = "accepted";\r
-       private static final String ACCEPTED_NAME = "acceptedName";\r
-       private static final String ADDENDA = "addenda";\r
-       private static final String ALTERNATEPUBTITLE = "alternatepubtitle";\r
-       private static final String ALTERNATIVE_COLLECTION_TYPE_STATUS = "alternativeCollectionTypeStatus";\r
-       private static final String ALTERNATIVE_COLLECTOR = "alternativeCollector";\r
-       private static final String ALTERNATIVE_FIELD_NUM = "alternativeFieldNum";\r
-       private static final String ALTITUDE = "altitude";\r
-       private static final String ANNOTATION = "annotation";\r
-       private static final String AUTHOR = "author";\r
-       private static final String BIBLIOGRAPHY = "bibliography";\r
-       private static final String BIOGRAPHIES = "biographies";\r
-       private static final String BOLD = "bold";\r
-       private static final String BR = "br";\r
-       private static final String CHAR = "char";\r
-       private static final String CITATION = "citation";\r
-       private static final String COLLECTION_AND_TYPE = "collectionAndType";\r
-       private static final String COLLECTION_TYPE_STATUS = "collectionTypeStatus";\r
-       private static final String COLLECTOR = "collector";\r
-       private static final String COLLECTION = "collection";\r
-       private static final String COORDINATES = "coordinates";\r
-       private static final String DATES = "dates";\r
-       private static final String DEDICATION = "dedication";\r
-       private static final String DEFAULT_MEDIA_URL = "defaultMediaUrl";\r
-       private static final String DESTROYED = "destroyed";\r
-       private static final String DETAILS = "details";\r
-       private static final String DISTRIBUTION_LIST = "distributionList";\r
-       private static final String DISTRIBUTION_LOCALITY = "distributionLocality";\r
-       private static final String EDITION = "edition";\r
-       private static final String EDITORS = "editors";\r
-       private static final String FEATURE = "feature";\r
-       private static final String FIGURE = "figure";\r
-       private static final String FIGURE_LEGEND = "figureLegend";\r
-       private static final String FIGURE_PART = "figurePart";\r
-       private static final String FIGURE_REF = "figureRef";\r
-       private static final String FIGURE_TITLE = "figureTitle";\r
-       private static final String FOOTNOTE = "footnote";\r
-       private static final String FOOTNOTE_REF = "footnoteRef";\r
-       private static final String FOOTNOTE_STRING = "footnoteString";\r
-       private static final String FIELD_NUM = "fieldNum";\r
-       private static final String FREQUENCY = "frequency";\r
-       private static final String FULL_NAME = "fullName";\r
-       private static final String FULL_TYPE = "fullType";\r
-       private static final String GATHERING = "gathering";\r
-       private static final String HEADING = "heading";\r
-       private static final String HABITAT = "habitat";\r
-       private static final String HABITAT_LIST = "habitatList";\r
-       private static final String HOMONYM = "homonym";\r
-       private static final String HOMOTYPES = "homotypes";\r
-       private static final String ID = "id";\r
-       private static final String INFRANK = "infrank";\r
-       private static final String INFRAUT = "infraut";\r
-       private static final String INFRPARAUT = "infrparaut";\r
-       private static final String ISSUE = "issue";\r
-       private static final String ITALICS = "italics";\r
-       private static final String KEY = "key";\r
-       private static final String LIFE_CYCLE_PERIODS = "lifeCyclePeriods";\r
-       private static final String LOCALITY = "locality";\r
-       private static final String LOST = "lost";\r
-       private static final String META_DATA = "metaData";\r
-       private static final String NAME = "name";\r
-       private static final String NAME_TYPE = "nameType";\r
-       private static final String NOM = "nom";\r
-       private static final String NOMENCLATURE = "nomenclature";\r
-       private static final String NOT_FOUND = "notFound";\r
-       private static final String NOT_SEEN = "notSeen";\r
-       private static final String NOTES = "notes";\r
-       private static final String ORIGINAL_DETERMINATION = "originalDetermination";\r
-       private static final String PAGES = "pages";\r
-       private static final String PARAUT = "paraut";\r
-       private static final String PUBFULLNAME = "pubfullname";\r
-       private static final String PUBLICATION = "publication";\r
-       private static final String PUBNAME = "pubname";\r
-       private static final String PUBTITLE = "pubtitle";\r
-       private static final String PUBTYPE = "pubtype";\r
-       private static final String QUOTE = "quote";\r
-       private static final String RANK = "rank";\r
-       private static final String REF = "ref";\r
-       private static final String REF_NUM = "refNum";\r
-       private static final String REF_PART = "refPart";\r
-       private static final String REFERENCE = "reference";\r
-       private static final String REFERENCES = "references";\r
-       private static final String TAXON = "taxon";\r
-       private static final String TAXONTITLE = "taxontitle";\r
-       private static final String TAXONTYPE = "taxontype";\r
-       private static final String TEXT_SECTION = "textSection";\r
-       private static final String TYPE = "type";\r
-       private static final String TYPE_STATUS = "typeStatus";\r
-       private static final String TREATMENT = "treatment";\r
-       private static final String SERIALS_ABBREVIATIONS = "serialsAbbreviations";\r
-       private static final String SPECIMEN_TYPE = "specimenType";\r
-       private static final String STATUS = "status";\r
-       private static final String STRING = "string";\r
-       private static final String SUB_HEADING = "subHeading";\r
-       private static final String SUB_COLLECTION = "subCollection";\r
-       private static final String SYNONYM = "synonym";\r
-       private static final String UNKNOWN = "unknown";\r
-       private static final String URL = "url";\r
-       private static final String USAGE = "usage";\r
-       private static final String VOLUME = "volume";\r
-       private static final String WRITER = "writer";\r
-       private static final String YEAR = "year";\r
-\r
-       private NonViralNameParserImpl parser = new NonViralNameParserImpl();\r
-\r
-       // TODO make part of state, but state is renewed when invoking the import a\r
-       // second time\r
-       private UnmatchedLeads unmatchedLeads;\r
-\r
-\r
-       private IEditGeoService editGeoService;\r
-       \r
-       private MarkupKeyImport keyImport;\r
-       \r
-       public MarkupDocumentImportNoComponent(MarkupDocumentImport docImport) {\r
-               super(docImport);\r
-               this.editGeoService = docImport.getEditGeoService();\r
-               keyImport = new MarkupKeyImport(docImport);\r
-       }\r
-\r
-       public void doInvoke(MarkupImportState state) throws XMLStreamException { \r
-               XMLEventReader reader = state.getReader();\r
-               \r
-               // publication (= root element)\r
-               String elName = PUBLICATION;\r
-               boolean hasPublication = false;\r
-               \r
-               while (reader.hasNext()) {\r
-                       XMLEvent nextEvent = reader.nextEvent();\r
-                       if (isStartingElement(nextEvent, elName)) {\r
-                               handlePublication(state, reader, nextEvent, elName);\r
-                               hasPublication = true;\r
-                       } else if (nextEvent.isEndDocument()) {\r
-                               if (!hasPublication) {\r
-                                       String message = "No publication root element found";\r
-                                       fireWarningEvent(message, nextEvent, 8);\r
-                               }\r
-                               // done\r
-                       } else {\r
-                               fireSchemaConflictEventExpectedStartTag(elName, reader);\r
-                       }\r
-               }\r
-\r
-               \r
-               return;\r
-\r
-       }\r
-\r
-       private void handlePublication(MarkupImportState state, XMLEventReader reader, XMLEvent currentEvent, String elName) throws XMLStreamException {\r
-\r
-               // attributes\r
-               StartElement element = currentEvent.asStartElement();\r
-               Map<String, Attribute> attributes = getAttributes(element);\r
-               String lang = getAndRemoveAttributeValue(attributes, "lang");\r
-               if (lang != null){\r
-                       Language language = getTermService().getLanguageByIso(lang);\r
-                       state.setDefaultLanguage(language);\r
-               }\r
-               \r
-               handleUnexpectedAttributes(element.getLocation(), attributes, "noNamespaceSchemaLocation");\r
-\r
-               while (reader.hasNext()) {\r
-                       XMLEvent event = readNoWhitespace(reader);\r
-                       // TODO cardinality of alternative\r
-                       if (event.isEndElement()) {\r
-                               if (isEndingElement(event, elName)) {\r
-                                       return;\r
-                               } else {\r
-                                       if (isEndingElement(event, BIOGRAPHIES)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(event.asEndElement());\r
-                                       } else if (isEndingElement(event, REFERENCES)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(event.asEndElement());\r
-                                       } else if (isEndingElement(event, TEXT_SECTION)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(event.asEndElement());\r
-                                       } else if (isEndingElement(event, ADDENDA)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(event.asEndElement());\r
-                                       } else {\r
-                                               handleUnexpectedElement(event);\r
-                                       }\r
-                               }\r
-                       } else if (event.isStartElement()) {\r
-                               if (isStartingElement(event, META_DATA)) {\r
-                                       handleMetaData(state, reader, event);\r
-                               } else if (isStartingElement(event, TREATMENT)) {\r
-                                       handleTreatment(state, reader, event);\r
-                               } else if (isStartingElement(event, BIOGRAPHIES)) {\r
-                                       handleNotYetImplementedElement(event);\r
-                               } else if (isStartingElement(event, REFERENCES)) {\r
-                                       handleNotYetImplementedElement(event);\r
-                               } else if (isStartingElement(event, TEXT_SECTION)) {\r
-                                       handleNotYetImplementedElement(event);\r
-                               } else if (isStartingElement(event, ADDENDA)) {\r
-                                       handleNotYetImplementedElement(event);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(event);\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedElement(event);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("Publication has no ending element");\r
-       }\r
-\r
-       private void handleMetaData(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               return;\r
-                       } else if (isStartingElement(next, DEFAULT_MEDIA_URL)) {\r
-                               String baseUrl = getCData(state, reader, next);\r
-                               try {\r
-                                       new URL(baseUrl);\r
-                                       state.setBaseMediaUrl(baseUrl);\r
-                               } catch (MalformedURLException e) {\r
-                                       String message = "defaultMediaUrl '%s' is not a valid URL";\r
-                                       message = String.format(message, baseUrl);\r
-                                       fireWarningEvent(message, next, 8);\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("MetaData has no ending element");\r
-\r
-       }\r
-\r
-       private void handleTreatment(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-               Taxon lastTaxon = null;\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isStartingElement(next, TAXON)) {\r
-                               Taxon thisTaxon = handleTaxon(state, reader, next.asStartElement());\r
-                               doTaxonRelation(state, thisTaxon, lastTaxon, parentEvent.getLocation());\r
-                               lastTaxon = thisTaxon;\r
-                               // TODO for imports spanning multiple documents ?? Still needed?\r
-                               state.getConfig().setLastTaxonUuid(lastTaxon.getUuid());\r
-                       } else if (isMyEndingElement(next, parentEvent)) {\r
-                               Set<PolytomousKeyNode> keyNodesToSave = state.getPolytomousKeyNodesToSave();\r
-                               //better save the key then the nodes\r
-                               Set<PolytomousKey> keySet = new HashSet<PolytomousKey>();\r
-                               for (PolytomousKeyNode node : keyNodesToSave){\r
-                                       PolytomousKey key = node.getKey();\r
-                                       keySet.add(key);\r
-                               }\r
-                               save(keySet, state);\r
-                               //unmatched key leads\r
-                               UnmatchedLeads unmatched = state.getUnmatchedLeads();\r
-                               if (unmatched.size() > 0){\r
-                                       String message = "The following key leads are unmatched: %s";\r
-                                       message = String.format(message, state.getUnmatchedLeads().toString());\r
-                                       fireWarningEvent(message, next, 6);\r
-                               }\r
-//                             save(keyNodesToSave, state);\r
-\r
-                               return;\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               return;\r
-       }\r
-\r
-       /**\r
-        * @param taxon\r
-        * @param lastTaxon\r
-        */\r
-       private void doTaxonRelation(MarkupImportState state, Taxon taxon,\r
-                       Taxon lastTaxon, Location dataLocation) {\r
-\r
-               Classification tree = makeTree(state, dataLocation);\r
-               if (lastTaxon == null) {\r
-                       tree.addChildTaxon(taxon, null, null, null);\r
-                       return;\r
-               }\r
-               Rank thisRank = taxon.getName().getRank();\r
-               Rank lastRank = lastTaxon.getName().getRank();\r
-               if (lastTaxon.getTaxonNodes().size() > 0) {\r
-                       TaxonNode lastNode = lastTaxon.getTaxonNodes().iterator().next();\r
-                       if (thisRank == null){\r
-                               String message = "rank is undefined for taxon '%s'. Can't create classification without rank.";\r
-                               message = String.format(message, taxon.getName().getTitleCache());\r
-                               fireWarningEvent(message, makeLocationStr(dataLocation), 6);\r
-                       }else if (thisRank.isLower(lastRank)) {\r
-                               lastNode.addChildTaxon(taxon, null, null, null);\r
-                               fillMissingEpithetsForTaxa(lastTaxon, taxon);\r
-                       } else if (thisRank.equals(lastRank)) {\r
-                               TaxonNode parent = lastNode.getParent();\r
-                               if (parent != null) {\r
-                                       parent.addChildTaxon(taxon, null, null, null);\r
-                                       fillMissingEpithetsForTaxa(parent.getTaxon(), taxon);\r
-                               } else {\r
-                                       tree.addChildTaxon(taxon, null, null, null);\r
-                               }\r
-                       } else if (thisRank.isHigher(lastRank)) {\r
-                               doTaxonRelation(state, taxon, lastNode.getParent().getTaxon(),  dataLocation);\r
-                               // TaxonNode parentNode = handleTaxonRelation(state, taxon,\r
-                               // lastNode.getParent().getTaxon());\r
-                               // parentNode.addChildTaxon(taxon, null, null, null);\r
-                       }\r
-               } else {\r
-\r
-                       String message = "Last taxon has no node";\r
-                       fireWarningEvent(message, makeLocationStr(dataLocation), 6);\r
-               }\r
-       }\r
-\r
-\r
-\r
-       /**\r
-        * @param state\r
-        * @param dataLocation \r
-        * @return\r
-        */\r
-       private Classification makeTree(MarkupImportState state, Location dataLocation) {\r
-               Classification result = state.getTree(null);\r
-               if (result == null) {\r
-                       UUID uuid = state.getConfig().getClassificationUuid();\r
-                       if (uuid == null) {\r
-                               String message = "No classification uuid is defined";\r
-                               fireWarningEvent(message, makeLocationStr(dataLocation), 6);\r
-                               result = createNewClassification(state);\r
-                       } else {\r
-                               result = getClassificationService().find(uuid);\r
-                               if (result == null) {\r
-                                       result = createNewClassification(state);\r
-                                       result.setUuid(uuid);\r
-                               }\r
-                       }\r
-                       state.putTree(null, result);\r
-               }\r
-               save(result, state);\r
-               return result;\r
-       }\r
-\r
-       private Classification createNewClassification(MarkupImportState state) {\r
-               Classification result;\r
-               result = Classification.NewInstance(state.getConfig().getClassificationTitle());\r
-               state.putTree(null, result);\r
-               return result;\r
-       }\r
-\r
-       private Taxon handleTaxon(MarkupImportState state, XMLEventReader reader, StartElement parentEvent) throws XMLStreamException {\r
-               // TODO progress monitoring\r
-               Map<String, Attribute> attributes = getAttributes(parentEvent);\r
-               Taxon taxon = createTaxonAndName(state, attributes);\r
-               state.setCurrentTaxon(taxon);\r
-\r
-               boolean hasTitle = false;\r
-               boolean hasNomenclature = false;\r
-               String taxonTitle = null;\r
-\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (next.isEndElement()) {\r
-                               if (isMyEndingElement(next, parentEvent)) {\r
-                                       checkMandatoryElement(hasTitle, parentEvent, TAXONTITLE);\r
-                                       checkMandatoryElement(hasNomenclature, parentEvent,     NOMENCLATURE);\r
-                                       handleUnexpectedAttributes(parentEvent.getLocation(),attributes);\r
-                                       if (taxon.getName().getRank() == null){\r
-                                               String warning = "No rank exists for taxon " + taxon.getTitleCache();\r
-                                               fireWarningEvent(warning, next, 12);\r
-                                       }\r
-                                       \r
-                                       keyImport.makeKeyNodes(state, parentEvent, taxonTitle);\r
-                                       state.setCurrentTaxon(null);\r
-                                       state.setCurrentTaxonNum(null);\r
-                                       save(taxon, state);\r
-                                       return taxon;\r
-                               } else {\r
-                                       if (isEndingElement(next, HEADING)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, TEXT_SECTION)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, REFERENCES)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, FIGURE_REF)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else {\r
-                                               handleUnexpectedEndElement(next.asEndElement());\r
-                                       }\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, HEADING)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, TAXONTITLE)) {\r
-                                       taxonTitle = handleTaxonTitle(state, reader, next);\r
-                                       hasTitle = true;\r
-                               } else if (isStartingElement(next, WRITER)) {\r
-                                       makeKeyWriter(state, reader, taxon, taxonTitle, next);\r
-                               } else if (isStartingElement(next, TEXT_SECTION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, KEY)) {\r
-                                       keyImport.handleKey(state, reader, next);\r
-                               } else if (isStartingElement(next, NOMENCLATURE)) {\r
-                                       handleNomenclature(state, reader, next);\r
-                                       hasNomenclature = true;\r
-                               } else if (isStartingElement(next, FEATURE)) {\r
-                                       handleFeature(state, reader, next);\r
-                               } else if (isStartingElement(next, NOTES)) {\r
-                                       // TODO is this the correct way to handle notes?\r
-                                       String note = handleNotes(state, reader, next);\r
-\r
-                                       UUID notesUuid;\r
-                                       try {\r
-                                               notesUuid = state.getTransformer().getFeatureUuid(\r
-                                                               "notes");\r
-                                               Feature feature = getFeature(state, notesUuid, "Notes",\r
-                                                               "Notes", "note", null);\r
-                                               TextData textData = TextData.NewInstance(feature);\r
-                                               textData.putText(Language.DEFAULT(), note);\r
-                                               TaxonDescription description = getTaxonDescription(\r
-                                                               taxon, null, false, true);\r
-                                               description.addElement(textData);\r
-                                       } catch (UndefinedTransformerMethodException e) {\r
-                                               String message = "getFeatureUuid method not yet implemented";\r
-                                               fireWarningEvent(message, next, 8);\r
-                                       }\r
-                               } else if (isStartingElement(next, REFERENCES)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, FIGURE_REF)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, FIGURE)) {\r
-                                       handleFigure(state, reader, next);\r
-                               } else if (isStartingElement(next, FOOTNOTE)) {\r
-                                       FootnoteDataHolder footnote = handleFootnote(state, reader,     next);\r
-                                       if (footnote.isRef()) {\r
-                                               String message = "Ref footnote not implemented here";\r
-                                               fireWarningEvent(message, next, 4);\r
-                                       } else {\r
-                                               registerGivenFootnote(state, footnote);\r
-                                       }\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next);\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<Taxon> has no closing tag");\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param reader\r
-        * @param taxon\r
-        * @param taxonTitle\r
-        * @param next\r
-        * @throws XMLStreamException\r
-        */\r
-       private void makeKeyWriter(MarkupImportState state, XMLEventReader reader, Taxon taxon, String taxonTitle, XMLEvent next) throws XMLStreamException {\r
-               WriterDataHolder writer = handleWriter(state, reader, next);\r
-               taxon.addExtension(writer.extension);\r
-               // TODO what if taxonTitle comes later\r
-               if (StringUtils.isNotBlank(taxonTitle)\r
-                               && writer.extension != null) {\r
-                       Reference<?> sec = ReferenceFactory.newBookSection();\r
-                       sec.setTitle(taxonTitle);\r
-                       TeamOrPersonBase<?> author = createAuthor(writer.writer);\r
-                       sec.setAuthorTeam(author);\r
-                       sec.setInReference(state.getConfig()\r
-                                       .getSourceReference());\r
-                       taxon.setSec(sec);\r
-                       registerFootnotes(state, sec, writer.footnotes);\r
-               } else {\r
-                       String message = "No taxontitle exists for writer";\r
-                       fireWarningEvent(message, next, 6);\r
-               }\r
-       }\r
-\r
-       private String handleNotes(MarkupImportState state, XMLEventReader reader,\r
-                       XMLEvent parentEvent) throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               return text;\r
-                       } else if (next.isEndElement()) {\r
-                               if (isEndingElement(next, HEADING)) {\r
-                                       popUnimplemented(next.asEndElement());\r
-                               } else if (isEndingElement(next, WRITER)) {\r
-                                       popUnimplemented(next.asEndElement());\r
-                               } else if (isEndingElement(next, NUM)) {\r
-                                       popUnimplemented(next.asEndElement());\r
-                               } else {\r
-                                       handleUnexpectedEndElement(next.asEndElement());\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, HEADING)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, SUB_HEADING)) {\r
-                                       String subheading = getCData(state, reader, next).trim();\r
-                                       if (! isNoteHeading(subheading)) {\r
-                                               fireNotYetImplementedElement(next.getLocation(), next.asStartElement().getName(), 0);\r
-                                       }\r
-                               } else if (isStartingElement(next, WRITER)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, NUM)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, STRING)) {\r
-                                       // TODO why multiple strings in schema?\r
-                                       text = makeNotesString(state, reader, text, next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next.asStartElement());\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<Notes> has no closing tag");\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param reader\r
-        * @param text\r
-        * @param next\r
-        * @return\r
-        * @throws XMLStreamException\r
-        */\r
-       private String makeNotesString(MarkupImportState state, XMLEventReader reader, String text, XMLEvent next) throws XMLStreamException {\r
-               Map<String, String> stringMap = handleString(state, reader,     next, null);\r
-               if (stringMap.size() == 0){\r
-                       String message = "No text available in <notes>";\r
-                       fireWarningEvent(message, next, 4);\r
-               }else if (stringMap.size() > 1){\r
-                       String message = "Subheadings not yet supported in <notes>";\r
-                       fireWarningEvent(message, next, 4);\r
-               }else{\r
-                       String firstSubheading = stringMap.keySet().iterator().next();\r
-                       if ( firstSubheading != null && ! isNoteHeading (firstSubheading) )  {\r
-                               String message = "Subheadings not yet supported in <notes>";\r
-                               fireWarningEvent(message, next, 4);\r
-                       }\r
-               }\r
-               for (String subheading : stringMap.keySet()){\r
-                       text += subheading;\r
-                       text += stringMap.get(subheading);\r
-               }\r
-               return text;\r
-       }\r
-\r
-       private boolean isNoteHeading(String heading) {\r
-               String excludePattern = "(i?)(Notes?):?";\r
-               return heading.matches(excludePattern);\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param attributes\r
-        */\r
-       private Taxon createTaxonAndName(MarkupImportState state,\r
-                       Map<String, Attribute> attributes) {\r
-               NonViralName<?> name;\r
-               Rank rank = null;  //Rank.SPECIES(); // default\r
-               boolean isCultivar = checkAndRemoveAttributeValue(attributes, CLASS, "cultivated");\r
-               if (isCultivar) {\r
-                       name = CultivarPlantName.NewInstance(rank);\r
-               } else {\r
-                       name = createNameByCode(state, rank);\r
-               }\r
-               Taxon taxon = Taxon.NewInstance(name, state.getConfig().getSourceReference());\r
-               if (checkAndRemoveAttributeValue(attributes, CLASS, "dubious")) {\r
-                       taxon.setDoubtful(true);\r
-               } else if (checkAndRemoveAttributeValue(attributes, CLASS, "excluded")) {\r
-                       taxon.setExcluded(true);\r
-               }\r
-               // TODO insufficient, new, expected\r
-               handleNotYetImplementedAttribute(attributes, CLASS);\r
-               // From old version\r
-               // MarkerType markerType = getMarkerType(state, attrValue);\r
-               // if (markerType == null){\r
-               // logger.warn("Class attribute value for taxon not yet supported: " +\r
-               // attrValue);\r
-               // }else{\r
-               // taxon.addMarker(Marker.NewInstance(markerType, true));\r
-               // }\r
-\r
-               // save(name, state);\r
-               // save(taxon, state);\r
-               return taxon;\r
-       }\r
-\r
-       private String handleTaxonTitle(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               //attributes\r
-               String text = "";\r
-               Map<String, Attribute> attributes = getAttributes(parentEvent);\r
-               String rankAttr = getAndRemoveAttributeValue(attributes, RANK);\r
-               Rank rank = makeRank(state, rankAttr, false);\r
-               String num = getAndRemoveAttributeValue(attributes, NUM);\r
-               state.setCurrentTaxonNum(num);\r
-               checkNoAttributes(attributes, parentEvent);\r
-\r
-               // TODO handle attributes\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (next.isEndElement()) {\r
-                               if (isMyEndingElement(next, parentEvent)) {\r
-                                       Taxon taxon = state.getCurrentTaxon();\r
-                                       String titleText = null;\r
-                                       if (checkMandatoryText(text, parentEvent)) {\r
-                                               titleText = normalize(text);\r
-                                               UUID uuidTitle = MarkupTransformer.uuidTaxonTitle;\r
-                                               ExtensionType titleExtension = this.getExtensionType(state, uuidTitle, "Taxon Title ","taxon title", "title");\r
-                                               taxon.addExtension(titleText, titleExtension);\r
-                                       }\r
-                                       taxon.getName().setRank(rank);\r
-                                       // TODO check title exists\r
-                                       return titleText;\r
-                               } else {\r
-                                       if (isEndingElement(next, FOOTNOTE)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else {\r
-                                               handleUnexpectedEndElement(next.asEndElement());\r
-                                               state.setUnsuccessfull();\r
-                                       }\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, FOOTNOTE)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next);\r
-                                       state.setUnsuccessfull();\r
-                               }\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                               state.setUnsuccessfull();\r
-                       }\r
-               }\r
-               return null;\r
-\r
-       }\r
-\r
-       private WriterDataHolder handleWriter(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               String text = "";\r
-               checkNoAttributes(parentEvent);\r
-               WriterDataHolder dataHolder = new WriterDataHolder();\r
-               List<FootnoteDataHolder> footnotes = new ArrayList<FootnoteDataHolder>();\r
-\r
-               // TODO handle attributes\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               text = CdmUtils.removeBrackets(text);\r
-                               if (checkMandatoryText(text, parentEvent)) {\r
-                                       text = normalize(text);\r
-                                       dataHolder.writer = text;\r
-                                       dataHolder.footnotes = footnotes;\r
-\r
-                                       // Extension\r
-                                       UUID uuidWriterExtension = MarkupTransformer.uuidWriterExtension;\r
-                                       ExtensionType writerExtensionType = this\r
-                                                       .getExtensionType(state, uuidWriterExtension,\r
-                                                                       "Writer", "writer", "writer");\r
-                                       Extension extension = Extension.NewInstance();\r
-                                       extension.setType(writerExtensionType);\r
-                                       extension.setValue(text);\r
-                                       dataHolder.extension = extension;\r
-\r
-                                       // Annotation\r
-                                       UUID uuidWriterAnnotation = MarkupTransformer.uuidWriterAnnotation;\r
-                                       AnnotationType writerAnnotationType = this.getAnnotationType(state, uuidWriterAnnotation, "Writer", "writer", "writer", null);\r
-                                       Annotation annotation = Annotation.NewInstance(text, writerAnnotationType, Language.DEFAULT());\r
-                                       dataHolder.annotation = annotation;\r
-\r
-                                       return dataHolder;\r
-                               } else {\r
-                                       return null;\r
-                               }\r
-                       } else if (isStartingElement(next, FOOTNOTE_REF)) {\r
-                               FootnoteDataHolder footNote = handleFootnoteRef(state, reader, next);\r
-                               if (footNote.isRef()) {\r
-                                       footnotes.add(footNote);\r
-                               } else {\r
-                                       logger.warn("Non ref footnotes not yet impelemnted");\r
-                               }\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                               state.setUnsuccessfull();\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<writer> has no end tag");\r
-       }\r
-\r
-       private void registerFootnotes(MarkupImportState state, AnnotatableEntity entity, List<FootnoteDataHolder> footnotes) {\r
-               for (FootnoteDataHolder footNote : footnotes) {\r
-                       registerFootnoteDemand(state, entity, footNote);\r
-               }\r
-       }\r
-\r
-       private void registerGivenFootnote(MarkupImportState state, FootnoteDataHolder footnote) {\r
-               state.registerFootnote(footnote);\r
-               Set<AnnotatableEntity> demands = state.getFootnoteDemands(footnote.id);\r
-               if (demands != null) {\r
-                       for (AnnotatableEntity entity : demands) {\r
-                               attachFootnote(state, entity, footnote);\r
-                       }\r
-               }\r
-       }\r
-\r
-       private void registerGivenFigure(MarkupImportState state, String id, Media figure) {\r
-               state.registerFigure(id, figure);\r
-               Set<AnnotatableEntity> demands = state.getFigureDemands(id);\r
-               if (demands != null) {\r
-                       for (AnnotatableEntity entity : demands) {\r
-                               attachFigure(state, entity, figure);\r
-                       }\r
-               }\r
-       }\r
-\r
-       private void registerFootnoteDemand(MarkupImportState state, AnnotatableEntity entity, FootnoteDataHolder footnote) {\r
-               FootnoteDataHolder existingFootnote = state.getFootnote(footnote.ref);\r
-               if (existingFootnote != null) {\r
-                       attachFootnote(state, entity, existingFootnote);\r
-               } else {\r
-                       Set<AnnotatableEntity> demands = state.getFootnoteDemands(footnote.ref);\r
-                       if (demands == null) {\r
-                               demands = new HashSet<AnnotatableEntity>();\r
-                               state.putFootnoteDemands(footnote.ref, demands);\r
-                       }\r
-                       demands.add(entity);\r
-               }\r
-       }\r
-\r
-       private void registerFigureDemand(MarkupImportState state, AnnotatableEntity entity, String figureRef) {\r
-               Media existingFigure = state.getFigure(figureRef);\r
-               if (existingFigure != null) {\r
-                       attachFigure(state, entity, existingFigure);\r
-               } else {\r
-                       Set<AnnotatableEntity> demands = state.getFigureDemands(figureRef);\r
-                       if (demands == null) {\r
-                               demands = new HashSet<AnnotatableEntity>();\r
-                               state.putFigureDemands(figureRef, demands);\r
-                       }\r
-                       demands.add(entity);\r
-               }\r
-       }\r
-\r
-       private void attachFootnote(MarkupImportState state, AnnotatableEntity entity, FootnoteDataHolder footnote) {\r
-               AnnotationType annotationType = this.getAnnotationType(state, MarkupTransformer.uuidFootnote, "Footnote", "An e-flora footnote", "fn", null);\r
-               Annotation annotation = Annotation.NewInstance(footnote.string,\r
-                               annotationType, Language.DEFAULT());\r
-               // TODO transient objects\r
-               entity.addAnnotation(annotation);\r
-               save(entity, state);\r
-       }\r
-\r
-       private void attachFigure(MarkupImportState state,\r
-                       AnnotatableEntity entity, Media figure) {\r
-               // IdentifiableEntity<?> toSave;\r
-               if (entity.isInstanceOf(TextData.class)) {\r
-                       TextData deb = CdmBase.deproxy(entity, TextData.class);\r
-                       deb.addMedia(figure);\r
-                       // toSave = ((TaxonDescription)deb.getInDescription()).getTaxon();\r
-               } else if (entity.isInstanceOf(IdentifiableMediaEntity.class)) {\r
-                       IdentifiableMediaEntity<?> ime = CdmBase.deproxy(entity,\r
-                                       IdentifiableMediaEntity.class);\r
-                       ime.addMedia(figure);\r
-                       // toSave = ime;\r
-               } else {\r
-                       String message = "Unsupported entity to attach media: %s";\r
-                       message = String.format(message, entity.getClass().getName());\r
-                       // toSave = null;\r
-               }\r
-               save(entity, state);\r
-       }\r
-\r
-       private void handleFigure(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               // FigureDataHolder result = new FigureDataHolder();\r
-\r
-               Map<String, Attribute> attributes = getAttributes(parentEvent);\r
-               String id = getAndRemoveAttributeValue(attributes, ID);\r
-               String type = getAndRemoveAttributeValue(attributes, TYPE);\r
-               checkNoAttributes(attributes, parentEvent);\r
-\r
-               String urlString = null;\r
-               String legendString = null;\r
-               String titleString = null;\r
-               String numString = null;\r
-               String text = null;\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               makeFigure(state, id, type, urlString, legendString, titleString, numString, next);\r
-                               return;\r
-                       } else if (isStartingElement(next, FIGURE_LEGEND)) {\r
-                               // TODO same as figurestring ?\r
-                               legendString = handleFootnoteString(state, reader, next);\r
-                       } else if (isStartingElement(next, FIGURE_TITLE)) {\r
-                               titleString = getCData(state, reader, next);\r
-                       } else if (isStartingElement(next, URL)) {\r
-                               String localUrl = getCData(state, reader, next);\r
-                               urlString = CdmUtils.Nz(state.getBaseMediaUrl()) + localUrl;\r
-                       } else if (isStartingElement(next, NUM)) {\r
-                               numString = getCData(state, reader, next);\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-                       } else {\r
-                               fireUnexpectedEvent(next, 0);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<figure> has no end tag");\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param id\r
-        * @param type\r
-        * @param urlString\r
-        * @param legendString\r
-        * @param titleString\r
-        * @param numString\r
-        * @param next\r
-        */\r
-       private void makeFigure(MarkupImportState state, String id, String type, String urlString, \r
-                                               String legendString, String titleString, String numString, XMLEvent next) {\r
-               Media media = null;\r
-               boolean isFigure = false;\r
-               try {\r
-                       //TODO maybe everything is a figure as it is all taken from a book\r
-                       if ("lineart".equals(type)) {\r
-                               isFigure = true;\r
-//                             media = Figure.NewInstance(url.toURI(), null, null,     null);\r
-                       } else if (type == null || "photo".equals(type)\r
-                                       || "signature".equals(type)\r
-                                       || "others".equals(type)) {\r
-                       } else {\r
-                               String message = "Unknown figure type '%s'";\r
-                               message = String.format(message, type);\r
-                               fireWarningEvent(message, next, 2);\r
-                       }\r
-                       media = docImport.getImageMedia(urlString, docImport.getReadMediaData(), isFigure);\r
-                       \r
-                       if (media != null){\r
-                               // title\r
-                               if (StringUtils.isNotBlank(titleString)) {\r
-                                       media.putTitle(Language.DEFAULT(), titleString);\r
-                               }\r
-                               // legend\r
-                               if (StringUtils.isNotBlank(legendString)) {\r
-                                       media.addDescription(legendString, Language.DEFAULT());\r
-                               }\r
-                               if (StringUtils.isNotBlank(numString)) {\r
-                                       // TODO use concrete source (e.g. DAPHNIPHYLLACEAE in FM\r
-                                       // vol.13)\r
-                                       Reference<?> citation = state.getConfig().getSourceReference();\r
-                                       media.addSource(numString, "num", citation, null);\r
-                                       // TODO name used in source if available\r
-                               }\r
-                               // TODO which citation\r
-                               if (StringUtils.isNotBlank(id)) {\r
-                                       media.addSource(id, null, state.getConfig().getSourceReference(), null);\r
-                               } else {\r
-                                       String message = "Figure id should never be empty or null";\r
-                                       fireWarningEvent(message, next, 6);\r
-                               }\r
-                               \r
-                               // text\r
-                               // do nothing\r
-\r
-                       }\r
-               } catch (MalformedURLException e) {\r
-                       String message = "Media uri has incorrect syntax: %s";\r
-                       message = String.format(message, urlString);\r
-                       fireWarningEvent(message, next, 4);\r
-//             } catch (URISyntaxException e) {\r
-//                     String message = "Media uri has incorrect syntax: %s";\r
-//                     message = String.format(message, urlString);\r
-//                     fireWarningEvent(message, next, 4);\r
-               }\r
-\r
-               registerGivenFigure(state, id, media);\r
-       }\r
-\r
-       private FigureDataHolder handleFigureRef(MarkupImportState state,\r
-                       XMLEventReader reader, XMLEvent parentEvent)\r
-                       throws XMLStreamException {\r
-               FigureDataHolder result = new FigureDataHolder();\r
-               Map<String, Attribute> attributes = getAttributes(parentEvent);\r
-               result.ref = getAndRemoveAttributeValue(attributes, REF);\r
-               checkNoAttributes(attributes, parentEvent);\r
-\r
-               // text is not handled, needed only for debugging purposes\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               return result;\r
-                       } else if (isStartingElement(next, NUM)) {\r
-                               String num = getCData(state, reader, next);\r
-                               result.num = num; // num is not handled during import\r
-                       } else if (isStartingElement(next, FIGURE_PART)) {\r
-                               result.figurePart = getCData(state, reader, next);\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-                       } else {\r
-                               fireUnexpectedEvent(next, 0);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<figureRef> has no end tag");\r
-       }\r
-\r
-       private FootnoteDataHolder handleFootnote(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               FootnoteDataHolder result = new FootnoteDataHolder();\r
-               Map<String, Attribute> attributes = getAttributes(parentEvent);\r
-               result.id = getAndRemoveAttributeValue(attributes, ID);\r
-               // result.ref = getAndRemoveAttributeValue(attributes, REF);\r
-               checkNoAttributes(attributes, parentEvent);\r
-\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isStartingElement(next, FOOTNOTE_STRING)) {\r
-                               String string = handleFootnoteString(state, reader, next);\r
-                               result.string = string;\r
-                       } else if (isMyEndingElement(next, parentEvent)) {\r
-                               return result;\r
-                       } else {\r
-                               fireUnexpectedEvent(next, 0);\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-\r
-       private FootnoteDataHolder handleFootnoteRef(MarkupImportState state,\r
-                       XMLEventReader reader, XMLEvent parentEvent)\r
-                       throws XMLStreamException {\r
-               FootnoteDataHolder result = new FootnoteDataHolder();\r
-               Map<String, Attribute> attributes = getAttributes(parentEvent);\r
-               result.ref = getAndRemoveAttributeValue(attributes, REF);\r
-               checkNoAttributes(attributes, parentEvent);\r
-\r
-               // text is not handled, needed only for debugging purposes\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       // if (isStartingElement(next, FOOTNOTE_STRING)){\r
-                       // String string = handleFootnoteString(state, reader, next);\r
-                       // result.string = string;\r
-                       // }else\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               return result;\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-\r
-                       } else {\r
-                               fireUnexpectedEvent(next, 0);\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-\r
-       private void handleNomenclature(MarkupImportState state,\r
-                       XMLEventReader reader, XMLEvent parentEvent)\r
-                       throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isStartingElement(next, HOMOTYPES)) {\r
-                               handleHomotypes(state, reader, next.asStartElement());\r
-                       } else if (isMyEndingElement(next, parentEvent)) {\r
-                               return;\r
-                       } else {\r
-                               fireSchemaConflictEventExpectedStartTag(HOMOTYPES, reader);\r
-                               state.setUnsuccessfull();\r
-                       }\r
-               }\r
-               return;\r
-       }\r
-\r
-       private String handleFootnoteString(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               boolean isTextMode = true;\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               return text;\r
-                       } else if (next.isEndElement()) {\r
-                               if (isEndingElement(next, FULL_NAME)) {\r
-                                       popUnimplemented(next.asEndElement());\r
-                               } else if (isEndingElement(next, BR)) {\r
-                                       isTextMode = true;\r
-                               } else if (isHtml(next)) {\r
-                                       text += getXmlTag(next);\r
-                               } else {\r
-                                       handleUnexpectedEndElement(next.asEndElement());\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, FULL_NAME)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, GATHERING)) {\r
-                                       text += handleInLineGathering(state, reader, next);\r
-                               } else if (isStartingElement(next, REFERENCES)) {\r
-                                       text += " " + handleInLineReferences(state, reader, next)+ " ";\r
-                               } else if (isStartingElement(next, BR)) {\r
-                                       text += "<br/>";\r
-                                       isTextMode = false;\r
-                               } else if (isHtml(next)) {\r
-                                       text += getXmlTag(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next.asStartElement());\r
-                               }\r
-                       } else if (next.isCharacters()) {\r
-                               if (!isTextMode) {\r
-                                       String message = "footnoteString is not in text mode";\r
-                                       fireWarningEvent(message, next, 6);\r
-                               } else {\r
-                                       text += next.asCharacters().getData().trim(); \r
-                                       // getCData(state, reader, next); does not work as we have inner tags like <references>\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedEndElement(next.asEndElement());\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<footnoteString> has no closing tag");\r
-\r
-       }\r
-\r
-       private String handleInLineGathering(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(DerivedUnitType.DerivedUnit.FieldObservation);\r
-               handleGathering(state, reader, parentEvent, facade);\r
-               FieldObservation fieldObservation = facade.innerFieldObservation();\r
-               String result = "<cdm:specimen uuid='%s'>%s</specimen>";\r
-               result = String.format(result, fieldObservation.getUuid(), fieldObservation.getTitleCache());\r
-               save(fieldObservation, state);\r
-               return result;  \r
-       }\r
-\r
-       private String handleInLineReferences(MarkupImportState state,XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-\r
-               boolean hasReference = false;\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               checkMandatoryElement(hasReference, parentEvent.asStartElement(), REFERENCE);\r
-                               return text;\r
-                       } else if (isStartingElement(next, REFERENCE)) {\r
-                               text += handleInLineReference(state, reader, next);\r
-                               hasReference = true;\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<References> has no closing tag");\r
-       }\r
-\r
-       private String handleInLineReference(MarkupImportState state,XMLEventReader reader, XMLEvent parentEvent)throws XMLStreamException {\r
-               Reference<?> reference = handleReference(state, reader, parentEvent);\r
-               String result = "<cdm:ref uuid='%s'>%s</ref>";\r
-               result = String.format(result, reference.getUuid(), reference.getTitleCache());\r
-               save(reference, state);\r
-               return result;\r
-       }\r
-\r
-       private Reference<?> handleReference(MarkupImportState state,XMLEventReader reader, XMLEvent parentEvent)throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-\r
-               boolean hasRefPart = false;\r
-               Map<String, String> refMap = new HashMap<String, String>();\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               checkMandatoryElement(hasRefPart, parentEvent.asStartElement(),\r
-                                               REF_PART);\r
-                               Reference<?> reference = createReference(state, refMap, next);\r
-                               return reference;\r
-                       } else if (isStartingElement(next, REF_PART)) {\r
-                               handleRefPart(state, reader, next, refMap);\r
-                               hasRefPart = true;\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               // TODO handle missing end element\r
-               throw new IllegalStateException("<Reference> has no closing tag");\r
-       }\r
-\r
-       private void handleHomotypes(MarkupImportState state, XMLEventReader reader, StartElement parentEvent)\r
-                       throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-\r
-               HomotypicalGroup homotypicalGroup = null;\r
-\r
-               boolean hasNom = false;\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (next.isEndElement()) {\r
-                               if (isMyEndingElement(next, parentEvent)) {\r
-                                       checkMandatoryElement(hasNom, parentEvent, NOM);\r
-                                       return;\r
-                               } else {\r
-                                       if (isEndingElement(next, NAME_TYPE)) {\r
-                                               state.setNameType(false);\r
-                                       } else if (isEndingElement(next, NOTES)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else {\r
-                                               handleUnexpectedEndElement(next.asEndElement());\r
-                                       }\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, NOM)) {\r
-                                       NonViralName<?> name = handleNom(state, reader, next, homotypicalGroup);\r
-                                       homotypicalGroup = name.getHomotypicalGroup();\r
-                                       hasNom = true;\r
-                               } else if (isStartingElement(next, NAME_TYPE)) {\r
-                                       state.setNameType(true);\r
-                                       handleNameType(state, reader, next, homotypicalGroup);\r
-                               } else if (isStartingElement(next, SPECIMEN_TYPE)) {\r
-                                       handleSpecimenType(state, reader, next, homotypicalGroup);\r
-                               } else if (isStartingElement(next, NOTES)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next);\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               // TODO handle missing end element\r
-               throw new IllegalStateException("Homotypes has no closing tag");\r
-\r
-       }\r
-\r
-       private void handleNameType(MarkupImportState state, XMLEventReader reader,\r
-                       XMLEvent parentEvent, HomotypicalGroup homotypicalGroup)\r
-                       throws XMLStreamException {\r
-               Map<String, Attribute> attributes = getAttributes(parentEvent);\r
-               String typeStatus = getAndRemoveAttributeValue(attributes, TYPE_STATUS);\r
-               checkNoAttributes(attributes, parentEvent);\r
-\r
-               NameTypeDesignationStatus status;\r
-               try {\r
-                       status = NameTypeParser.parseNameTypeStatus(typeStatus);\r
-               } catch (UnknownCdmTypeException e) {\r
-                       String message = "Type status could not be recognized: %s";\r
-                       message = String.format(message, typeStatus);\r
-                       fireWarningEvent(message, parentEvent, 4);\r
-                       status = null;\r
-               }\r
-\r
-               boolean hasNom = false;\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (next.isEndElement()) {\r
-                               if (isMyEndingElement(next, parentEvent)) {\r
-                                       checkMandatoryElement(hasNom, parentEvent.asStartElement(),\r
-                                                       NOM);\r
-                                       state.setNameType(false);\r
-                                       return;\r
-                               } else {\r
-                                       if (isEndingElement(next, ACCEPTED_NAME)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else {\r
-                                               handleUnexpectedEndElement(next.asEndElement());\r
-                                       }\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, NOM)) {\r
-                                       // TODO should we check if the type is always a species, is\r
-                                       // this a rule?\r
-                                       NonViralName<?> speciesName = handleNom(state, reader,\r
-                                                       next, null);\r
-                                       for (TaxonNameBase<?, ?> name : homotypicalGroup\r
-                                                       .getTypifiedNames()) {\r
-                                               name.addNameTypeDesignation(speciesName, null, null,\r
-                                                               null, status, false, false, false, false);\r
-                                       }\r
-                                       hasNom = true;\r
-                               } else if (isStartingElement(next, ACCEPTED_NAME)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next);\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               // TODO handle missing end element\r
-               throw new IllegalStateException("Homotypes has no closing tag");\r
-\r
-       }\r
-\r
-       private void handleSpecimenType(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent,\r
-                               HomotypicalGroup homotypicalGroup) throws XMLStreamException {\r
-               // attributes\r
-               Map<String, Attribute> attributes = getAttributes(parentEvent);\r
-               String typeStatus = getAndRemoveAttributeValue(attributes, TYPE_STATUS);\r
-               String notSeen = getAndRemoveAttributeValue(attributes, NOT_SEEN);\r
-               String unknown = getAndRemoveAttributeValue(attributes, UNKNOWN);\r
-               String notFound = getAndRemoveAttributeValue(attributes, NOT_FOUND);\r
-               String destroyed = getAndRemoveAttributeValue(attributes, DESTROYED);\r
-               String lost = getAndRemoveAttributeValue(attributes, LOST);\r
-               checkNoAttributes(attributes, parentEvent);\r
-               if (StringUtils.isNotEmpty(typeStatus)) {\r
-                       // TODO\r
-                       // currently not needed\r
-               } else if (StringUtils.isNotEmpty(notSeen)) {\r
-                       handleNotYetImplementedAttribute(attributes, NOT_SEEN);\r
-               } else if (StringUtils.isNotEmpty(unknown)) {\r
-                       handleNotYetImplementedAttribute(attributes, UNKNOWN);\r
-               } else if (StringUtils.isNotEmpty(notFound)) {\r
-                       handleNotYetImplementedAttribute(attributes, NOT_FOUND);\r
-               } else if (StringUtils.isNotEmpty(destroyed)) {\r
-                       handleNotYetImplementedAttribute(attributes, DESTROYED);\r
-               } else if (StringUtils.isNotEmpty(lost)) {\r
-                       handleNotYetImplementedAttribute(attributes, LOST);\r
-               }\r
-\r
-               NonViralName<?> firstName = null;\r
-               Set<TaxonNameBase> names = homotypicalGroup.getTypifiedNames();\r
-               if (names.isEmpty()) {\r
-                       String message = "There is no name in a homotypical group. Can't create the specimen type";\r
-                       fireWarningEvent(message, parentEvent, 8);\r
-               } else {\r
-                       firstName = CdmBase.deproxy(names.iterator().next(),NonViralName.class);\r
-               }\r
-\r
-               DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(DerivedUnitType.Specimen);\r
-               String text = "";\r
-               // elements\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (next.isEndElement()) {\r
-                               if (isMyEndingElement(next, parentEvent)) {\r
-                                       makeSpecimenType(state, facade, text, firstName, parentEvent);\r
-                                       return;\r
-                               } else {\r
-                                       if (isEndingElement(next, FULL_TYPE)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, TYPE_STATUS)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, ORIGINAL_DETERMINATION)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, SPECIMEN_TYPE)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, COLLECTION_AND_TYPE)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, CITATION)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, NOTES)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, ANNOTATION)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else {\r
-                                               handleUnexpectedEndElement(next.asEndElement());\r
-                                       }\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, FULL_TYPE)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                                       // homotypicalGroup = handleNom(state, reader, next, taxon,\r
-                                       // homotypicalGroup);\r
-                               } else if (isStartingElement(next, TYPE_STATUS)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, GATHERING)) {\r
-                                       handleGathering(state, reader, next, facade);\r
-                               } else if (isStartingElement(next, ORIGINAL_DETERMINATION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, SPECIMEN_TYPE)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, COLLECTION_AND_TYPE)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, CITATION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, NOTES)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, ANNOTATION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next);\r
-                               }\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               // TODO handle missing end element\r
-               throw new IllegalStateException("Specimen type has no closing tag"); \r
-       }\r
-\r
-       private void makeSpecimenType(MarkupImportState state, DerivedUnitFacade facade, String text, \r
-                       NonViralName name, XMLEvent parentEvent) {\r
-               text = text.trim();\r
-               // remove brackets\r
-               if (text.matches("^\\(.*\\)\\.?$")) {\r
-                       text = text.replaceAll("\\.", "");\r
-                       text = text.substring(1, text.length() - 1);\r
-               }\r
-               String[] split = text.split("[;,]");\r
-               for (String str : split) {\r
-                       str = str.trim();\r
-                       boolean addToAllNamesInGroup = true;\r
-                       TypeInfo typeInfo = makeSpecimenTypeTypeInfo(str, parentEvent);\r
-                       SpecimenTypeDesignationStatus typeStatus = typeInfo.status;\r
-                       Collection collection = createCollection(typeInfo.collectionString);\r
-\r
-                       // TODO improve cache strategy handling\r
-                       DerivedUnitBase typeSpecimen = facade.addDuplicate(collection,\r
-                                       null, null, null, null);\r
-                       typeSpecimen.setCacheStrategy(new DerivedUnitFacadeCacheStrategy());\r
-                       name.addSpecimenTypeDesignation((Specimen) typeSpecimen, typeStatus, null, null, null, false, addToAllNamesInGroup);\r
-               }\r
-       }\r
-\r
-       private Collection createCollection(String code) {\r
-               // TODO deduplicate\r
-               // TODO code <-> name\r
-               Collection result = Collection.NewInstance();\r
-               result.setCode(code);\r
-               return result;\r
-       }\r
-\r
-       private TypeInfo makeSpecimenTypeTypeInfo(String originalString, XMLEvent event) {\r
-               TypeInfo result = new TypeInfo();\r
-               String[] split = originalString.split("\\s+");\r
-               for (String str : split) {\r
-                       if (str.matches(SpecimenTypeParser.typeTypePattern)) {\r
-                               SpecimenTypeDesignationStatus status;\r
-                               try {\r
-                                       status = SpecimenTypeParser.parseSpecimenTypeStatus(str);\r
-                               } catch (UnknownCdmTypeException e) {\r
-                                       String message = "Specimen type status '%s' not recognized by parser";\r
-                                       message = String.format(message, str);\r
-                                       fireWarningEvent(message, event, 4);\r
-                                       status = null;\r
-                               }\r
-                               result.status = status;\r
-                       } else if (str.matches(SpecimenTypeParser.collectionPattern)) {\r
-                               result.collectionString = str;\r
-                       } else {\r
-                               String message = "Type part '%s' could not be recognized";\r
-                               message = String.format(message, str);\r
-                               fireWarningEvent(message, event, 2);\r
-                       }\r
-               }\r
-\r
-               return result;\r
-       }\r
-\r
-       \r
-       private void handleGathering(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent , DerivedUnitFacade facade) throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-               boolean hasCollector = false;\r
-               boolean hasFieldNum = false;\r
-\r
-               // elements\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (next.isEndElement()) {\r
-                               if (isMyEndingElement(next, parentEvent)) {\r
-                                       checkMandatoryElement(hasCollector,parentEvent.asStartElement(), COLLECTOR);\r
-                                       checkMandatoryElement(hasFieldNum,parentEvent.asStartElement(), FIELD_NUM);\r
-                                       return;\r
-                               } else {\r
-                                       if (isEndingElement(next, ALTERNATIVE_COLLECTOR)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, ALTERNATIVE_FIELD_NUM)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, COLLECTION_TYPE_STATUS)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, COLLECTION_AND_TYPE)) {\r
-                                               // NOT YET IMPLEMENTED , does this make sense here? \r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next,\r
-                                                       ALTERNATIVE_COLLECTION_TYPE_STATUS)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, SUB_COLLECTION)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, COLLECTION)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, DATES)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, NOTES)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else {\r
-                                               handleUnexpectedEndElement(next.asEndElement());\r
-                                       }\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, COLLECTOR)) {\r
-                                       hasCollector = true;\r
-                                       String collectorStr = getCData(state, reader, next);\r
-                                       AgentBase<?> collector = createCollector(collectorStr);\r
-                                       facade.setCollector(collector);\r
-                               } else if (isStartingElement(next, ALTERNATIVE_COLLECTOR)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, FIELD_NUM)) {\r
-                                       hasFieldNum = true;\r
-                                       String fieldNumStr = getCData(state, reader, next);\r
-                                       facade.setFieldNumber(fieldNumStr);\r
-                               } else if (isStartingElement(next, ALTERNATIVE_FIELD_NUM)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, COLLECTION_TYPE_STATUS)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, COLLECTION_AND_TYPE)) {  //does this make sense here?\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, ALTERNATIVE_COLLECTION_TYPE_STATUS)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, SUB_COLLECTION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, COLLECTION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, LOCALITY)) {\r
-                                       handleLocality(state, reader, next, facade);\r
-                               } else if (isStartingElement(next, DATES)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, NOTES)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next);\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               // TODO handle missing end element\r
-               throw new IllegalStateException("Collection has no closing tag");\r
-\r
-       }\r
-\r
-       private void handleLocality(MarkupImportState state, XMLEventReader reader,XMLEvent parentEvent, DerivedUnitFacade facade)throws XMLStreamException {\r
-               String classValue = getClassOnlyAttribute(parentEvent);\r
-               boolean isLocality = false;\r
-               NamedAreaLevel areaLevel = null;\r
-               if ("locality".equalsIgnoreCase(classValue)) {\r
-                       isLocality = true;\r
-               } else {\r
-                       areaLevel = makeNamedAreaLevel(state, classValue, parentEvent);\r
-               }\r
-\r
-               String text = "";\r
-               // elements\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (next.isEndElement()) {\r
-                               if (isMyEndingElement(next, parentEvent)) {\r
-                                       if (StringUtils.isNotBlank(text)) {\r
-                                               text = normalize(text);\r
-                                               if (isLocality) {\r
-                                                       facade.setLocality(text);\r
-                                               } else {\r
-                                                       text = CdmUtils.removeTrailingDot(text);\r
-                                                       NamedArea area = makeArea(state, text, areaLevel);\r
-                                                       facade.addCollectingArea(area);\r
-                                               }\r
-                                       }\r
-                                       // TODO\r
-                                       return;\r
-                               } else {\r
-                                       if (isEndingElement(next, ALTITUDE)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, COORDINATES)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, ANNOTATION)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else {\r
-                                               handleUnexpectedEndElement(next.asEndElement());\r
-                                       }\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, ALTITUDE)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                                       // homotypicalGroup = handleNom(state, reader, next, taxon,\r
-                                       // homotypicalGroup);\r
-                               } else if (isStartingElement(next, COORDINATES)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, ANNOTATION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next);\r
-                               }\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<SpecimenType> has no closing tag"); \r
-       }\r
-\r
-//     private NamedArea createArea(String text, NamedAreaLevel areaLevel, MarkupImportState state) {\r
-//             NamedArea area = NamedArea.NewInstance(text, text, null);\r
-//             area.setLevel(areaLevel);\r
-//             save(area, state);\r
-//             return area;\r
-//     }\r
-\r
-       private AgentBase<?> createCollector(String collectorStr) {\r
-               return createAuthor(collectorStr);\r
-       }\r
-\r
-       /**\r
-        * Creates the name defined by a nom tag. Adds it to the given homotypical\r
-        * group (if not null).\r
-        * \r
-        * @param state\r
-        * @param reader\r
-        * @param parentEvent\r
-        * @param homotypicalGroup\r
-        * @return\r
-        * @throws XMLStreamException\r
-        */\r
-       private NonViralName<?> handleNom(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent,\r
-                       HomotypicalGroup homotypicalGroup) throws XMLStreamException {\r
-               boolean isSynonym = false;\r
-               boolean isNameType = state.isNameType();\r
-               // attributes\r
-               String classValue = getClassOnlyAttribute(parentEvent);\r
-               NonViralName<?> name;\r
-               if (!isNameType && ACCEPTED.equalsIgnoreCase(classValue)) {\r
-                       isSynonym = false;\r
-                       name = createName(state, homotypicalGroup, isSynonym);\r
-               } else if (!isNameType && SYNONYM.equalsIgnoreCase(classValue)) {\r
-                       isSynonym = true;\r
-                       name = createName(state, homotypicalGroup, isSynonym);\r
-               } else if (isNameType && NAME_TYPE.equalsIgnoreCase(classValue)) {\r
-                       // TODO do we need to define the rank here?\r
-                       name = createNameByCode(state, null);\r
-               } else {\r
-                       fireUnexpectedAttributeValue(parentEvent, CLASS, classValue);\r
-                       name = createNameByCode(state, null);\r
-               }\r
-\r
-               Map<String, String> nameMap = new HashMap<String, String>();\r
-\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (next.isEndElement()) {\r
-                               if (isMyEndingElement(next, parentEvent)) {\r
-                                       // fill the name with all data gathered\r
-                                       fillName(state, nameMap, name, next);\r
-                                       return name;\r
-                               } else {\r
-                                       if (isEndingElement(next, FULL_NAME)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, HOMONYM)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, NOTES)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, ANNOTATION)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else {\r
-                                               handleUnexpectedEndElement(next.asEndElement());\r
-                                       }\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, FULL_NAME)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                                       // homotypicalGroup = handleNom(state, reader, next, taxon,\r
-                                       // homotypicalGroup);\r
-                               } else if (isStartingElement(next, NUM)) {\r
-                                       String num = getCData(state, reader, next);\r
-                                       num = num.replace(".", "");\r
-                                       num = num.replace(")", "");\r
-                                       if (StringUtils.isNotBlank(num)){\r
-                                               if (state.getCurrentTaxonNum() != null &&  ! state.getCurrentTaxonNum().equals(num) ){\r
-                                                       String message = "Taxontitle num and homotypes/nom/num differ ( %s <-> %s ). I use the later one.";\r
-                                                       message = String.format(message, state.getCurrentTaxonNum(), num);\r
-                                                       fireWarningEvent(message, next, 4);\r
-                                               }\r
-                                               state.setCurrentTaxonNum(num);\r
-                                       }\r
-                               } else if (isStartingElement(next, NAME)) {\r
-                                       handleName(state, reader, next, nameMap);\r
-                               } else if (isStartingElement(next, CITATION)) {\r
-                                       handleCitation(state, reader, next, name);\r
-                               } else if (isStartingElement(next, HOMONYM)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, NOTES)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, ANNOTATION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next);\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               // TODO handle missing end element\r
-               throw new IllegalStateException("Nom has no closing tag");\r
-\r
-       }\r
-\r
-       private void fillName(MarkupImportState state, Map<String, String> nameMap,\r
-                       NonViralName<?> name, XMLEvent event) {\r
-\r
-               // Ranks: family, subfamily, tribus, genus, subgenus, section,\r
-               // subsection, species, subspecies, variety, subvariety, forma\r
-               // infrank, paraut, author, infrparaut, infraut, status, notes\r
-\r
-               String infrank = getAndRemoveMapKey(nameMap, INFRANK);\r
-               String authorStr = getAndRemoveMapKey(nameMap, AUTHOR);\r
-               String paraut = getAndRemoveMapKey(nameMap, PARAUT);\r
-\r
-               String infrParAut = getAndRemoveMapKey(nameMap, INFRPARAUT);\r
-               String infrAut = getAndRemoveMapKey(nameMap, INFRAUT);\r
-\r
-               String statusStr = getAndRemoveMapKey(nameMap, STATUS);\r
-               String notes = getAndRemoveMapKey(nameMap, NOTES);\r
-\r
-               makeRankDecision(state, nameMap, name, event, infrank);\r
-\r
-               // test consistency of rank and authors\r
-               testRankAuthorConsistency(name, event, authorStr, paraut, infrParAut,infrAut);\r
-\r
-               // authors\r
-               makeNomenclaturalAuthors(name, event, authorStr, paraut, infrParAut,infrAut);\r
-\r
-               // status\r
-               // TODO handle pro parte, pro syn. etc.\r
-               if (StringUtils.isNotBlank(statusStr)) {\r
-                       String proPartePattern = "(pro parte|p.p.)";\r
-                       if (statusStr.matches(proPartePattern)) {\r
-                               state.setProParte(true);\r
-                       }\r
-                       try {\r
-                               // TODO handle trim earlier\r
-                               statusStr = statusStr.trim();\r
-                               NomenclaturalStatusType nomStatusType = NomenclaturalStatusType.getNomenclaturalStatusTypeByAbbreviation(statusStr);\r
-                               name.addStatus(NomenclaturalStatus.NewInstance(nomStatusType));\r
-                       } catch (UnknownCdmTypeException e) {\r
-                               String message = "Status '%s' could not be recognized";\r
-                               message = String.format(message, statusStr);\r
-                               fireWarningEvent(message, event, 4);\r
-                       }\r
-               }\r
-\r
-               // notes\r
-               if (StringUtils.isNotBlank(notes)) {\r
-                       handleNotYetImplementedAttributeValue(event, CLASS, NOTES);\r
-               }\r
-\r
-               return;\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param nameMap\r
-        * @param name\r
-        * @param event\r
-        * @param infrankStr\r
-        */\r
-       private void makeRankDecision(MarkupImportState state, Map<String, String> nameMap, \r
-                       NonViralName<?> name, XMLEvent event, String infrankStr) {\r
-               // TODO ranks\r
-               for (String key : nameMap.keySet()) {\r
-                       Rank rank = makeRank(state, key, false);\r
-                       if (rank == null) {\r
-                               handleNotYetImplementedAttributeValue(event, CLASS, key);\r
-                       } else {\r
-                               if (name.getRank() == null || rank.isLower(name.getRank())) {\r
-                                       name.setRank(rank);\r
-                               }\r
-                               String value = nameMap.get(key);\r
-                               if (rank.isSupraGeneric() || rank.isGenus()) {\r
-                                       name.setGenusOrUninomial(toFirstCapital(value));\r
-                               } else if (rank.isInfraGeneric()) {\r
-                                       name.setInfraGenericEpithet(toFirstCapital(value));\r
-                               } else if (rank.isSpecies()) {\r
-                                       if (isFirstCapitalWord(value)){ //capital letters are allowed for species epithet in case of person names (e.g. Manilkara Welwitschii Engl.\r
-                                               name.setSpecificEpithet(value);\r
-                                       }else{\r
-                                               name.setSpecificEpithet(value.toLowerCase());\r
-                                       }\r
-                               } else if (rank.isInfraSpecific()) {\r
-                                       name.setInfraSpecificEpithet(value.toLowerCase());\r
-                               } else {\r
-                                       String message = "Invalid rank '%s'. Can't decide which epithet to fill with '%s'";\r
-                                       message = String.format(message, rank.getTitleCache(),value);\r
-                                       fireWarningEvent(message, event, 4);\r
-                               }\r
-                       }\r
-\r
-               }\r
-               // handle given infrank marker\r
-               if (StringUtils.isNotBlank(infrankStr)) {\r
-                       Rank infRank = makeRank(state, infrankStr, true);\r
-\r
-                       if (infRank == null) {\r
-                               String message = "Infrank '%s' rank not recognized";\r
-                               message = String.format(message, infrankStr);\r
-                               fireWarningEvent(message, event, 4);\r
-                       } else {\r
-                               if (name.getRank() == null) {\r
-                                       name.setRank(infRank);\r
-                               } else if (infRank.isLower(name.getRank())) {\r
-                                       String message = "InfRank '%s' is lower than existing rank ";\r
-                                       message = String.format(message, infrankStr);\r
-                                       fireWarningEvent(message, event, 2);\r
-                                       name.setRank(infRank);\r
-                               } else if (infRank.equals(name.getRank())) {\r
-                                       // nothing\r
-                               } else {\r
-                                       String message = "InfRank '%s' is higher than existing rank ";\r
-                                       message = String.format(message, infrankStr);\r
-                                       fireWarningEvent(message, event, 2);\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       private String toFirstCapital(String value) {\r
-               if (StringUtils.isBlank(value)){\r
-                       return value;\r
-               }else{\r
-                       String result = "";\r
-                       value = value.trim();\r
-                       result += value.trim().substring(0,1).toUpperCase();\r
-                       if (value.length()>1){\r
-                               result += value.substring(1).toLowerCase();\r
-                       }\r
-                       return result;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * @param name\r
-        * @param event\r
-        * @param authorStr\r
-        * @param paraut\r
-        * @param infrParAut\r
-        * @param infrAut\r
-        */\r
-       private void makeNomenclaturalAuthors(NonViralName name, XMLEvent event,\r
-                               String authorStr, String paraut, String infrParAut, String infrAut) {\r
-               if (name.getRank() != null && name.getRank().isInfraSpecific()) {\r
-                       if (StringUtils.isNotBlank(infrAut)) {\r
-                               INomenclaturalAuthor[] authorAndEx = authorAndEx(infrAut, event);\r
-                               name.setCombinationAuthorTeam(authorAndEx[0]);\r
-                               name.setExCombinationAuthorTeam(authorAndEx[1]);\r
-                       }\r
-                       if (StringUtils.isNotBlank(infrParAut)) {\r
-                               INomenclaturalAuthor[] authorAndEx = authorAndEx(infrParAut, event);\r
-                               name.setBasionymAuthorTeam(authorAndEx[0]);\r
-                               name.setExBasionymAuthorTeam(authorAndEx[1]);\r
-                       }\r
-               } else {\r
-                       if (name.getRank() == null){\r
-                               String message = "No rank defined. Check correct usage of authors!";\r
-                               fireWarningEvent(message, event, 4);\r
-                               if (isNotBlank(infrParAut) || isNotBlank(infrAut)){\r
-                                       authorStr = infrAut;\r
-                                       paraut = infrParAut;\r
-                               }\r
-                       }\r
-                       if (StringUtils.isNotBlank(authorStr)) {\r
-                               INomenclaturalAuthor[] authorAndEx = authorAndEx(authorStr, event);\r
-                               name.setCombinationAuthorTeam(authorAndEx[0]);\r
-                               name.setExCombinationAuthorTeam(authorAndEx[1]);\r
-                       }\r
-                       if (StringUtils.isNotBlank(paraut)) {\r
-                               INomenclaturalAuthor[] authorAndEx = authorAndEx(paraut, event);\r
-                               name.setBasionymAuthorTeam(authorAndEx[0]);\r
-                               name.setExBasionymAuthorTeam(authorAndEx[1]);\r
-                       }\r
-               }\r
-       }\r
-\r
-       private TeamOrPersonBase[] authorAndEx(String authorAndEx, XMLEvent xmlEvent) {\r
-               authorAndEx = authorAndEx.trim();\r
-               TeamOrPersonBase[] result = new TeamOrPersonBase[2];\r
-\r
-               String[] split = authorAndEx.split("\\sex\\s");\r
-               if (split.length > 2) {\r
-                       String message = "There is more then 1 ' ex ' in author string. Can't separate author and ex-author";\r
-                       fireWarningEvent(message, xmlEvent, 4);\r
-                       result[0] = createAuthor(authorAndEx);\r
-               } else if (split.length == 2) {\r
-                       result[0] = createAuthor(split[1]);\r
-                       result[1] = createAuthor(split[0]);\r
-               } else {\r
-                       result[0] = createAuthor(split[0]);\r
-               }\r
-               return result;\r
-       }\r
-\r
-       /**\r
-        * Tests if the names rank is consistent with the given author strings.\r
-        * @param name\r
-        * @param event\r
-        * @param authorStr\r
-        * @param paraut\r
-        * @param infrParAut\r
-        * @param infrAut\r
-        */\r
-       private void testRankAuthorConsistency(NonViralName name, XMLEvent event, \r
-                               String authorStr, String paraut, String infrParAut, String infrAut) {\r
-               if (name.getRank() == null){\r
-                       return;\r
-               }\r
-               if (name.getRank().isInfraSpecific()) {\r
-                       if (StringUtils.isBlank(infrParAut)\r
-                                       && StringUtils.isBlank(infrAut)    //was isNotBlank before 29.5.2012\r
-                                       && (StringUtils.isNotBlank(paraut) || StringUtils.isNotBlank(authorStr)) \r
-                                       && ! name.isAutonym()) {\r
-                               String message = "Rank is infraspecicific but has only specific or higher author(s)";\r
-                               fireWarningEvent(message, event, 4);\r
-                       }\r
-               } else {\r
-                       // is not infraspecific\r
-                       if (StringUtils.isNotBlank(infrParAut)  || StringUtils.isNotBlank(infrAut)) {\r
-                               String message = "Rank is not infraspecicific but name has infra author(s)";\r
-                               fireWarningEvent(message, event, 4);\r
-                       }\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Returns the (empty) name with the correct homotypical group depending on\r
-        * the taxon status. Throws NPE if no currentTaxon is set in state.\r
-        * \r
-        * @param state\r
-        * @param homotypicalGroup\r
-        * @param isSynonym\r
-        * @return\r
-        */\r
-       private NonViralName<?> createName(MarkupImportState state,\r
-                       HomotypicalGroup homotypicalGroup, boolean isSynonym) {\r
-               NonViralName<?> name;\r
-               Taxon taxon = state.getCurrentTaxon();\r
-               if (isSynonym) {\r
-                       Rank defaultRank = Rank.SPECIES(); // can be any\r
-                       name = createNameByCode(state, defaultRank);\r
-                       if (homotypicalGroup != null) {\r
-                               name.setHomotypicalGroup(homotypicalGroup);\r
-                       }\r
-                       SynonymRelationshipType synonymType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();\r
-                       if (taxon.getHomotypicGroup().equals(homotypicalGroup)) {\r
-                               synonymType = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();\r
-                       }\r
-                       taxon.addSynonymName(name, synonymType);\r
-               } else {\r
-                       name = CdmBase.deproxy(taxon.getName(), NonViralName.class);\r
-               }\r
-               return name;\r
-       }\r
-\r
-       private void handleName(MarkupImportState state, XMLEventReader reader, \r
-                       XMLEvent parentEvent, Map<String, String> nameMap)\r
-                       throws XMLStreamException {\r
-               String classValue = getClassOnlyAttribute(parentEvent);\r
-\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               nameMap.put(classValue, text);\r
-                               return;\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, ANNOTATION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next.asStartElement());\r
-                               }\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-                       } else {\r
-                               handleUnexpectedEndElement(next.asEndElement());\r
-                       }\r
-               }\r
-               throw new IllegalStateException("name has no closing tag");\r
-\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param classValue\r
-        * @param byAbbrev\r
-        * @return\r
-        */\r
-       private Rank makeRank(MarkupImportState state, String value,\r
-                       boolean byAbbrev) {\r
-               Rank rank = null;\r
-               if (StringUtils.isBlank(value)) {\r
-                       return null;\r
-               }\r
-               try {\r
-                       boolean useUnknown = true;\r
-                       NomenclaturalCode nc = makeNomenclaturalCode(state);\r
-                       if (byAbbrev) {\r
-                               rank = Rank.getRankByAbbreviation(value, nc, useUnknown);\r
-                       } else {\r
-                               rank = Rank.getRankByEnglishName(value, nc, useUnknown);\r
-                       }\r
-                       if (rank.equals(Rank.UNKNOWN_RANK())) {\r
-                               rank = null;\r
-                       }\r
-               } catch (UnknownCdmTypeException e) {\r
-                       // doNothing\r
-               }\r
-               return rank;\r
-       }\r
-\r
-       // public void handleNameNotRank(MarkupImportState state, XMLEventReader\r
-       // reader, XMLEvent parentEvent, String classValue, NonViralName name)\r
-       // throws XMLStreamException {\r
-       // if (ACCEPTED.equalsIgnoreCase(classValue)){\r
-       // }else if (SYNONYM.equalsIgnoreCase(classValue)){\r
-       // }else{\r
-       // //TODO Not yet implemented\r
-       // handleNotYetImplementedAttributeValue(parentEvent, CLASS, classValue);\r
-       // }\r
-       // }\r
-\r
-       private void handleCitation(MarkupImportState state, XMLEventReader reader,     XMLEvent parentEvent, NonViralName name) throws XMLStreamException {\r
-               String classValue = getClassOnlyAttribute(parentEvent);\r
-\r
-               state.setCitation(true);\r
-               boolean hasRefPart = false;\r
-               Map<String, String> refMap = new HashMap<String, String>();\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               checkMandatoryElement(hasRefPart, parentEvent.asStartElement(),\r
-                                               REF_PART);\r
-                               Reference<?> reference = createReference(state, refMap, next);\r
-                               String microReference = refMap.get(DETAILS);\r
-                               doCitation(state, name, classValue, reference, microReference,\r
-                                               parentEvent);\r
-                               state.setCitation(false);\r
-                               return;\r
-                       } else if (isStartingElement(next, REF_PART)) {\r
-                               handleRefPart(state, reader, next, refMap);\r
-                               hasRefPart = true;\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("Citation has no closing tag");\r
-\r
-       }\r
-\r
-       private void handleRefPart(MarkupImportState state, XMLEventReader reader,XMLEvent parentEvent, Map<String, String> refMap) throws XMLStreamException {\r
-               String classValue = getClassOnlyAttribute(parentEvent);\r
-\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               refMap.put(classValue, text);\r
-                               return;\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, ANNOTATION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, ITALICS)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, BOLD)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next.asStartElement());\r
-                               }\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-                       } else {\r
-                               handleUnexpectedEndElement(next.asEndElement());\r
-                       }\r
-               }\r
-               throw new IllegalStateException("RefPart has no closing tag");\r
-\r
-       }\r
-\r
-       private Reference<?> createReference(MarkupImportState state, Map<String, String> refMap, XMLEvent parentEvent) {\r
-               // TODO\r
-               Reference<?> reference;\r
-\r
-               String type = getAndRemoveMapKey(refMap, PUBTYPE);\r
-               String authorStr = getAndRemoveMapKey(refMap, AUTHOR);\r
-               String titleStr = getAndRemoveMapKey(refMap, PUBTITLE);\r
-               String titleCache = getAndRemoveMapKey(refMap, PUBFULLNAME);\r
-               String volume = getAndRemoveMapKey(refMap, VOLUME);\r
-               String edition = getAndRemoveMapKey(refMap, EDITION);\r
-               String editors = getAndRemoveMapKey(refMap, EDITORS);\r
-               String year = getAndRemoveMapKey(refMap, YEAR);\r
-               String pubName = getAndRemoveMapKey(refMap, PUBNAME);\r
-               String pages = getAndRemoveMapKey(refMap, PAGES);\r
-\r
-               if (state.isCitation()) {\r
-                       if (volume != null || "journal".equalsIgnoreCase(type)) {\r
-                               IArticle article = ReferenceFactory.newArticle();\r
-                               if (pubName != null) {\r
-                                       IJournal journal = ReferenceFactory.newJournal();\r
-                                       journal.setTitle(pubName);\r
-                                       article.setInJournal(journal);\r
-                               }\r
-                               reference = (Reference<?>) article;\r
-\r
-                       } else {\r
-                               // TODO\r
-                               if (pubName != null){\r
-                                       reference  = ReferenceFactory.newBookSection();\r
-                               }else{\r
-                                       reference = ReferenceFactory.newBook();\r
-                               }\r
-                       }\r
-                       // TODO use existing author from name or before\r
-                       TeamOrPersonBase<?> author = createAuthor(authorStr);\r
-                       reference.setAuthorTeam(author);\r
-\r
-                       reference.setTitle(titleStr);\r
-                       if (StringUtils.isNotBlank(titleCache)) {\r
-                               reference.setTitleCache(titleCache, true);\r
-                       }\r
-                       reference.setEdition(edition);\r
-                       reference.setEditor(editors);\r
-\r
-                       if (pubName != null) {\r
-                               Reference<?> inReference;\r
-                               if (reference.getType().equals(ReferenceType.Article)) {\r
-                                       inReference = ReferenceFactory.newJournal();\r
-                               } else {\r
-                                       inReference = ReferenceFactory.newGeneric();\r
-                               }\r
-                               inReference.setTitle(pubName);\r
-                               reference.setInReference(inReference);\r
-                       }\r
-\r
-                       \r
-               } else {  //no citation\r
-                       if (volume != null || "journal".equalsIgnoreCase(type)) {\r
-                               IArticle article = ReferenceFactory.newArticle();\r
-                               if (pubName != null) {\r
-                                       IJournal journal = ReferenceFactory.newJournal();\r
-                                       journal.setTitle(pubName);\r
-                                       article.setInJournal(journal);\r
-                               }\r
-                               reference = (Reference<?>) article;\r
-\r
-                       } else {\r
-                               Reference<?> bookOrPartOf = ReferenceFactory.newGeneric();\r
-                               reference = bookOrPartOf;\r
-                       }\r
-\r
-                       // TODO type\r
-                       TeamOrPersonBase<?> author = createAuthor(authorStr);\r
-                       reference.setAuthorTeam(author);\r
-\r
-                       reference.setTitle(titleStr);\r
-                       if (StringUtils.isNotBlank(titleCache)) {\r
-                               reference.setTitleCache(titleCache, true);\r
-                       }\r
-                       reference.setEdition(edition);\r
-                       reference.setEditor(editors);\r
-\r
-                       if (pubName != null) {\r
-                               Reference<?> inReference;\r
-                               if (reference.getType().equals(ReferenceType.Article)) {\r
-                                       inReference = ReferenceFactory.newJournal();\r
-                               } else {\r
-                                       inReference = ReferenceFactory.newGeneric();\r
-                               }\r
-                               inReference.setTitle(pubName);\r
-                               reference.setInReference(inReference);\r
-                       }\r
-               }\r
-               reference.setVolume(volume);\r
-               reference.setDatePublished(TimePeriod.parseString(year));\r
-               //TODO check if this is handled correctly in FM markup\r
-               reference.setPages(pages);\r
-\r
-               // TODO\r
-               String[] unhandledList = new String[]{ALTERNATEPUBTITLE, ISSUE, NOTES, STATUS};\r
-               for (String unhandled : unhandledList){\r
-                       String value = getAndRemoveMapKey(refMap, unhandled);\r
-                       if (isNotBlank(value)){\r
-                               this.handleNotYetImplementedAttributeValue(parentEvent, CLASS, unhandled);\r
-                       }\r
-               }\r
-               \r
-               for (String key : refMap.keySet()) {\r
-                       if (!DETAILS.equalsIgnoreCase(key)) {\r
-                               this.fireUnexpectedAttributeValue(parentEvent, CLASS, key);\r
-                       }\r
-               }\r
-\r
-               return reference;\r
-       }\r
-\r
-       private TeamOrPersonBase createAuthor(String authorTitle) {\r
-               // TODO atomize and also use by name creation\r
-               TeamOrPersonBase result = Team.NewTitledInstance(authorTitle,\r
-                               authorTitle);\r
-               return result;\r
-       }\r
-\r
-       private String getAndRemoveMapKey(Map<String, String> map, String key) {\r
-               String result = map.get(key);\r
-               map.remove(key);\r
-               if (result != null) {\r
-                       result = normalize(result);\r
-               }\r
-               return StringUtils.stripToNull(result);\r
-       }\r
-\r
-       private void doCitation(MarkupImportState state, NonViralName name,\r
-                       String classValue, Reference reference, String microCitation,\r
-                       XMLEvent parentEvent) {\r
-               if (PUBLICATION.equalsIgnoreCase(classValue)) {\r
-                       name.setNomenclaturalReference(reference);\r
-                       name.setNomenclaturalMicroReference(microCitation);\r
-               } else if (USAGE.equalsIgnoreCase(classValue)) {\r
-                       Taxon taxon = state.getCurrentTaxon();\r
-                       TaxonDescription td = getTaxonDescription(taxon, state\r
-                                       .getConfig().getSourceReference(), false, true);\r
-                       TextData citation = TextData.NewInstance(Feature.CITATION());\r
-                       // TODO name used in source\r
-                       citation.addSource(null, null, reference, microCitation);\r
-                       td.addElement(citation);\r
-               } else if (TYPE.equalsIgnoreCase(classValue)) {\r
-                       handleNotYetImplementedAttributeValue(parentEvent, CLASS,\r
-                                       classValue);\r
-               } else {\r
-                       // TODO Not yet implemented\r
-                       handleNotYetImplementedAttributeValue(parentEvent, CLASS,\r
-                                       classValue);\r
-               }\r
-       }\r
-\r
-       private void handleFeature(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               String classValue = getClassOnlyAttribute(parentEvent);\r
-               Feature feature = makeFeature(classValue, state, parentEvent);\r
-               Taxon taxon = state.getCurrentTaxon();\r
-               TaxonDescription taxonDescription = getTaxonDescription(taxon, state.getConfig().getSourceReference(), NO_IMAGE_GALLERY, CREATE_NEW);\r
-               // TextData figureHolderTextData = null; //for use with one TextData for\r
-               // all figure only\r
-\r
-               boolean isDescription = feature.equals(Feature.DESCRIPTION());\r
-               DescriptionElementBase lastDescriptionElement = null;\r
-               \r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               return;\r
-                       } else if (isEndingElement(next, DISTRIBUTION_LIST) || isEndingElement(next, HABITAT_LIST)) { \r
-                               // only handle list elements\r
-                       } else if (isStartingElement(next, HEADING)) {\r
-                               makeFeatureHeading(state, reader, classValue, feature, next);\r
-                       } else if (isStartingElement(next, WRITER)) {\r
-                               makeFeatureWriter(state, reader, feature, taxon, next);\r
-//                     } else if (isStartingElement(next, DISTRIBUTION_LOCALITY)) {\r
-//                             if (!feature.equals(Feature.DISTRIBUTION())) {\r
-//                                     String message = "Distribution locality only allowed for feature of type 'distribution'";\r
-//                                     fireWarningEvent(message, next, 4);\r
-//                             }\r
-//                             handleDistributionLocality(state, reader, next);\r
-                       } else if (isStartingElement(next, DISTRIBUTION_LIST) || isStartingElement(next, HABITAT_LIST)) {\r
-                               // only handle single list elements\r
-                       } else if (isStartingElement(next, HABITAT)) {\r
-                               if (!(feature.equals(Feature.HABITAT())\r
-                                               || feature.equals(Feature.HABITAT_ECOLOGY()) \r
-                                               || feature.equals(Feature.ECOLOGY()))) {\r
-                                       String message = "Habitat only allowed for feature of type 'habitat','habitat ecology' or 'ecology'";\r
-                                       fireWarningEvent(message, next, 4);\r
-                               }\r
-                               handleHabitat(state, reader, next);\r
-                       } else if (isStartingElement(next, CHAR)) {\r
-                               TextData textData = handleChar(state, reader, next);\r
-                               taxonDescription.addElement(textData);\r
-                       } else if (isStartingElement(next, STRING)) {\r
-                               lastDescriptionElement = makeFeatureString(state, reader,feature, taxonDescription, lastDescriptionElement,next);\r
-                       } else if (isStartingElement(next, FIGURE_REF)) {\r
-                               lastDescriptionElement = makeFeatureFigureRef(state, reader, taxonDescription, isDescription, lastDescriptionElement, next);\r
-                       } else if (isStartingElement(next, REFERENCES)) {\r
-                               // TODO details/microcitation ??\r
-\r
-                               List<Reference<?>> refs = handleReferences(state, reader, next);\r
-                               if (!refs.isEmpty()) {\r
-                                       // TODO\r
-                                       Reference<?> descriptionRef = state.getConfig().getSourceReference();\r
-                                       TaxonDescription description = getTaxonDescription(taxon, descriptionRef, false, true);\r
-                                       TextData featurePlaceholder = docImport.getFeaturePlaceholder(state, description, feature, true);\r
-                                       for (Reference<?> citation : refs) {\r
-                                               featurePlaceholder.addSource(null, null, citation, null);\r
-                                       }\r
-                               } else {\r
-                                       String message = "No reference found in references";\r
-                                       fireWarningEvent(message, next, 6);\r
-                               }\r
-                       } else if (isStartingElement(next, NUM)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, NUM)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<Feature> has no closing tag");\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param reader\r
-        * @param taxonDescription\r
-        * @param isDescription\r
-        * @param lastDescriptionElement\r
-        * @param next\r
-        * @return\r
-        * @throws XMLStreamException\r
-        */\r
-       private DescriptionElementBase makeFeatureFigureRef(MarkupImportState state, XMLEventReader reader,TaxonDescription taxonDescription, \r
-                                       boolean isDescription, DescriptionElementBase lastDescriptionElement, XMLEvent next)throws XMLStreamException {\r
-               FigureDataHolder figureHolder = handleFigureRef(state, reader, next);\r
-               Feature figureFeature = getFeature(state,MarkupTransformer.uuidFigures, "Figures", "Figures", "Fig.",null);\r
-               if (isDescription) {\r
-                       TextData figureHolderTextData = null;\r
-                       // if (figureHolderTextData == null){\r
-                       figureHolderTextData = TextData.NewInstance(figureFeature);\r
-                       if (StringUtils.isNotBlank(figureHolder.num)) {\r
-                               String annotationText = "<num>" + figureHolder.num.trim()\r
-                                               + "</num>";\r
-                               Annotation annotation = Annotation.NewInstance(annotationText,\r
-                                               AnnotationType.TECHNICAL(), Language.DEFAULT());\r
-                               figureHolderTextData.addAnnotation(annotation);\r
-                       }\r
-                       if (StringUtils.isNotBlank(figureHolder.figurePart)) {\r
-                               String annotationText = "<figurePart>"+ figureHolder.figurePart.trim() + "</figurePart>";\r
-                               Annotation annotation = Annotation.NewInstance(annotationText,AnnotationType.EDITORIAL(), Language.DEFAULT());\r
-                               figureHolderTextData.addAnnotation(annotation);\r
-                       }\r
-                       // if (StringUtils.isNotBlank(figureText)){\r
-                       // figureHolderTextData.putText(Language.DEFAULT(), figureText);\r
-                       // }\r
-                       taxonDescription.addElement(figureHolderTextData);\r
-                       // }\r
-                       registerFigureDemand(state, figureHolderTextData, figureHolder.ref);\r
-               } else {\r
-                       if (lastDescriptionElement == null) {\r
-                               String message = "No description element created yet that can be referred by figure. Create new TextData instead";\r
-                               fireWarningEvent(message, next, 4);\r
-                               lastDescriptionElement = TextData.NewInstance(figureFeature);\r
-                               taxonDescription.addElement(lastDescriptionElement);\r
-                       }\r
-                       registerFigureDemand(state, lastDescriptionElement,\r
-                                       figureHolder.ref);\r
-               }\r
-               return lastDescriptionElement;\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param reader\r
-        * @param feature\r
-        * @param taxonDescription\r
-        * @param lastDescriptionElement\r
-        * @param distributionList \r
-        * @param next\r
-        * @return\r
-        * @throws XMLStreamException\r
-        */\r
-       private DescriptionElementBase makeFeatureString(MarkupImportState state,XMLEventReader reader, Feature feature, \r
-                               TaxonDescription taxonDescription, DescriptionElementBase lastDescriptionElement, XMLEvent next) throws XMLStreamException {\r
-               //for specimen only\r
-               if (feature.equals(Feature.SPECIMEN()) || feature.equals(Feature.MATERIALS_EXAMINED())){\r
-                       \r
-                       List<DescriptionElementBase> specimens = handleMaterialsExamined(state, reader, next);\r
-                       for (DescriptionElementBase specimen : specimens){\r
-                               taxonDescription.addElement(specimen);\r
-                               lastDescriptionElement = specimen;\r
-                       }\r
-                       return lastDescriptionElement;\r
-               }\r
-               \r
-               //others\r
-               Map<String, String> subheadingMap = handleString(state, reader, next, feature);\r
-               for (String subheading : subheadingMap.keySet()) {\r
-                       Feature subheadingFeature = feature;\r
-                       if (StringUtils.isNotBlank(subheading) && subheadingMap.size() > 1) {\r
-                               subheadingFeature = makeFeature(subheading, state, next);\r
-                       }\r
-                       if (feature.equals(Feature.COMMON_NAME())){\r
-                               List<DescriptionElementBase> commonNames = makeVernacular(state, subheading, subheadingMap.get(subheading));\r
-                               for (DescriptionElementBase commonName : commonNames){\r
-                                       taxonDescription.addElement(commonName);\r
-                                       lastDescriptionElement = commonName;\r
-                               }\r
-                       }else {\r
-                               TextData textData = TextData.NewInstance(subheadingFeature);\r
-                               textData.putText(Language.DEFAULT(), subheadingMap.get(subheading));\r
-                               taxonDescription.addElement(textData);\r
-                               lastDescriptionElement = textData;\r
-                               // TODO how to handle figures when these data are split in\r
-                               // subheadings\r
-                       }\r
-               }\r
-               return lastDescriptionElement;\r
-       }\r
-\r
-       private List<DescriptionElementBase> makeVernacular(MarkupImportState state, String subheading, String commonNameString) throws XMLStreamException {\r
-               List<DescriptionElementBase> result = new ArrayList<DescriptionElementBase>();\r
-               String[] splits = commonNameString.split(",");\r
-               for (String split : splits){\r
-                       split = split.trim();\r
-                       if (! split.matches(".*\\(.*\\)\\.?")){\r
-                               fireWarningEvent("Common name string '"+split+"' does not match given pattern", state.getReader().peek(), 4);\r
-                       }\r
-                       \r
-                       String name = split.replaceAll("\\(.*\\)", "").replace(".", "").trim();\r
-                       String languageStr = split.replaceFirst(".*\\(", "").replaceAll("\\)\\.?", "").trim();\r
-                       \r
-                       Language language = null;\r
-                       if (StringUtils.isNotBlank(languageStr)){\r
-                               try {\r
-                                       UUID langUuid = state.getTransformer().getLanguageUuid(languageStr);\r
-                                       TermVocabulary<?> voc = null;\r
-                                       language = getLanguage(state, langUuid, languageStr, languageStr, null, voc);\r
-                                       if (language == null){\r
-                                               logger.warn("Language " + languageStr + " not recognized by transformer");\r
-                                       }\r
-                               } catch (UndefinedTransformerMethodException e) {\r
-                                       throw new RuntimeException(e);\r
-                               }\r
-                       }\r
-                       NamedArea area = null;\r
-                       CommonTaxonName commonTaxonName = CommonTaxonName.NewInstance(name, language, area);\r
-                       result.add(commonTaxonName);\r
-               }\r
-               \r
-               return result;\r
-       }\r
-       \r
-       private List<DescriptionElementBase>  handleMaterialsExamined(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               List<DescriptionElementBase> result = new ArrayList<DescriptionElementBase>();\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               if (result.isEmpty()){\r
-                                       fireWarningEvent("Materials examined created empty Individual Associations list", parentEvent, 4);\r
-                               }\r
-                               return result;\r
-                       } else if (isStartingElement(next, SUB_HEADING)) {\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isStartingElement(next, BR)) {\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isStartingElement(next, GATHERING)) {\r
-                               DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(DerivedUnitType.DerivedUnit.DerivedUnit);\r
-                               handleGathering(state, reader, next, facade);\r
-                               SpecimenOrObservationBase<?> specimen;\r
-                               if (facade.innerDerivedUnit() != null){\r
-                                       specimen = facade.innerDerivedUnit();\r
-                               }else{\r
-                                       specimen = facade.innerFieldObservation();\r
-                               }\r
-                               IndividualsAssociation individualsAssociation = IndividualsAssociation.NewInstance();\r
-                               individualsAssociation.setAssociatedSpecimenOrObservation(specimen);\r
-                               result.add(individualsAssociation);\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<String> has no closing tag");\r
-               \r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param reader\r
-        * @param feature\r
-        * @param taxon\r
-        * @param next\r
-        * @throws XMLStreamException\r
-        */\r
-       private void makeFeatureWriter(MarkupImportState state,XMLEventReader reader, Feature feature, Taxon taxon, XMLEvent next) throws XMLStreamException {\r
-               WriterDataHolder writer = handleWriter(state, reader, next);\r
-               if (isNotBlank(writer.writer)) {\r
-                       // TODO\r
-                       Reference<?> ref = state.getConfig().getSourceReference();\r
-                       TaxonDescription description = getTaxonDescription(taxon, ref,\r
-                                       false, true);\r
-                       TextData featurePlaceholder = docImport.getFeaturePlaceholder(state,\r
-                                       description, feature, true);\r
-                       featurePlaceholder.addAnnotation(writer.annotation);\r
-                       registerFootnotes(state, featurePlaceholder, writer.footnotes);\r
-               } else {\r
-                       String message = "Writer element is empty";\r
-                       fireWarningEvent(message, next, 4);\r
-               }\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param reader\r
-        * @param classValue\r
-        * @param feature\r
-        * @param next\r
-        * @throws XMLStreamException\r
-        */\r
-       private void makeFeatureHeading(MarkupImportState state, XMLEventReader reader, String classValue, Feature feature, XMLEvent next) throws XMLStreamException {\r
-               String heading = handleHeading(state, reader, next);\r
-               if (StringUtils.isNotBlank(heading)) {\r
-                       if (!heading.equalsIgnoreCase(classValue)) {\r
-                               try {\r
-                                       if (!feature.equals(state.getTransformer().getFeatureByKey(\r
-                                                       heading))) {\r
-                                               UUID headerFeatureUuid = state.getTransformer()\r
-                                                               .getFeatureUuid(heading);\r
-                                               if (!feature.getUuid().equals(headerFeatureUuid)) {\r
-                                                       String message = "Feature heading '%s' differs from feature class '%s' and can not be transformed to feature";\r
-                                                       message = String.format(message, heading,\r
-                                                                       classValue);\r
-                                                       fireWarningEvent(message, next, 1);\r
-                                               }\r
-                                       }\r
-                               } catch (UndefinedTransformerMethodException e) {\r
-                                       throw new RuntimeException(e);\r
-                               }\r
-                       } else {\r
-                               // do nothing\r
-                       }\r
-               }\r
-       }\r
-\r
-       private List<Reference<?>> handleReferences(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               // attributes\r
-               Map<String, Attribute> attributes = getAttributes(parentEvent);\r
-               String bibliography = getAndRemoveAttributeValue(attributes,\r
-                               BIBLIOGRAPHY);\r
-               String serialsAbbreviations = getAndRemoveAttributeValue(attributes,\r
-                               SERIALS_ABBREVIATIONS);\r
-               if (isNotBlank(bibliography) || isNotBlank(serialsAbbreviations)) {\r
-                       String message = "Attributes not yet implemented for <references>";\r
-                       fireWarningEvent(message, parentEvent, 4);\r
-               }\r
-\r
-               List<Reference<?>> result = new ArrayList<Reference<?>>();\r
-\r
-               // elements\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (next.isEndElement()) {\r
-                               if (isMyEndingElement(next, parentEvent)) {\r
-                                       return result;\r
-                               } else {\r
-                                       if (isEndingElement(next, HEADING)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, WRITER)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, FOOTNOTE)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, STRING)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else if (isEndingElement(next, REF_NUM)) {\r
-                                               // NOT YET IMPLEMENTED\r
-                                               popUnimplemented(next.asEndElement());\r
-                                       } else {\r
-                                               handleUnexpectedEndElement(next.asEndElement());\r
-                                       }\r
-                               }\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, HEADING)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, SUB_HEADING)) {\r
-                                       String subheading = getCData(state, reader, next).trim();\r
-                                       String excludePattern = "(i?)(References?|Literature):?";\r
-                                       if (!subheading.matches(excludePattern)) {\r
-                                               fireNotYetImplementedElement(next.getLocation(), next.asStartElement().getName(), 0);\r
-                                       }\r
-                               } else if (isStartingElement(next, WRITER)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, FOOTNOTE)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, STRING)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, REF_NUM)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, REFERENCE)) {\r
-                                       Reference<?> ref = handleReference(state, reader, next);\r
-                                       result.add(ref);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next);\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<References> has no closing tag");\r
-       }\r
-\r
-       private void handleHabitat(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-               Taxon taxon = state.getCurrentTaxon();\r
-               // TODO which ref to take?\r
-               Reference<?> ref = state.getConfig().getSourceReference();\r
-\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               TaxonDescription description = getTaxonDescription(taxon, ref,\r
-                                               false, true);\r
-                               UUID uuidExtractedHabitat = MarkupTransformer.uuidExtractedHabitat;\r
-                               Feature feature = getFeature(\r
-                                               state,\r
-                                               uuidExtractedHabitat,\r
-                                               "Extracted Habitat",\r
-                                               "An structured habitat that was extracted from a habitat text",\r
-                                               "extr. habit.", null);\r
-                               TextData habitat = TextData.NewInstance(feature);\r
-                               habitat.putText(Language.DEFAULT(), text);\r
-                               description.addElement(habitat);\r
-\r
-                               return;\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, ALTITUDE)) {\r
-                                       text = text.trim() + getTaggedCData(state, reader, next);\r
-                               } else if (isStartingElement(next, LIFE_CYCLE_PERIODS)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next.asStartElement());\r
-                               }\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<Habitat> has no closing tag");\r
-       }\r
-\r
-       private String getTaggedCData(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-\r
-               String text = getXmlTag(parentEvent);\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               text += getXmlTag(next);\r
-                               return text;\r
-                       } else if (next.isStartElement()) {\r
-                               text += getTaggedCData(state, reader, next);\r
-                       } else if (next.isEndElement()) {\r
-                               text += getTaggedCData(state, reader, next);\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-                       } else {\r
-                               handleUnexpectedEndElement(next.asEndElement());\r
-                       }\r
-               }\r
-               throw new IllegalStateException("Some tag has no closing tag");\r
-       }\r
-\r
-       private String handleDistributionLocality(MarkupImportState state,XMLEventReader reader, XMLEvent parentEvent)throws XMLStreamException {\r
-               Map<String, Attribute> attributes = getAttributes(parentEvent);\r
-               String classValue = getAndRemoveRequiredAttributeValue(parentEvent, attributes, CLASS);\r
-               String statusValue =getAndRemoveAttributeValue(attributes, STATUS);\r
-               String frequencyValue =getAndRemoveAttributeValue(attributes, FREQUENCY);\r
-               \r
-\r
-               Taxon taxon = state.getCurrentTaxon();\r
-               // TODO which ref to take?\r
-               Reference<?> ref = state.getConfig().getSourceReference();\r
-\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               if (StringUtils.isNotBlank(text)) {\r
-                                       String label = CdmUtils.removeTrailingDot(normalize(text));\r
-                                       TaxonDescription description = getTaxonDescription(taxon, ref, false, true);\r
-                                       NamedAreaLevel level = makeNamedAreaLevel(state,classValue, next);\r
-                                       \r
-                                       //status\r
-                                       PresenceAbsenceTermBase<?> status = null;\r
-                                       if (isNotBlank(statusValue)){\r
-                                               try {\r
-                                                       status = state.getTransformer().getPresenceTermByKey(statusValue);\r
-                                                       if (status == null){\r
-                                                               //TODO\r
-                                                               String message = "The status '%s' could not be transformed to an CDM status";\r
-                                                               fireWarningEvent(message, next, 4);\r
-                                                       }\r
-                                               } catch (UndefinedTransformerMethodException e) {\r
-                                                       throw new RuntimeException(e);\r
-                                               }\r
-                                       }else{\r
-                                               status = PresenceTerm.PRESENT();\r
-                                       }\r
-                                       //frequency\r
-                                       if (isNotBlank(frequencyValue)){\r
-                                               String message = "The frequency attribute is currently not yet available in CDM";\r
-                                               fireWarningEvent(message, parentEvent, 6);\r
-                                       }\r
-                                       \r
-                                       NamedArea higherArea = null;\r
-                                       List<NamedArea> areas = new ArrayList<NamedArea>(); \r
-                                       \r
-                                       String patSingleArea = "([^,\\(]{3,})";\r
-                                       String patSeparator = "(,|\\sand\\s)";\r
-                                       String hierarchiePattern = String.format("%s\\((%s(%s%s)*)\\)",patSingleArea, patSingleArea, patSeparator, patSingleArea);\r
-                                       Pattern patHierarchie = Pattern.compile(hierarchiePattern, Pattern.CASE_INSENSITIVE);\r
-                                       Matcher matcher = patHierarchie.matcher(label); \r
-                                       if (matcher.matches()){\r
-                                               String higherAreaStr = matcher.group(1).trim();\r
-                                               higherArea =  makeArea(state, higherAreaStr, level);\r
-                                               String[] innerAreas = matcher.group(2).split(patSeparator);\r
-                                               for (String innerArea : innerAreas){\r
-                                                       if (isNotBlank(innerArea)){\r
-                                                               NamedArea singleArea = makeArea(state, innerArea.trim(), level);\r
-                                                               areas.add(singleArea);\r
-                                                               NamedArea partOf = singleArea.getPartOf();\r
-//                                                             if (partOf == null){\r
-//                                                                     singleArea.setPartOf(higherArea);\r
-//                                                             }\r
-                                                       }\r
-                                               }\r
-                                       }else{\r
-                                               NamedArea singleArea = makeArea(state, label, level);\r
-                                               areas.add(singleArea);\r
-                                       }\r
-                                       \r
-                                       for (NamedArea area : areas){\r
-                                               //create distribution\r
-                                               Distribution distribution = Distribution.NewInstance(area,status);\r
-                                               description.addElement(distribution);\r
-                                       }\r
-                               } else {\r
-                                       String message = "Empty distribution locality";\r
-                                       fireWarningEvent(message, next, 4);\r
-                               }\r
-                               return text;\r
-                       } else if (isStartingElement(next, COORDINATES)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, COORDINATES)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<DistributionLocality> has no closing tag");\r
-       }\r
-\r
-       /**\r
-        * @param state\r
-        * @param areaName\r
-        * @param level\r
-        * @return \r
-        */\r
-       private NamedArea makeArea(MarkupImportState state, String areaName, NamedAreaLevel level) {\r
-               \r
-               \r
-               //TODO FM vocabulary\r
-               TermVocabulary<NamedArea> voc = null; \r
-               NamedAreaType areaType = null;\r
-               \r
-               NamedArea area = null;\r
-               try {\r
-                       area = state.getTransformer().getNamedAreaByKey(areaName);\r
-               } catch (UndefinedTransformerMethodException e) {\r
-                       throw new RuntimeException(e);\r
-               }\r
-               if (area == null){\r
-                       boolean isNewInState = false;\r
-                       UUID uuid = state.getAreaUuid(areaName);\r
-                       if (uuid == null){\r
-                               isNewInState = true;\r
-                               \r
-                               \r
-                               try {\r
-                                       uuid = state.getTransformer().getNamedAreaUuid(areaName);\r
-                               } catch (UndefinedTransformerMethodException e) {\r
-                                       throw new RuntimeException(e);\r
-                               }\r
-                       }\r
-                       \r
-                       CdmImportBase.TermMatchMode matchMode = CdmImportBase.TermMatchMode.UUID_LABEL;\r
-                       area = getNamedArea(state, uuid, areaName, areaName, areaName, areaType, level, voc, matchMode);\r
-                       if (isNewInState){\r
-                               state.putAreaUuid(areaName, area.getUuid());\r
-                               \r
-                               //TODO just for testing -> make generic and move to better place\r
-                               String geoServiceLayer="vmap0_as_bnd_political_boundary_a";\r
-                               String layerFieldName ="nam";\r
-                               \r
-                               if ("Bangka".equals(areaName)){\r
-                                       String areaValue = "PULAU BANGKA#SUMATERA SELATAN";\r
-                                       GeoServiceArea geoServiceArea = new GeoServiceArea();\r
-                                       geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue);\r
-                                       this.editGeoService.setMapping(area, geoServiceArea);\r
-//                                     save(area, state);\r
-                               }\r
-                               if ("Luzon".equals(areaName)){\r
-                                       GeoServiceArea geoServiceArea = new GeoServiceArea();\r
-                                       \r
-                                       List<String> list = Arrays.asList("HERMANA MAYOR ISLAND#CENTRAL LUZON",\r
-                                                       "HERMANA MENOR ISLAND#CENTRAL LUZON",\r
-                                                       "CENTRAL LUZON");\r
-                                       for (String areaValue : list){\r
-                                               geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue);\r
-                                       }\r
-                                       \r
-                                       this.editGeoService.setMapping(area, geoServiceArea);\r
-//                                     save(area, state);\r
-                               }\r
-                               if ("Mindanao".equals(areaName)){\r
-                                       GeoServiceArea geoServiceArea = new GeoServiceArea();\r
-                                       \r
-                                       List<String> list = Arrays.asList("NORTHERN MINDANAO",\r
-                                                       "SOUTHERN MINDANAO",\r
-                                                       "WESTERN MINDANAO");\r
-                                       //TODO to be continued\r
-                                       for (String areaValue : list){\r
-                                               geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue);\r
-                                       }\r
-                                       \r
-                                       this.editGeoService.setMapping(area, geoServiceArea);\r
-//                                     save(area, state);\r
-                               }\r
-                               if ("Palawan".equals(areaName)){\r
-                                       GeoServiceArea geoServiceArea = new GeoServiceArea();\r
-                                       \r
-                                       List<String> list = Arrays.asList("PALAWAN#SOUTHERN TAGALOG");\r
-                                       for (String areaValue : list){\r
-                                               geoServiceArea.add(geoServiceLayer, layerFieldName, areaValue);\r
-                                       }\r
-                                       \r
-                                       this.editGeoService.setMapping(area, geoServiceArea);\r
-//                                     save(area, state);\r
-                               }\r
-                               \r
-\r
-                       }\r
-               }\r
-               return area;\r
-       }\r
-       \r
-\r
-       /**\r
-        * @param state\r
-        * @param levelString\r
-        * @param next\r
-        * @return\r
-        */\r
-       private NamedAreaLevel makeNamedAreaLevel(MarkupImportState state,\r
-                       String levelString, XMLEvent next) {\r
-               NamedAreaLevel level;\r
-               try {\r
-                       level = state.getTransformer().getNamedAreaLevelByKey(levelString);\r
-                       if (level == null) {\r
-                               UUID levelUuid = state.getTransformer().getNamedAreaLevelUuid(levelString);\r
-                               if (levelUuid == null) {\r
-                                       String message = "Unknown distribution locality class (named area level): %s. Create new level instead.";\r
-                                       message = String.format(message, levelString);\r
-                                       fireWarningEvent(message, next, 6);\r
-                               }\r
-                               level = getNamedAreaLevel(state, levelUuid, levelString, levelString, levelString, null);\r
-                       }\r
-               } catch (UndefinedTransformerMethodException e) {\r
-                       throw new RuntimeException(e);\r
-               }\r
-               return level;\r
-       }\r
-\r
-       private String handleHeading(MarkupImportState state,XMLEventReader reader, XMLEvent parentEvent)throws XMLStreamException {\r
-               checkNoAttributes(parentEvent);\r
-\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               return text;\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, FOOTNOTE)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next.asStartElement());\r
-                               }\r
-                       } else if (next.isCharacters()) {\r
-                               text += next.asCharacters().getData();\r
-                       } else {\r
-                               handleUnexpectedEndElement(next.asEndElement());\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<String> has no closing tag");\r
-\r
-       }\r
-\r
-       /**\r
-        * Handle string\r
-        * @param state\r
-        * @param reader\r
-        * @param parentEvent\r
-        * @param feature only needed for distributionLocalities\r
-        * @return\r
-        * @throws XMLStreamException\r
-        */\r
-       private Map<String, String> handleString(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent, Feature feature)throws XMLStreamException {\r
-               // attributes\r
-               String classValue = getClassOnlyAttribute(parentEvent, false);\r
-               if (StringUtils.isNotBlank(classValue)) {\r
-                       String message = "class attribute for <string> not yet implemented";\r
-                       fireWarningEvent(message, parentEvent, 2);\r
-               }\r
-\r
-               // subheadings\r
-               Map<String, String> subHeadingMap = new HashMap<String, String>();\r
-               String currentSubheading = null;\r
-\r
-               boolean isTextMode = true;\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               putCurrentSubheading(subHeadingMap, currentSubheading, text);\r
-                               return subHeadingMap;\r
-                       } else if (isStartingElement(next, BR)) {\r
-                               text += "<br/>";\r
-                               isTextMode = false;\r
-                       } else if (isEndingElement(next, BR)) {\r
-                               isTextMode = true;\r
-                       } else if (isHtml(next)) {\r
-                               text += getXmlTag(next);\r
-                       } else if (isStartingElement(next, SUB_HEADING)) {\r
-                               text = putCurrentSubheading(subHeadingMap,currentSubheading, text);\r
-                               // TODO footnotes\r
-                               currentSubheading = getCData(state, reader, next).trim();\r
-                       } else if (isStartingElement(next, DISTRIBUTION_LOCALITY)) {\r
-                               if (feature != null && !feature.equals(Feature.DISTRIBUTION())) {\r
-                                       String message = "Distribution locality only allowed for feature of type 'distribution'";\r
-                                       fireWarningEvent(message, next, 4);\r
-                               }\r
-                               text += handleDistributionLocality(state, reader, next);\r
-                       } else if (next.isCharacters()) {\r
-                               if (!isTextMode) {\r
-                                       String message = "String is not in text mode";\r
-                                       fireWarningEvent(message, next, 6);\r
-                               } else {\r
-                                       text += next.asCharacters().getData();\r
-                               }\r
-                       } else if (isStartingElement(next, HEADING)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, HEADING)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, QUOTE)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, QUOTE)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, DEDICATION)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, DEDICATION)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, TAXONTYPE)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, TAXONTYPE)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, FULL_NAME)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, FULL_NAME)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       }else if (isStartingElement(next, REFERENCES)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, REFERENCES)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, GATHERING)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, GATHERING)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, ANNOTATION)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, ANNOTATION)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, HABITAT)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, HABITAT)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, FIGURE_REF)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, FIGURE_REF)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, FIGURE)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, FIGURE)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, FOOTNOTE_REF)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, FOOTNOTE_REF)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, FOOTNOTE)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, FOOTNOTE)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, WRITER)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, WRITER)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, DATES)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, DATES)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else {\r
-                               handleUnexpectedElement(next);\r
-                       }\r
-               }\r
-               throw new IllegalStateException("<String> has no closing tag");\r
-       }\r
-\r
-       /**\r
-        * @param subHeadingMap\r
-        * @param currentSubheading\r
-        * @param text\r
-        * @return\r
-        */\r
-       private String putCurrentSubheading(Map<String, String> subHeadingMap, String currentSubheading, String text) {\r
-               if (StringUtils.isNotBlank(text)) {\r
-                       text = removeStartingMinus(text);\r
-                       subHeadingMap.put(currentSubheading, text.trim());\r
-               }\r
-               return "";\r
-       }\r
-\r
-       private String removeStartingMinus(String string) {\r
-               string = replaceStart(string, "-");\r
-               string = replaceStart(string, "\u002d");\r
-               string = replaceStart(string, "\u2013");\r
-               string = replaceStart(string, "\u2014");\r
-               string = replaceStart(string, "--");\r
-               return string;\r
-       }\r
-       \r
-       /**\r
-        * @param value\r
-        * @param replacementString\r
-        */\r
-       private String replaceStart(String value, String replacementString) {\r
-               if (value.startsWith(replacementString) ){\r
-                       value = value.substring(replacementString.length()).trim();\r
-               }\r
-               while (value.startsWith("-") || value.startsWith("\u2014") ){\r
-                       value = value.substring("-".length()).trim();\r
-               }\r
-               return value;\r
-       }\r
-       \r
-       private String getXmlTag(XMLEvent event) {\r
-               String result;\r
-               if (event.isStartElement()) {\r
-                       result = "<" + event.asStartElement().getName().getLocalPart()\r
-                                       + ">";\r
-               } else if (event.isEndElement()) {\r
-                       result = "</" + event.asEndElement().getName().getLocalPart() + ">";\r
-               } else {\r
-                       String message = "Only start or end elements are allowed as Html tags";\r
-                       throw new IllegalStateException(message);\r
-               }\r
-               return result;\r
-       }\r
-\r
-       protected static final List<String> htmlList = Arrays.asList("sub", "sup",\r
-                       "ol", "ul", "li", "i", "b", "table", "br","tr","td");\r
-\r
-       private boolean isHtml(XMLEvent event) {\r
-               if (event.isStartElement()) {\r
-                       String tag = event.asStartElement().getName().getLocalPart();\r
-                       return htmlList.contains(tag);\r
-               } else if (event.isEndElement()) {\r
-                       String tag = event.asEndElement().getName().getLocalPart();\r
-                       return htmlList.contains(tag);\r
-               } else {\r
-                       return false;\r
-               }\r
-\r
-       }\r
-\r
-       private TextData handleChar(MarkupImportState state, XMLEventReader reader,\r
-                       XMLEvent parentEvent) throws XMLStreamException {\r
-               String classValue = getClassOnlyAttribute(parentEvent);\r
-               Feature feature = makeFeature(classValue, state, parentEvent);\r
-\r
-               boolean isTextMode = true;\r
-               String text = "";\r
-               while (reader.hasNext()) {\r
-                       XMLEvent next = readNoWhitespace(reader);\r
-                       if (isMyEndingElement(next, parentEvent)) {\r
-                               TextData textData = TextData.NewInstance(feature);\r
-                               textData.putText(Language.DEFAULT(), text);\r
-                               return textData;\r
-                       } else if (isStartingElement(next, FIGURE_REF)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, FIGURE_REF)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());\r
-                       } else if (isStartingElement(next, FOOTNOTE_REF)) {\r
-                               //TODO\r
-                               handleNotYetImplementedElement(next);\r
-                       } else if (isEndingElement(next, FOOTNOTE_REF)) {\r
-                               //TODO\r
-                               popUnimplemented(next.asEndElement());  \r
-                       } else if (isStartingElement(next, BR)) {\r
-                               text += "<br/>";\r
-                               isTextMode = false;\r
-                       } else if (isEndingElement(next, BR)) {\r
-                               isTextMode = true;\r
-                       } else if (isHtml(next)) {\r
-                               text += getXmlTag(next);\r
-                       } else if (next.isStartElement()) {\r
-                               if (isStartingElement(next, ANNOTATION)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, ITALICS)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, BOLD)) {\r
-                                       handleNotYetImplementedElement(next);\r
-                               } else if (isStartingElement(next, FIGURE)) {\r
-                                       handleFigure(state, reader, next);\r
-                               } else if (isStartingElement(next, FOOTNOTE)) {\r
-                                       FootnoteDataHolder footnote = handleFootnote(state, reader,     next);\r
-                                       if (footnote.isRef()) {\r
-                                               String message = "Ref footnote not implemented here";\r
-                                               fireWarningEvent(message, next, 4);\r
-                                       } else {\r
-                                               registerGivenFootnote(state, footnote);\r
-                                       }\r
-                               } else {\r
-                                       handleUnexpectedStartElement(next.asStartElement());\r
-                               }\r
-                       } else if (next.isCharacters()) {\r
-                               if (!isTextMode) {\r
-                                       String message = "String is not in text mode";\r
-                                       fireWarningEvent(message, next, 6);\r
-                               } else {\r
-                                       text += next.asCharacters().getData();\r
-                               }\r
-                       } else {\r
-                               handleUnexpectedEndElement(next.asEndElement());\r
-                       }\r
-               }\r
-               throw new IllegalStateException("RefPart has no closing tag");\r
-       }\r
-\r
-       /**\r
-        * @param classValue\r
-        * @param state\r
-        * @param parentEvent\r
-        * @return\r
-        * @throws UndefinedTransformerMethodException\r
-        */\r
-       private Feature makeFeature(String classValue, MarkupImportState state, XMLEvent parentEvent) {\r
-               UUID uuid;\r
-               try {\r
-                       Feature feature = state.getTransformer().getFeatureByKey(classValue);\r
-                       if (feature != null) {\r
-                               return feature;\r
-                       }\r
-                       uuid = state.getTransformer().getFeatureUuid(classValue);\r
-                       if (uuid == null) {\r
-                               // TODO\r
-                               String message = "Uuid is not defined for '%s'";\r
-                               message = String.format(message, classValue);\r
-                               fireWarningEvent(message, parentEvent, 8);\r
-                       }\r
-                       String featureText = StringUtils.capitalize(classValue);\r
-\r
-                       // TODO eFlora vocabulary\r
-                       TermVocabulary<Feature> voc = null;\r
-                       feature = getFeature(state, uuid, featureText, featureText, classValue, voc);\r
-                       if (feature == null) {\r
-                               throw new NullPointerException(classValue + " not recognized as a feature");\r
-                       }\r
-                       return feature;\r
-               } catch (Exception e) {\r
-                       String message = "Could not create feature for %s: %s";\r
-                       message = String.format(message, classValue, e.getMessage());\r
-                       fireWarningEvent(message, parentEvent, 4);\r
-                       return Feature.UNKNOWN();\r
-               }\r
-       }\r
-\r
-\r
-\r
-}\r
+/**
+ * Copyright (C) 2009 EDIT
+ * European Distributed Institute of Taxonomy
+ * http://www.e-taxonomy.eu
+ *
+ * The contents of this file are subject to the Mozilla Public License Version 1.1
+ * See LICENSE.TXT at the top of this package for the full license terms.
+ */
+
+package eu.etaxonomy.cdm.io.markup;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
+import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
+import eu.etaxonomy.cdm.model.common.ExtensionType;
+import eu.etaxonomy.cdm.model.common.Language;
+import eu.etaxonomy.cdm.model.description.Feature;
+import eu.etaxonomy.cdm.model.description.PolytomousKey;
+import eu.etaxonomy.cdm.model.description.PolytomousKeyNode;
+import eu.etaxonomy.cdm.model.description.TaxonDescription;
+import eu.etaxonomy.cdm.model.description.TextData;
+import eu.etaxonomy.cdm.model.name.INonViralName;
+import eu.etaxonomy.cdm.model.name.Rank;
+import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
+import eu.etaxonomy.cdm.model.reference.Reference;
+import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
+import eu.etaxonomy.cdm.model.taxon.Classification;
+import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.model.taxon.TaxonNode;
+
+
+/**
+ * @author a.mueller
+ *
+ */
+public class MarkupDocumentImportNoComponent extends MarkupImportBase {
+       @SuppressWarnings("unused")
+       private static final Logger logger = Logger.getLogger(MarkupDocumentImportNoComponent.class);
+
+       private final MarkupKeyImport keyImport;
+
+       private final MarkupModsImport modsImport;
+       private final MarkupSpecimenImport specimenImport;
+       private final MarkupNomenclatureImport nomenclatureImport;
+
+       public MarkupDocumentImportNoComponent(MarkupDocumentImport docImport) {
+               super(docImport);
+               this.keyImport = new MarkupKeyImport(docImport);
+               this.specimenImport = new MarkupSpecimenImport(docImport);
+               this.nomenclatureImport = new MarkupNomenclatureImport(docImport, specimenImport);
+               this.modsImport = new MarkupModsImport(docImport);
+               this.featureImport = new MarkupFeatureImport(docImport, specimenImport, nomenclatureImport, keyImport);
+       }
+
+       public void doInvoke(MarkupImportState state) throws XMLStreamException {
+               XMLEventReader reader = state.getReader();
+
+               // publication (= root element)
+               String elName = PUBLICATION;
+               boolean hasPublication = false;
+
+               while (reader.hasNext()) {
+                       XMLEvent nextEvent = reader.nextEvent();
+                       if (isStartingElement(nextEvent, elName)) {
+                               handlePublication(state, reader, nextEvent, elName);
+                               hasPublication = true;
+                       } else if (nextEvent.isEndDocument()) {
+                               if (!hasPublication) {
+                                       String message = "No publication root element found";
+                                       fireWarningEvent(message, nextEvent, 8);
+                               }
+                               // done
+                       } else {
+                               fireSchemaConflictEventExpectedStartTag(elName, reader);
+                       }
+               }
+
+
+               return;
+
+       }
+
+       private void handlePublication(MarkupImportState state, XMLEventReader reader, XMLEvent currentEvent, String elName) throws XMLStreamException {
+
+               // attributes
+               StartElement element = currentEvent.asStartElement();
+               Map<String, Attribute> attributes = getAttributes(element);
+               String lang = getAndRemoveAttributeValue(attributes, "lang");
+               if (lang != null){
+                       Language language = getTermService().getLanguageByIso(lang);
+                       state.setDefaultLanguage(language);
+               }
+
+               handleUnexpectedAttributes(element.getLocation(), attributes, "noNamespaceSchemaLocation");
+
+               while (reader.hasNext()) {
+                       XMLEvent event = readNoWhitespace(reader);
+                       // TODO cardinality of alternative
+                       if (isEndingElement(event, elName)) {
+                               return;
+                       } else if (event.isStartElement()) {
+                               if (isStartingElement(event, META_DATA)) {
+                                       handleMetaData(state, reader, event);
+                               } else if (isStartingElement(event, TREATMENT)) {
+                                       handleTreatment(state, reader, event);
+                               } else if (isStartingElement(event, BIOGRAPHIES)) {
+                                       handleNotYetImplementedElement(event);
+                               } else if (isStartingElement(event, REFERENCES)) {
+                                       handleNotYetImplementedElement(event);
+                               } else if (isStartingElement(event, TEXT_SECTION)) {
+                                       handleNotYetImplementedElement(event);
+                               } else if (isStartingElement(event, ADDENDA)) {
+                                       handleNotYetImplementedElement(event);
+                               } else {
+                                       handleUnexpectedStartElement(event);
+                               }
+                       } else {
+                               handleUnexpectedElement(event);
+                       }
+               }
+               throw new IllegalStateException("Publication has no ending element");
+       }
+
+       private void handleMetaData(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
+               checkNoAttributes(parentEvent);
+
+               while (reader.hasNext()) {
+                       XMLEvent next = readNoWhitespace(reader);
+                       if (isMyEndingElement(next, parentEvent)) {
+                               return;
+                       } else if (isStartingElement(next, DEFAULT_MEDIA_URL)) {
+                               String baseUrl = getCData(state, reader, next);
+                               try {
+                                       new URL(baseUrl);
+                                       state.setBaseMediaUrl(baseUrl);
+                               } catch (MalformedURLException e) {
+                                       String message = "defaultMediaUrl '%s' is not a valid URL";
+                                       message = String.format(message, baseUrl);
+                                       fireWarningEvent(message, next, 8);
+                               }
+                       } else if (isStartingElement(next, MODS)){
+                               modsImport.handleMods(state, reader, next);
+                       } else {
+                               handleUnexpectedElement(next);
+                       }
+               }
+               throw new IllegalStateException("MetaData has no ending element");
+
+       }
+
+       private void handleTreatment(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
+               checkNoAttributes(parentEvent);
+               Taxon lastTaxon = null;
+               while (reader.hasNext()) {
+                       XMLEvent next = readNoWhitespace(reader);
+                       if (isMyEndingElement(next, parentEvent)) {
+                               Set<PolytomousKeyNode> keyNodesToSave = state.getPolytomousKeyNodesToSave();
+                               //better save the key then the nodes
+                               Set<PolytomousKey> keySet = new HashSet<PolytomousKey>();
+                               for (PolytomousKeyNode node : keyNodesToSave){
+                                       PolytomousKey key = node.getKey();
+                                       keySet.add(key);
+                               }
+                               save(keySet, state);
+                               //unmatched key leads
+                               UnmatchedLeads unmatched = state.getUnmatchedLeads();
+                               if (unmatched.size() > 0){
+                                       String message = "The following %d key leads are unmatched: %s";
+                                       message = String.format(message, unmatched.size(), state.getUnmatchedLeads().toString());
+                                       fireWarningEvent(message, next, 6);
+                               }
+//                             save(keyNodesToSave, state);
+
+                               return;
+                       } else if (isStartingElement(next, TAXON)) {
+                               state.setCurrentTaxonExcluded(false);
+                           Taxon thisTaxon = handleTaxon(state, reader, next.asStartElement());
+                               doTaxonRelation(state, thisTaxon, lastTaxon, parentEvent.getLocation());
+                               if (state.isTaxonInClassification() == true){
+                                       lastTaxon = thisTaxon;
+                                       // TODO for imports spanning multiple documents ?? Still needed?
+                                       state.getConfig().setLastTaxonUuid(lastTaxon.getUuid());
+                               }
+                       } else if (isStartingElement(next, ADDENDA)) {
+                               handleNotYetImplementedElement(next);
+                       } else {
+                               handleUnexpectedElement(next);
+                       }
+               }
+               return;
+       }
+
+       /**
+        * @param taxon
+        * @param lastTaxon
+        */
+       private TaxonNode doTaxonRelation(MarkupImportState state, Taxon taxon, Taxon lastTaxon, Location dataLocation) {
+
+               if (state.isTaxonInClassification() == false){
+                       return null;
+               }
+
+               boolean excluded = state.isCurrentTaxonExcluded();
+               TaxonNode node;
+               Classification tree = makeTree(state, dataLocation);
+               if (lastTaxon == null) {
+                       node = tree.addChildTaxon(taxon, null, null);
+                       node.setExcluded(excluded);
+                       return node;
+               }
+               Rank thisRank = taxon.getName().getRank();
+               Rank lastRank = lastTaxon.getName().getRank();
+               if (lastRank == null){
+                       String message = "Last rank was null. Can't create tree correctly";
+                       fireWarningEvent(message, makeLocationStr(dataLocation), 12);
+               }
+               if (!lastTaxon.getTaxonNodes().isEmpty()) {
+                       TaxonNode lastNode = lastTaxon.getTaxonNodes().iterator().next();
+                       if (thisRank == null){
+                           String message = "Rank is undefined for taxon '%s'. Can't create classification without rank.";
+                               message = String.format(message, taxon.getName().getTitleCache());
+                               fireWarningEvent(message, makeLocationStr(dataLocation), 6);
+                               node = null;
+                       }else if (thisRank.isLower(lastRank)) {
+                           node = null;
+                   node = lastNode.addChildTaxon(taxon, null, null);
+                               fillMissingEpithetsForTaxa(lastTaxon, taxon);
+                       } else if (thisRank.equals(lastRank)) {
+                           TaxonNode parent = lastNode.getParent();
+                               if (parent != null && parent.getTaxon() != null) {
+                                       node = parent.addChildTaxon(taxon, null, null);
+                                       fillMissingEpithetsForTaxa(parent.getTaxon(), taxon);
+                               } else {
+                                       node = tree.addChildTaxon(taxon, null, null);
+                               }
+                       } else if (thisRank.isHigher(lastRank)) {
+                           TaxonNode parent = lastNode.getParent();
+                               if (parent != null){
+                                       node = doTaxonRelation(state, taxon, parent.getTaxon(), dataLocation);
+                               }else{
+                                       String warning = "No parent available for lastNode. Classification can not be build correctly. Maybe the rank was missing for the lastNode";
+                                       fireWarningEvent(warning, makeLocationStr(dataLocation), 16);
+                                       //TODO what to do in this case (haven't spend time to think about yet
+                                       node = null;
+                               }
+
+                               // TaxonNode parentNode = handleTaxonRelation(state, taxon,
+                               // lastNode.getParent().getTaxon());
+                               // parentNode.addChildTaxon(taxon, null, null, null);
+                       }else{
+                           fireWarningEvent("Unhandled case", makeLocationStr(dataLocation), 8);
+                           node = null;
+                       }
+               } else {
+                       String message = "Last taxon has no node";
+                       fireWarningEvent(message, makeLocationStr(dataLocation), 6);
+                       node = null;
+               }
+               if (excluded){
+                   if (node != null){
+                       node.setExcluded(excluded);
+                   }else{
+                       fireWarningEvent("Taxon is excluded but no taxon node can be created", makeLocationStr(dataLocation), 4);
+                   }
+               }
+               return node;
+       }
+
+
+
+       /**
+        * @param state
+        * @param dataLocation
+        * @return
+        */
+       private Classification makeTree(MarkupImportState state, Location dataLocation) {
+               Classification result = state.getTree(null);
+               if (result == null) {
+                       UUID uuid = state.getConfig().getClassificationUuid();
+                       if (uuid == null) {
+                               String message = "No classification uuid is defined";
+                               fireWarningEvent(message, makeLocationStr(dataLocation), 6);
+                               result = createNewClassification(state);
+                       } else {
+                               result = getClassificationService().find(uuid);
+                               if (result == null) {
+                                       result = createNewClassification(state);
+                                       result.setUuid(uuid);
+                               }
+                       }
+                       state.putTree(null, result);
+               }
+               save(result, state);
+               return result;
+       }
+
+       private Classification createNewClassification(MarkupImportState state) {
+               Classification result = Classification.NewInstance(state.getConfig().getClassificationName(), getDefaultLanguage(state));
+               state.putTree(null, result);
+               return result;
+       }
+
+       private Taxon handleTaxon(MarkupImportState state, XMLEventReader reader, StartElement parentEvent) throws XMLStreamException {
+               // TODO progress monitoring
+               Map<String, Attribute> attributes = getAttributes(parentEvent);
+               Taxon taxon = createTaxonAndName(state, attributes, parentEvent);
+               state.setCurrentTaxon(taxon);
+               state.addNewFeatureSorterLists(taxon.getUuid().toString());
+
+               boolean hasTitle = false;
+               boolean hasNomenclature = false;
+               String taxonTitle = null;
+
+               Reference sourceReference = state.getConfig().getSourceReference();
+               while (reader.hasNext()) {
+                       XMLEvent next = readNoWhitespace(reader);
+                       if (isMyEndingElement(next, parentEvent)) {
+//                             checkMandatoryElement(hasTitle, parentEvent, TAXONTITLE);
+                               checkMandatoryElement(hasNomenclature, parentEvent,     NOMENCLATURE);
+                               boolean inClassification = getAndRemoveBooleanAttributeValue(next, attributes, "inClassification", true);
+                               state.setTaxonInClassification(inClassification);
+                               handleUnexpectedAttributes(parentEvent.getLocation(),attributes);
+                               if (taxon.getName().getRank() == null){
+                                       String warning = "No rank exists for taxon " + taxon.getTitleCache();
+                                       fireWarningEvent(warning, next, 12);
+                                       taxon.getName().setRank(Rank.UNKNOWN_RANK());
+                               }
+                               //hybrid
+                               if (state.isTaxonIsHybrid() && !taxon.getName().isHybrid()){
+                                   fireWarningEvent("Taxon is hybrid but name is not a hybrid name", next, 4);
+                               }
+                               state.setTaxonIsHybrid(false);
+
+                               keyImport.makeKeyNodes(state, parentEvent, taxonTitle);
+                               state.setCurrentTaxon(null);
+                               state.setCurrentTaxonNum(null);
+                               if (taxon.getName().getRank().isHigher(Rank.GENUS())){
+                                       state.setLatestGenusEpithet(null);
+                               }else{
+                                       state.setLatestGenusEpithet(taxon.getName().getGenusOrUninomial());
+                               }
+                               save(taxon, state);
+                               return taxon;
+                       } else if (next.isStartElement()) {
+                               if (isStartingElement(next, HEADING)) {
+                                       handleNotYetImplementedElement(next);
+                               } else if (isStartingElement(next, TAXONTITLE)) {
+                                       taxonTitle = handleTaxonTitle(state, reader, next);
+                                       hasTitle = true;
+                               } else if (isStartingElement(next, WRITER)) {
+                                       makeKeyWriter(state, reader, taxon, taxonTitle, next);
+                               } else if (isStartingElement(next, TEXT_SECTION)) {
+                                       handleNotYetImplementedElement(next);
+                               } else if (isStartingElement(next, KEY)) {
+                                       keyImport.handleKey(state, reader, next);
+                               } else if (isStartingElement(next, NOMENCLATURE)) {
+                                       nomenclatureImport.handleNomenclature(state, reader, next);
+                                       hasNomenclature = true;
+                               } else if (isStartingElement(next, FEATURE)) {
+                                       featureImport.handleFeature(state, reader, next);
+                               } else if (isStartingElement(next, NOTES)) {
+                                       // TODO is this the correct way to handle notes?
+                                       String note = handleNotes(state, reader, next);
+
+                                       UUID notesUuid;
+                                       try {
+                                               notesUuid = state.getTransformer().getFeatureUuid("notes");
+                                               Feature feature = getFeature(state, notesUuid, "Notes", "Notes", "note", null);
+                                               TextData textData = TextData.NewInstance(feature);
+                                               textData.addPrimaryTaxonomicSource(sourceReference);
+                                               textData.putText(getDefaultLanguage(state), note);
+                                               TaxonDescription description = getDefaultTaxonDescription(taxon, false, true, sourceReference);
+                                               description.addElement(textData);
+                                       } catch (UndefinedTransformerMethodException e) {
+                                               String message = "getFeatureUuid method not yet implemented";
+                                               fireWarningEvent(message, next, 8);
+                                       }
+                               } else if (isStartingElement(next, REFERENCES)) {
+                                       handleNotYetImplementedElement(next);
+                               } else if (isStartingElement(next, FIGURE_REF)) {
+                                       TaxonDescription desc = getTaxonDescription(taxon, sourceReference, IMAGE_GALLERY, CREATE_NEW);
+                                       TextData textData;
+                                       if (desc.getElements().isEmpty()){
+                                               textData = TextData.NewInstance(Feature.IMAGE());
+                                               textData.addPrimaryTaxonomicSource(sourceReference);
+                                               desc.addElement(textData);
+                                       }
+                                       textData = (TextData)desc.getElements().iterator().next();
+                                       featureImport.makeFeatureFigureRef(state, reader, desc, false, textData, sourceReference, next);
+                               } else if (isStartingElement(next, FIGURE)) {
+                                       handleFigure(state, reader, next, specimenImport, nomenclatureImport);
+                               } else if (isStartingElement(next, FOOTNOTE)) {
+                                       FootnoteDataHolder footnote = handleFootnote(state, reader,     next, specimenImport, nomenclatureImport);
+                                       if (footnote.isRef()) {
+                                               String message = "Ref footnote not implemented here";
+                                               fireWarningEvent(message, next, 4);
+                                       } else {
+                                               registerGivenFootnote(state, footnote);
+                                       }
+                               } else {
+                                       handleUnexpectedStartElement(next);
+                               }
+                       } else {
+                               handleUnexpectedElement(next);
+                       }
+               }
+               throw new IllegalStateException("<Taxon> has no closing tag");
+       }
+
+       /**
+        * @param state
+        * @param reader
+        * @param taxon
+        * @param taxonTitle
+        * @param next
+        * @throws XMLStreamException
+        */
+       private void makeKeyWriter(MarkupImportState state, XMLEventReader reader, Taxon taxon, String taxonTitle, XMLEvent next) throws XMLStreamException {
+               WriterDataHolder writer = handleWriter(state, reader, next);
+               if (state.getConfig().isHandleWriterManually()){
+                   fireWarningEvent("<Writer> is expected to be handled manually", next, 1);
+               }else{
+                   taxon.addExtension(writer.extension);
+               // TODO what if taxonTitle comes later
+               taxonTitle = taxonTitle != null ? taxonTitle : taxon.getName() == null ? null : taxon.getName().getNameCache();
+               if (writer.extension != null) {
+                   if (StringUtils.isBlank(taxonTitle)){
+                       fireWarningEvent("No taxon title defined for writer. Please add sec.title manually.", next, 6);
+                       taxonTitle = null;
+                   }
+                   Reference sec = ReferenceFactory.newBookSection();
+                   sec.setTitle(taxonTitle);
+                   TeamOrPersonBase<?> author = createAuthor(state, writer.writer);
+                   sec.setAuthorship(author);
+                   sec.setInReference(state.getConfig().getSourceReference());
+                   taxon.setSec(sec);
+                   registerFootnotes(state, sec, writer.footnotes);
+               } else {
+                   String message = "There is no writer extension defined";
+                   fireWarningEvent(message, next, 6);
+               }
+               }
+       }
+
+       private String handleNotes(MarkupImportState state, XMLEventReader reader,
+                       XMLEvent parentEvent) throws XMLStreamException {
+               checkNoAttributes(parentEvent);
+
+               String text = "";
+               while (reader.hasNext()) {
+                       XMLEvent next = readNoWhitespace(reader);
+                       if (isMyEndingElement(next, parentEvent)) {
+                               return text;
+                       } else if (next.isStartElement()) {
+                               if (isStartingElement(next, HEADING)) {
+                                       handleNotYetImplementedElement(next);
+                               } else if (isStartingElement(next, SUB_HEADING)) {
+                                       String subheading = getCData(state, reader, next).trim();
+                                       if (! isNoteHeading(subheading)) {
+                                               fireNotYetImplementedElement(next.getLocation(), next.asStartElement().getName(), 0);
+                                       }
+                               } else if (isStartingElement(next, WRITER)) {
+                                       handleNotYetImplementedElement(next);
+                               } else if (isStartingElement(next, NUM)) {
+                                       handleNotYetImplementedElement(next);
+                               } else if (isStartingElement(next, STRING)) {
+                                       // TODO why multiple strings in schema?
+                                       text = makeNotesString(state, reader, text, next);
+                               } else {
+                                       handleUnexpectedStartElement(next.asStartElement());
+                               }
+                       } else {
+                               handleUnexpectedElement(next);
+                       }
+               }
+               throw new IllegalStateException("<Notes> has no closing tag");
+       }
+
+       /**
+        * @param state
+        * @param reader
+        * @param text
+        * @param next
+        * @return
+        * @throws XMLStreamException
+        */
+       private String makeNotesString(MarkupImportState state, XMLEventReader reader, String text, XMLEvent next) throws XMLStreamException {
+               Map<String, SubheadingResult> stringMap = handleString(state, reader,   next, null);
+               if (stringMap.size() == 0){
+                       String message = "No text available in <notes>";
+                       fireWarningEvent(message, next, 4);
+               }else if (stringMap.size() > 1){
+                       String message = "Subheadings not yet supported in <notes>";
+                       fireWarningEvent(message, next, 4);
+               }else{
+                       String firstSubheading = stringMap.keySet().iterator().next();
+                       if ( firstSubheading != null && ! isNoteHeading (firstSubheading) )  {
+                               String message = "Subheadings not yet supported in <notes>";
+                               fireWarningEvent(message, next, 4);
+                       }
+               }
+               for (String subheading : stringMap.keySet()){
+                       text += subheading;
+                       text += stringMap.get(subheading);
+               }
+               return text;
+       }
+
+       private boolean isNoteHeading(String heading) {
+               String excludePattern = "(i?)(Notes?):?";
+               return heading.matches(excludePattern);
+       }
+
+       /**
+        * @param state
+        * @param attributes
+        * @param event
+        */
+       private Taxon createTaxonAndName(MarkupImportState state,
+                       Map<String, Attribute> attributes, StartElement event) {
+               INonViralName name;
+               Rank rank = null;  //Rank.SPECIES(); // default
+               boolean isCultivar = checkAndRemoveAttributeValue(attributes, CLASS, "cultivated");
+
+               if (isCultivar) {
+                       name = TaxonNameFactory.NewCultivarInstance(rank);
+               } else {
+                       name = createNameByCode(state, rank);
+               }
+               Taxon taxon = Taxon.NewInstance(name, state.getConfig().getSourceReference());
+               if (checkAndRemoveAttributeValue(attributes, CLASS, "dubious")) {
+                       taxon.setDoubtful(true);
+               } else if (checkAndRemoveAttributeValue(attributes, CLASS, "excluded")) {
+                       state.setCurrentTaxonExcluded(true);
+               }
+        state.setTaxonIsHybrid(checkAndRemoveAttributeValue(attributes, CLASS, "hybrid"));
+
+               // TODO insufficient, new, expected
+               handleNotYetImplementedAttribute(attributes, CLASS, event);
+               // From old version
+               // MarkerType markerType = getMarkerType(state, attrValue);
+               // if (markerType == null){
+               // logger.warn("Class attribute value for taxon not yet supported: " +
+               // attrValue);
+               // }else{
+               // taxon.addMarker(Marker.NewInstance(markerType, true));
+               // }
+
+               // save(name, state);
+               // save(taxon, state);
+               return taxon;
+       }
+
+       private String handleTaxonTitle(MarkupImportState state, XMLEventReader reader, XMLEvent parentEvent) throws XMLStreamException {
+               //attributes
+               String text = "";
+               Map<String, Attribute> attributes = getAttributes(parentEvent);
+               String rankAttr = getAndRemoveAttributeValue(attributes, RANK);
+               Rank rank = makeRank(state, rankAttr, false);
+               String num = getAndRemoveAttributeValue(attributes, NUM);
+               state.setCurrentTaxonNum(num);
+               checkNoAttributes(attributes, parentEvent);
+
+               // TODO handle attributes
+               while (reader.hasNext()) {
+                       XMLEvent next = readNoWhitespace(reader);
+                       if (next.isEndElement()) {
+                               if (isMyEndingElement(next, parentEvent)) {
+                                       Taxon taxon = state.getCurrentTaxon();
+                                       String titleText = null;
+                                       if (state.getConfig().isDoExtensionForTaxonTitle() && checkMandatoryText(text, parentEvent)) {
+                                               titleText = normalize(text);
+                                               UUID uuidTitle = MarkupTransformer.uuidTaxonTitle;
+                                               ExtensionType titleExtension = this.getExtensionType(state, uuidTitle, "Taxon Title ","taxon title", "title");
+                                               taxon.addExtension(titleText, titleExtension);
+                                       }
+                                       taxon.getName().setRank(rank);
+                                       // TODO check title exists
+                                       return titleText;
+                               } else {
+                                       if (isEndingElement(next, FOOTNOTE)) {
+                                               // NOT YET IMPLEMENTED
+                                               popUnimplemented(next.asEndElement());
+                                       } else {
+                                               handleUnexpectedEndElement(next.asEndElement());
+                                               state.setUnsuccessfull();
+                                       }
+                               }
+                       } else if (next.isStartElement()) {
+                               if (isStartingElement(next, FOOTNOTE)) {
+                                       handleNotYetImplementedElement(next);
+                               }else if (isStartingElement(next, FOOTNOTE_REF)) {
+                                       handleNotYetImplementedElement(next);
+                               } else {
+                                       handleUnexpectedStartElement(next);
+                                       state.setUnsuccessfull();
+                               }
+                       } else if (next.isCharacters()) {
+                               text += next.asCharacters().getData();
+
+                       } else {
+                               handleUnexpectedElement(next);
+                               state.setUnsuccessfull();
+                       }
+               }
+               return null;
+
+       }
+
+
+}