package org.ambraproject.wombat.service;

import org.ambraproject.wombat.model.Reference;
import org.ambraproject.wombat.util.NodeListAdapter;
import org.ambraproject.wombat.util.ParseXmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import javax.management.modelmbean.XMLParseException;
import javax.xml.parsers.DocumentBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


public class ParseXmlServiceImpl implements ParseXmlService {
  private static final Logger log = LoggerFactory.getLogger(ParseXmlServiceImpl.class);
  @Autowired
  private ParseReferenceService parseReferenceService;


  /**
   * {@inheritDoc}
   */
  @Override
  public List<Reference> parseArticleReferences(InputStream xml) throws IOException {
    Objects.requireNonNull(xml);

    Document doc;
    try {
      DocumentBuilder builder = XmlUtil.newDocumentBuilder();
      doc = builder.parse(xml);
    } catch (SAXException e) {
      throw new RuntimeException(e);
    }

    // to combine adjacent text nodes and remove empty ones in the dom
    doc.getDocumentElement().normalize();

    List<Reference> references = new ArrayList<>();
    List<Node> refListNodes = NodeListAdapter.wrap(doc.getElementsByTagName("ref-list"));

    if (ParseXmlUtil.isNullOrEmpty(refListNodes)) {
      log.info("No <ref-list> element was found in the xml.");
      return references;
    }

    if (refListNodes.size() > 1) {
      throw new XmlContentException("More than one <ref-list> element was found in the xml.");
    }

    Node refListNode = refListNodes.get(0);
    if (refListNode.getNodeType() != Node.ELEMENT_NODE) {
      throw new XmlContentException("<ref-list> is not an element.");
    }

    Element refListElement = (Element) refListNode;

    List<Node> refNodes = NodeListAdapter.wrap(refListElement.getElementsByTagName("ref"));
    references = refNodes.stream()
        .map(ref -> {
          try {
            return parseReferenceService.buildReferences((Element) ref);
          } catch (XMLParseException e) {
            throw new RuntimeException(e);
          }
        }) // Stream<List<Reference>>
        .flatMap(r -> r.stream()).collect(Collectors.toList());

    return references;
  }
}

@@ -598,24 +598,53 @@
 .ArrayList;%0A
+import java.util.Collection;%0A
 import java.
@@ -1710,145 +1710,13 @@
     
-if (refListNodes.size() %3E 1) %7B%0A      throw new XmlContentException(%22More than one %3Cref-list%3E element was found in the xml.%22);%0A    %7D%0A%0A    
+for (
 Node
@@ -1728,17 +1728,17 @@
 istNode 
-=
+:
  refList
@@ -1746,21 +1746,18 @@
 odes
-.get(0);%0A
+) %7B%0A 
     
+ 
 if (
@@ -1802,24 +1802,26 @@
 ENT_NODE) %7B%0A
+  
       throw 
@@ -1878,27 +1878,31 @@
 ent.%22);%0A    
+  
 %7D%0A%0A
+  
     Element 
@@ -1942,24 +1942,26 @@
 tNode;%0A%0A    
+  
 List%3CNode%3E r
@@ -2040,16 +2040,18 @@
 ));%0A    
+  
 referenc
@@ -2052,19 +2052,24 @@
 ferences
- = 
+.addAll(
 refNodes
@@ -2086,16 +2086,18 @@
         
+  
 .map(ref
@@ -2102,16 +2102,18 @@
 ef -%3E %7B%0A
+  
         
@@ -2128,24 +2128,26 @@
             
+  
 return parse
@@ -2195,16 +2195,18 @@
 ) ref);%0A
+  
         
@@ -2243,32 +2243,34 @@
 ) %7B%0A            
+  
 throw new Runtim
@@ -2294,18 +2294,22 @@
         
+ 
+ 
 %7D%0A
+  
         
@@ -2346,16 +2346,18 @@
         
+  
 .flatMap
@@ -2361,23 +2361,26 @@
 Map(
-r -%3E r.
+Collection::
 stream
-()
 ).co
@@ -2405,18 +2405,24 @@
 oList())
+)
 ;%0A
+    %7D
 %0A    ret

implement multiple ref-lists