package de.ddb.pdc.metadata;

import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.xml.xpath.Jaxp13XPathTemplate;
import org.springframework.xml.xpath.XPathOperations;

import javax.xml.transform.dom.DOMSource;
import java.util.HashMap;
import java.util.Map;


/**
 * Implementation of the {@link MetaFetcher} interface.
 */
public class MetaFetcherImpl implements MetaFetcher {

  private static final String URL =
      "https://www.deutsche-digitale-bibliothek.de";

  private RestTemplate restTemplate;
  private String apiKey;

  private XPathOperations xpathTemplate;

  /**
   * Creates a new object of the class MetaFetcherImpl.
   * This class collects the needed information for answering the questions.
   * The data about works and authors is collected by calls to the DDB API.
   *
   * @param restTemplate RestTemplate to use for issuing requests
   * @param apiKey       DDB API key for authentication
   */
  public MetaFetcherImpl(RestTemplate restTemplate, String apiKey) {
    this.restTemplate = restTemplate;
    this.restTemplate.getMessageConverters()
        .add(new Jaxb2RootElementHttpMessageConverter());
    this.apiKey = apiKey;

    initNamespaces();
  }

  /**
   * initialize the namespaces for XPath
   */
  private void initNamespaces() {
    Map<String,String> namespaces = new HashMap<String,String>();
    namespaces.put("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
    namespaces.put("gndo", "http://d-nb.info/standards/elementset/gnd#");
    namespaces.put("ctx", "http://www.deutsche-digitale-bibliothek.de/cortex");
    namespaces.put("ns2", "http://www.deutsche-digitale-bibliothek.de/institution");
    namespaces.put("ns3", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
    namespaces.put("ns4", "http://www.deutsche-digitale-bibliothek.de/item");
    namespaces.put("ore", "http://www.openarchives.org/ore/terms/");
    namespaces.put("edm", "http://www.europeana.eu/schemas/edm/");
    namespaces.put("skos", "http://www.w3.org/2004/02/skos/core#");
    namespaces.put("dc", "http://purl.org/dc/elements/1.1/" );
    namespaces.put("dcterms", "http://purl.org/dc/terms/");
    Jaxp13XPathTemplate jaxp13XPathTemplate = new Jaxp13XPathTemplate();
    jaxp13XPathTemplate.setNamespaces(namespaces);
    this.xpathTemplate = jaxp13XPathTemplate;
  }

  /**
   * {@inheritDoc}
   */
  public DDBItem[] searchForItems(String query, int startItem, int maxCount,
      String sort) throws RestClientException {
    String url = ApiUrls.searchUrl(query, startItem, maxCount, sort, apiKey);
    SearchResults results = restTemplate.getForObject(url, SearchResults.class);
    return getDDBItems(results);
  }

  private DDBItem[] getDDBItems(SearchResults results) {
    if (results.getResultItems() == null) {
      return new DDBItem[0];
    }
    int numItems = results.getResultItems().size();
    DDBItem[] ddbItems = new DDBItem[numItems];

    int idx = 0;
    for (SearchResultItem rsi : results.getResultItems()) {
      DDBItem ddbItem = new DDBItem(rsi.getId());
      ddbItem.setMaxResults(results.getNumberOfResults());
      ddbItem.setTitle(deleteMatchTags(rsi.getTitle()));
      ddbItem.setSubtitle(deleteMatchTags(rsi.getSubtitle()));
      ddbItem.setImageUrl(URL + rsi.getThumbnail());
      ddbItem.setCategory(rsi.getCategory());
      ddbItem.setMedia(rsi.getMedia());
      ddbItem.setType(rsi.getType());
      ddbItems[idx] = ddbItem;
      idx++;
    }

    return ddbItems;
  }

  private static String deleteMatchTags(String string) {
    return string.replace("<match>", "").replace("</match>", "");
  }

  /**
   * {@inheritDoc}
   */
  public DDBItem fetchMetadata(String itemId) throws RestClientException {
    DDBItem ddbItem = new DDBItem(itemId);
    String url = ApiUrls.itemAipUrl(itemId, apiKey);
    DOMSource domSource = restTemplate.getForObject(url, DOMSource.class);
    if (domSource != null) {
      fillDDBItem(ddbItem, domSource);
      fetchAuthorMetadata(ddbItem);
    }
    return ddbItem;
  }

  private void fillDDBItem(DDBItem item, DOMSource result) {
    ItemAipXml itemAipXml = new ItemAipXml(result, xpathTemplate);
    item.setPublishedYear(itemAipXml.getPublishedYear());
    item.setInstitution(itemAipXml.getInstitution());
    for (String authorId : itemAipXml.getAuthorUrls()) {
      Author author = new Author(authorId);
      item.addAuthor(author);
    }
  }

  private void fetchAuthorMetadata(DDBItem item) {
    for (Author author : item.getAuthors()) {
      String dnbUrl = ApiUrls.dnbUrl(author.getDnbId());
      DOMSource domSource = restTemplate.getForObject(dnbUrl, DOMSource.class);
      fillAuthor(author, domSource);
    }
  }

  private void fillAuthor(Author author, DOMSource domSource) {
    if (domSource != null) {
      ItemDnbAuthorXml idax = new ItemDnbAuthorXml(domSource, xpathTemplate);
      author.setName(idax.getName());
      author.setDateOfBirth(idax.getDateOfBirth());
      author.setDateOfDeath(idax.getDateOfDeath());

      DOMSource location = null;
      String dnbLocationUrl;
      String placeOfBirth = idax.getPlaceOfBirth();
      if (placeOfBirth == null || placeOfBirth.equals("")) {
        String placeOfDeath = idax.getPlaceOfDeath();
        if (placeOfDeath != null || !placeOfDeath.equals("")) {
          dnbLocationUrl = ApiUrls.dnbUrl(placeOfDeath);
          location = restTemplate.getForObject(dnbLocationUrl, DOMSource.class);
        }
      } else {
        dnbLocationUrl = ApiUrls.dnbUrl(placeOfBirth);
        location = restTemplate.getForObject(dnbLocationUrl, DOMSource.class);
      }

      if (location != null) {
        ItemDnbLocationXml idlx = new ItemDnbLocationXml(location,
            xpathTemplate);
        author.setNationality(idlx.getIso2CountryCode());
      }
    }
  }
}

@@ -4210,22 +4210,25 @@
 MSource 
-result
+domSource
 ) %7B%0A    
@@ -4266,22 +4266,25 @@
 mAipXml(
-result
+domSource
 , xpathT
@@ -4289,24 +4289,169 @@
 hTemplate);%0A
+    item.setTitle(itemAipXml.getTitle());%0A    item.setSubtitle(itemAipXml.getSubtitle());%0A    item.setImageUrl(URL + itemAipXml.getThumbnail());%0A
     item.set

add title subtitle and thumbnail to fetchmetadata