/**
 * 
 */
package ecologylab.bigsemantics.service.mmd;

import java.net.URI;
import java.util.Map;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap.Builder;

import ecologylab.bigsemantics.collecting.DownloadStatus;
import ecologylab.bigsemantics.metadata.builtins.Document;
import ecologylab.bigsemantics.metametadata.MetaMetadata;
import ecologylab.bigsemantics.metametadata.MetaMetadataCompositeField;
import ecologylab.bigsemantics.service.SemanticServiceErrorMessages;
import ecologylab.bigsemantics.service.SemanticsServiceScope;
import ecologylab.bigsemantics.service.ServiceUtils;
import ecologylab.net.ParsedURL;
import ecologylab.serialization.formatenums.StringFormat;

/**
 * Helper class for mmd.xml and mmd.json root resources
 * 
 * @author ajit
 */
public class MMDServiceHelper implements MMDServiceParamNames
{

  public static final int                       MAX_CACHED_URL        = 1000;

  static Logger                                 logger;

  static SemanticsServiceScope                  semanticsServiceScope = SemanticsServiceScope.get();

  static ConcurrentLinkedHashMap<ParsedURL, MetaMetadata> mmdByUrl;

  static
  {
    logger = LoggerFactory.getLogger(MMDServiceHelper.class);
    Builder<ParsedURL, MetaMetadata> lruMapBuilder = new Builder<ParsedURL, MetaMetadata>();
    lruMapBuilder.maximumWeightedCapacity(MAX_CACHED_URL);
    mmdByUrl = lruMapBuilder.build();
  }
  
  public static Response getMmdResponse(String url,
                                        String name,
                                        String callback,
                                        String withUrl,
                                        UriInfo uriInfo,
                                        StringFormat format)
  {
    Response resp = null;
    if (url != null)
    {
      ParsedURL purl = ParsedURL.getAbsolute(url);
      if (purl != null)
      {
        MetaMetadata mmd = getMmdByUrl(purl);
        if (mmd != null)
        {
          UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder().queryParam(NAME, mmd.getName());
          if (callback != null)
          {
            uriBuilder = uriBuilder.queryParam(CALLBACK, callback);
            if (withUrl != null)
            {
              // Here, note that whatever the value of withurl is, in the redirection we use the
              // real URL. in this way you don't need to repeat the URL, since it is already
              // available through the url parameter.
              uriBuilder = uriBuilder.queryParam(WITH_URL, ServiceUtils.urlencode(url));
            }
          }
          URI nameURI = uriBuilder.build();
          resp = Response.status(Status.SEE_OTHER).location(nameURI).build();
        }
      }
    }
    else if (name != null)
    {
      MetaMetadata mmd = getMmdByName(name);
      if (mmd != null)
      {
        String mmdJson = ServiceUtils.serialize(mmd, format);
        String respString = mmdJson;
        if (callback != null)
        {
          String locParam = "";
          if (withUrl != null)
          {
            logger.info("withUrl = {}", withUrl);
            locParam = "\"" + withUrl + "\", ";
          }
          respString = callback + "(" + locParam + mmdJson + ");";
        }
        resp = Response.status(Status.OK).entity(respString).build();
      }
    }
    else
    {
      resp = Response
          .status(Status.BAD_REQUEST)
          .entity(SemanticServiceErrorMessages.BAD_REQUEST)
          .type(MediaType.TEXT_PLAIN)
          .build();
    }

    if (resp == null)
    {
      resp = Response
          .status(Status.NOT_FOUND)
          .entity(SemanticServiceErrorMessages.METAMETADATA_NOT_FOUND)
          .type(MediaType.TEXT_PLAIN)
          .build();
    }
    
    return resp;
  }

  public static MetaMetadata getMmdByName(String mmdName)
  {
    MetaMetadata docMM = semanticsServiceScope.getMetaMetadataRepository().getMMByName(mmdName);
    return docMM;
  }

