package org.ambraproject.wombat.service.remote;

import org.ambraproject.wombat.config.RuntimeConfiguration;
import org.ambraproject.wombat.freemarker.SitePageContext;
import org.apache.commons.io.IOUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

/**
 * Retrieves stored blocks of homepage content from a remote service.
 */
public class StoredHomepageService implements FetchHtmlService {

  @Autowired
  private RuntimeConfiguration runtimeConfiguration;
  @Autowired
  private SoaService soaService;

  /**
   * {@inheritDoc}
   * <p/>
   * Applies transforms that are particular to the "Lemur" API for homepages.
   */
  @Override
  public Reader readHtml(SitePageContext sitePageContext, String key) throws IOException {
    // TODO: Cache

    Document document;
    String address = String.format("repo/homepages/%s/latest", key);
    try (Reader html = soaService.requestReader(address)) {
      // It would be nice to feed the reader directly into the parser, but Jsoup's API makes this awkward.
      // The whole document will be in memory anyway, so buffering it into a string is no great performance loss.
      String htmlString = IOUtils.toString(html);
      document = Jsoup.parse(htmlString);
    }

    for (AttributeTransformation transformation : AttributeTransformation.values()) {
      transformation.apply(sitePageContext, document);
    }

    // We received a snippet, which Jsoup has automatically turned into a complete HTML document.
    // We want to return only the transformed snippet, so retrieve it from the body tag.
    String transformedHtml = document.getElementsByTag("body").html();
    return new StringReader(transformedHtml);
  }

  private static enum AttributeTransformation {
    IMAGE("img", "data-lemur-key", "src") {
      @Override
      protected String transformAttribute(SitePageContext sitePageContext, String value) {
        String path = String.format("indirect/homepages/%s/latest", value);
        return sitePageContext.buildLink(path);
      }
    },

    ARTICLE("a", "data-lemur-doi", "href") {
      @Override
      protected String transformAttribute(SitePageContext sitePageContext, String value) {
        return sitePageContext.buildLink("article?id=" + value);
      }
    };

    private final String tagName; // Search tags with this name
    private final String sourceAttributeKey; // Find attributes with this key
    private final String targetAttributeKey; // Replace source attribute with this key, with transformed value

    /**
     * Transform the source attribute value into the target attribute value.
     *
     * @param sitePageContext the context of the HTML page
     * @param value           the source attribute value
     * @return the target attribute value
     */
    protected abstract String transformAttribute(SitePageContext sitePageContext, String value);

    private AttributeTransformation(String tagName, String sourceAttributeKey, String targetAttributeKey) {
      this.tagName = tagName;
      this.sourceAttributeKey = sourceAttributeKey;
      this.targetAttributeKey = targetAttributeKey;
    }

    /**
     * For each tag with an attribute as described this object: delete the old attribute, apply this object's
     * transformation to the attribute value, and write the target attribute with the transformed value.
     *
     * @param document the document to modify in place
     */
    public void apply(SitePageContext sitePageContext, Document document) {
      for (Element element : document.getElementsByAttribute(sourceAttributeKey)) {
        if (element.tagName().equals(tagName)) {
          String oldValue = element.attr(sourceAttributeKey);
          String newValue = transformAttribute(sitePageContext, oldValue);

          element.removeAttr(sourceAttributeKey);
          element.attr(targetAttributeKey, newValue);
        }
      }
    }
  }

}

@@ -846,16 +846,22 @@
 eadHtml(
+final 
 SitePage
@@ -942,33 +942,51 @@
 he%0A%0A    
-Document document
+String cacheKey = %22homepage:%22 + key
 ;%0A    St
@@ -1052,25 +1052,32 @@
 y);%0A
+%0A
     
+S
 tr
-y (Reader h
+ing transformedH
 tml 
@@ -1100,27 +1100,165 @@
 uest
+Cached
 Reader(
-address)) %7B%0A
+cacheKey, address, new CacheDeserializer%3CReader, String%3E() %7B%0A      @Override%0A      public String read(Reader htmlReader) throws IOException %7B%0A  
     
@@ -1360,16 +1360,18 @@
 wkward.%0A
+  
       //
@@ -1478,24 +1478,26 @@
 loss.%0A      
+  
 String htmlS
@@ -1525,16 +1525,22 @@
 ing(html
+Reader
 );%0A     
@@ -1540,16 +1540,27 @@
 ;%0A      
+ 
+ Document 
 document
@@ -1587,23 +1587,21 @@
 tring);%0A
+%0A
     
-%7D%0A%0A
     for 
@@ -1674,24 +1674,28 @@
 values()) %7B%0A
+    
       transf
@@ -1737,27 +1737,35 @@
 ument);%0A    
-%7D%0A%0A
+    %7D%0A%0A    
     // We re
@@ -1850,24 +1850,28 @@
 cument.%0A    
+ 
+   
 // We want t
@@ -1951,32 +1951,18 @@
     
-String transformedHtml =
+    return
  doc
@@ -2000,16 +2000,32 @@
 html();%0A
+      %7D%0A    %7D);%0A
     retu

Use cache headers when querying content repo through Rhino