  public static MetaMetadata getMmdByUrl(ParsedURL url)
  {
    MetaMetadata docMM = mmdByUrl.get(url);

    if (docMM == null)
    {
      // check if we already have a Document associated with this URL. if so, we want to use the
      // meta-metadata for that Document, because it may get changed when we make the HTTP
      // connection.
      Document doc = semanticsServiceScope.getOrConstructDocument(url);
      if (doc != null && doc.getDownloadStatus() == DownloadStatus.DOWNLOAD_DONE)
      {
        MetaMetadataCompositeField docMMComposite = doc.getMetaMetadata();
        if (docMMComposite instanceof MetaMetadata)
        {
          docMM = (MetaMetadata) docMMComposite;
        }
      }

      if (docMM == null)
      {
        // if no downloaded Document found, we can only use the URL to find a meta-metadata.
        docMM = semanticsServiceScope.getMetaMetadataRepository().getDocumentMM(url);
        if (docMM != null)
        {
          // cache the mmd
          mmdByUrl.putIfAbsent(url, docMM);
        }
      }
    }
    
    return docMM;
  }

}

@@ -81,31 +81,8 @@
 RI;%0D
-%0Aimport java.util.Map;%0D
 %0A%0D%0Ai
@@ -331,221 +331,8 @@
 %0D%0A%0D%0A
-import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;%0D%0Aimport com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap.Builder;%0D%0A%0D%0Aimport ecologylab.bigsemantics.collecting.DownloadStatus;%0D%0A
 impo
@@ -450,81 +450,8 @@
 a;%0D%0A
-import ecologylab.bigsemantics.metametadata.MetaMetadataCompositeField;%0D%0A
 impo
@@ -1133,79 +1133,8 @@
 %0D%0A%0D%0A
-  static ConcurrentLinkedHashMap%3CParsedURL, MetaMetadata%3E mmdByUrl;%0D%0A%0D%0A
   st
@@ -1211,201 +1211,8 @@
 );%0D%0A
-    Builder%3CParsedURL, MetaMetadata%3E lruMapBuilder = new Builder%3CParsedURL, MetaMetadata%3E();%0D%0A    lruMapBuilder.maximumWeightedCapacity(MAX_CACHED_URL);%0D%0A    mmdByUrl = lruMapBuilder.build();%0D%0A
   %7D%0D
@@ -1717,38 +1717,48 @@
     
-MetaMetadata mmd = getMmdByUrl
+Document initialDoc = getInitialDocument
 (pur
@@ -1766,35 +1766,42 @@
 );%0D%0A        if (
-mmd
+initialDoc
  != null)%0D%0A     
@@ -1798,32 +1798,107 @@
 ll)%0D%0A        %7B%0D%0A
+          MetaMetadata mmd = (MetaMetadata) initialDoc.getMetaMetadata();%0D%0A
           UriBui
@@ -3953,364 +3953,76 @@
 tic 
-MetaMetadata getMmdByUrl(ParsedURL url)%0D%0A  %7B%0D%0A    MetaMetadata docMM = mmdByUrl.get(url);%0D%0A%0D%0A    if (docMM == null)%0D%0A    %7B%0D%0A      // check if we already have a Document associated with this URL. if so, we want to use the%0D%0A      // meta-metadata for that Document, because it may get changed when we make the HTTP
+Document getInitialDocument(ParsedURL requestedUrl)%0D%0A  %7B
 %0D%0A    
- 
- // connection.%0D%0A      Document doc =
+return
  sem
@@ -4067,696 +4067,21 @@
 ent(
-url);%0D%0A      if (doc != null && doc.getDownloadStatus() == DownloadStatus.DOWNLOAD_DONE)%0D%0A      %7B%0D%0A        MetaMetadataCompositeField docMMComposite = doc.getMetaMetadata();%0D%0A        if (docMMComposite instanceof MetaMetadata)%0D%0A        %7B%0D%0A          docMM = (MetaMetadata) docMMComposite;%0D%0A        %7D%0D%0A      %7D%0D%0A%0D%0A      if (docMM == null)%0D%0A      %7B%0D%0A        // if no downloaded Document found, we can only use the URL to find a meta-metadata.%0D%0A        docMM = semanticsServiceScope.getMetaMetadataRepository().getDocumentMM(url);%0D%0A        if (docMM != null)%0D%0A        %7B%0D%0A          // cache the mmd%0D%0A          mmdByUrl.putIfAbsent(url, docMM);%0D%0A        %7D%0D%0A      %7D%0D%0A    %7D%0D%0A    %0D%0A    return docMM
+requestedUrl)
 ;%0D%0A 

Use initial document for getting mmd from url.