<commit_before>package controllers.search

import models.PortalTheme
import scala.collection.JavaConversions._
import play.mvc.Http.Request
import play.Logger
import play.mvc.results.Result

/**
 *
 * @author <NAME> <<EMAIL>>
 * @since 10/17/11 2:25 PM  
 */
object SearchService {

  def getApiResult(request: Request, theme: PortalTheme) : Result =
    new SearchService(request, theme).getApiResult

}

class SearchService(request: Request, theme: PortalTheme) {

  import play.mvc.results.Result
  import xml.PrettyPrinter

  val prettyPrinter = new PrettyPrinter(150, 5)
  val params = request.params
  val paramMap = params.all()
  val format = paramMap.getOrElse("format", Array[String]("default")).head

  /**
   * This function parses the response for with output format needs to be rendered
   */

  def getApiResult : Result = {

      val response = try {
      if (theme.apiWsKey) {
        val wskey = paramMap.getOrElse("wskey", Array[String]("unknown")).head
        // todo add proper wskey checking
        if (wskey.isEmpty) {
          import models.AccessKeyException
          Logger.warn(String.format("Service Access Key %s invalid!", wskey));
          throw new AccessKeyException(String.format("Access Key %s not accepted", wskey));
        }
      }
      format match {
        case "json" => getJSONResultResponse()
        case "jsonp" =>
          getJSONResultResponse(callback = paramMap.getOrElse("callback", Array[String]("delvingCallback")).head)
          // todo add simile and similep support later
        case _ => getXMLResultResponse()
      }
    }
    catch {
      case ex : Exception =>
        Logger.error(ex, "something went wrong")
        errorResponse(errorMessage = ex.getLocalizedMessage, format = format)
    }
    response
  }

  def getJSONResultResponse(authorized: Boolean = true, callback : String = ""): Result = {
    import play.mvc.results.RenderJson
    import org.apache.solr.client.solrj.SolrQuery
    require(params._contains("query") || params._contains("id") || params._contains("explain"))

    val response : String = paramMap.keys.toList match {
      case x : List[String] if x.contains("explain") => ExplainResponse(theme).renderAsJson
      case x : List[String] if x.contains("id") && !paramMap.get("id").head.isEmpty =>
        val fullItemView = getFullResultsFromSolr
        val response1 = CHResponse(params = params, theme = theme, chQuery = CHQuery(solrQuery = new SolrQuery("*:*"), responseFormat = "json"), response = fullItemView.response)
        FullView(fullItemView, response1).renderAsJSON(authorized)
      case _ =>
        val briefView = getBriefResultsFromSolr
        SearchSummary(result = briefView, chResponse = briefView.chResponse).renderAsJSON(authorized)
    }
    new RenderJson(if (!callback.isEmpty) "%s(%s)".format(callback, response) else response)

  }

  def getXMLResultResponse(authorized: Boolean = true): Result  = {
    import xml.Elem
    import play.mvc.results.RenderXml
    require(params._contains("query") || params._contains("id") || params._contains("explain"))

    val response : Elem = paramMap.keys.toList match {
      case x : List[String] if x.contains("explain") => ExplainResponse(theme).renderAsXml
      case x : List[String] if x.contains("id") && !paramMap.get("id").head.isEmpty =>
        import org.apache.solr.client.solrj.SolrQuery
        val fullItemView = getFullResultsFromSolr
        val response1 = CHResponse(params = params, theme = theme, chQuery = CHQuery(solrQuery = new SolrQuery("*:*"), responseFormat = "xml"), response = fullItemView.response)
        FullView(fullItemView, response1).renderAsXML(authorized)
      case _ =>
        val briefView = getBriefResultsFromSolr
        SearchSummary(result = briefView, chResponse = briefView.chResponse).renderAsXML(authorized)
    }

    new RenderXml("<?xml version='1.0' encoding='utf-8' ?>\n" + prettyPrinter.format(response))
  }

  private def getBriefResultsFromSolr: BriefItemView = {
    require(!paramMap.get("query").head.isEmpty)
    val chQuery = SolrQueryService.createCHQuery(request, theme, true)
    BriefItemView(CHResponse(params, theme, SolrQueryService.getSolrResponseFromServer(chQuery.solrQuery, theme.solrSelectUrl, true), chQuery))
  }

  private def getFullResultsFromSolr : FullItemView = {
    import org.apache.solr.client.solrj.SolrQuery
    require(params._contains("id") || params._contains("did"))
    // todo must be coded differently in the future
    val response = SolrQueryService.getSolrResponseFromServer(new SolrQuery("europeana_uri:\"%s\"".format(params.get("id"))), theme.solrSelectUrl)
    FullItemView(SolrBindingService.getFullDoc(response), response)
  }


   def errorResponse(error : String = "Unable to respond to the API request",
                    errorMessage: String = "Unable to determine the cause of the Failure", format : String = "xml") : Result = {

     import play.mvc.results.{RenderXml, RenderJson}

     def toXML : String = {
      val response =
        <results>
         <error>
           <title>{error}</title>
           <description>{errorMessage}</description>
         </error>
       </results>
    "<?xml version='1.0' encoding='utf-8' ?>\n" + prettyPrinter.format(response)
    }

    def toJSON : String = {
      import net.liftweb.json.JsonAST._
      import net.liftweb.json.{Extraction, Printer}
      import collection.immutable.ListMap
      //      aro.response setContentType ("text/javascript")
      implicit val formats = net.liftweb.json.DefaultFormats
      val docMap = ListMap("status" -> error, "message" -> errorMessage)
      Printer pretty (render(Extraction.decompose(docMap)))
    }

    val response = format match {
       case x : String if x.startsWith("json") || x.startsWith("simile") => new RenderJson(toJSON)
       case _ => new RenderXml(toXML)
     }

//    aro.response setStatus (HttpServletResponse.SC_BAD_REQUEST)
     // todo set error response
    response
  }

}

case class SearchSummary(result : BriefItemView, language: String = "en", chResponse: CHResponse) {

  import collection.mutable.LinkedHashMap
  import xml.Elem

  private val pagination = result.getPagination
  private val searchTerms = pagination.getPresentationQuery.getUserSubmittedQuery

  def minusAmp(link : String) = link.replaceAll("amp;", "").replaceAll(" ","%20").replaceAll("qf=","qf[]=")

  def localiseKey(metadataField: String, defaultLabel: String = "unknown", language: String = "en"): String = {
    import java.util.Locale
    val locale = new Locale(language)
//    val localizedName: String = aro.lookup.toLocalizedName(metadataField.replace(":", "_"), locale)
    val localizedName: String = metadataField.replace(":", "_")
    if (localizedName != null && !defaultLabel.startsWith("#")) localizedName else defaultLabel
  }

  val layoutMap = LinkedHashMap[String, String]("#thumbnail" -> "europeana:object", "#title" -> "dc:title", "#uri" -> "europeana:uri",
    "#isShownAt" -> "europeana:isShownAt", "#description" -> "dc:description", "Creator" -> "dc:creator",
    "Subject(s)" -> "dc:subject", "County" -> "abm:county", "Municipality" -> "abm:municipality", "Place" -> "abm:namedPlace",
    "Person(s)" -> "abm:aboutPerson")

  def renderAsXML(authorized : Boolean) : Elem = {

    val response : Elem =
      <results xmlns:icn="http://www.icn.nl/" xmlns:europeana="http://www.europeana.eu/schemas/ese/" xmlns:dc="http://purl.org/dc/elements/1.1/"
               xmlns:raw="http://delving.eu/namespaces/raw" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:ese="http://www.europeana.eu/schemas/ese/"
               xmlns:abm="http://to_be_decided/abm/" xmlns:abc="http://www.ab-c.nl/">
        <query numFound={pagination.getNumFound.toString}>
            <terms>{searchTerms}</terms>
            <breadCrumbs>
              {pagination.getBreadcrumbs.map(bc => <breadcrumb field={bc.field} href={minusAmp(bc.href)} value={bc.value}>{bc.display}</breadcrumb>)}
            </breadCrumbs>
        </query>
        <pagination>
            <start>{pagination.getStart}</start>
            <rows>{pagination.getRows}</rows>
            <numFound>{pagination.getNumFound}</numFound>
            {if (pagination.isNext) <nextPage>{pagination.getNextPage}</nextPage>}
            {if (pagination.isPrevious) <previousPage>{pagination.getPreviousPage}</previousPage>}
            <currentPage>{pagination.getStart}</currentPage>
            <links>
              {pagination.getPageLinks.map(pageLink =>
              <link start={pageLink.start.toString} isLinked={pageLink.isLinked.toString}>{pageLink.display}</link>)}
            </links><commit_msg>Added the delving namespace to the xml API output<commit_after>package controllers.search

import models.PortalTheme
import scala.collection.JavaConversions._
import play.mvc.Http.Request
import play.Logger
import play.mvc.results.Result

/**
 *
 * @author <NAME> <<EMAIL>>
 * @since 10/17/11 2:25 PM  
 */
object SearchService {

  def getApiResult(request: Request, theme: PortalTheme) : Result =
    new SearchService(request, theme).getApiResult

}

class SearchService(request: Request, theme: PortalTheme) {

  import play.mvc.results.Result
  import xml.PrettyPrinter

  val prettyPrinter = new PrettyPrinter(150, 5)
  val params = request.params
  val paramMap = params.all()
  val format = paramMap.getOrElse("format", Array[String]("default")).head

  /**
   * This function parses the response for with output format needs to be rendered
   */

  def getApiResult : Result = {

      val response = try {
      if (theme.apiWsKey) {
        val wskey = paramMap.getOrElse("wskey", Array[String]("unknown")).head
        // todo add proper wskey checking
        if (wskey.isEmpty) {
          import models.AccessKeyException
          Logger.warn(String.format("Service Access Key %s invalid!", wskey));
          throw new AccessKeyException(String.format("Access Key %s not accepted", wskey));
        }
      }
      format match {
        case "json" => getJSONResultResponse()
        case "jsonp" =>
          getJSONResultResponse(callback = paramMap.getOrElse("callback", Array[String]("delvingCallback")).head)
          // todo add simile and similep support later
        case _ => getXMLResultResponse()
      }
    }
    catch {
      case ex : Exception =>
        Logger.error(ex, "something went wrong")
        errorResponse(errorMessage = ex.getLocalizedMessage, format = format)
    }
    response
  }

  def getJSONResultResponse(authorized: Boolean = true, callback : String = ""): Result = {
    import play.mvc.results.RenderJson
    import org.apache.solr.client.solrj.SolrQuery
    require(params._contains("query") || params._contains("id") || params._contains("explain"))

    val response : String = paramMap.keys.toList match {
      case x : List[String] if x.contains("explain") => ExplainResponse(theme).renderAsJson
      case x : List[String] if x.contains("id") && !paramMap.get("id").head.isEmpty =>
        val fullItemView = getFullResultsFromSolr
        val response1 = CHResponse(params = params, theme = theme, chQuery = CHQuery(solrQuery = new SolrQuery("*:*"), responseFormat = "json"), response = fullItemView.response)
        FullView(fullItemView, response1).renderAsJSON(authorized)
      case _ =>
        val briefView = getBriefResultsFromSolr
        SearchSummary(result = briefView, chResponse = briefView.chResponse).renderAsJSON(authorized)
    }
    new RenderJson(if (!callback.isEmpty) "%s(%s)".format(callback, response) else response)

  }

  def getXMLResultResponse(authorized: Boolean = true): Result  = {
    import xml.Elem
    import play.mvc.results.RenderXml
    require(params._contains("query") || params._contains("id") || params._contains("explain"))

    val response : Elem = paramMap.keys.toList match {
      case x : List[String] if x.contains("explain") => ExplainResponse(theme).renderAsXml
      case x : List[String] if x.contains("id") && !paramMap.get("id").head.isEmpty =>
        import org.apache.solr.client.solrj.SolrQuery
        val fullItemView = getFullResultsFromSolr
        val response1 = CHResponse(params = params, theme = theme, chQuery = CHQuery(solrQuery = new SolrQuery("*:*"), responseFormat = "xml"), response = fullItemView.response)
        FullView(fullItemView, response1).renderAsXML(authorized)
      case _ =>
        val briefView = getBriefResultsFromSolr
        SearchSummary(result = briefView, chResponse = briefView.chResponse).renderAsXML(authorized)
    }

    new RenderXml("<?xml version='1.0' encoding='utf-8' ?>\n" + prettyPrinter.format(response))
  }

  private def getBriefResultsFromSolr: BriefItemView = {
    require(!paramMap.get("query").head.isEmpty)
    val chQuery = SolrQueryService.createCHQuery(request, theme, true)
    BriefItemView(CHResponse(params, theme, SolrQueryService.getSolrResponseFromServer(chQuery.solrQuery, theme.solrSelectUrl, true), chQuery))
  }

  private def getFullResultsFromSolr : FullItemView = {
    import org.apache.solr.client.solrj.SolrQuery
    require(params._contains("id") || params._contains("did"))
    // todo must be coded differently in the future
    val response = SolrQueryService.getSolrResponseFromServer(new SolrQuery("europeana_uri:\"%s\"".format(params.get("id"))), theme.solrSelectUrl)
    FullItemView(SolrBindingService.getFullDoc(response), response)
  }


   def errorResponse(error : String = "Unable to respond to the API request",
                    errorMessage: String = "Unable to determine the cause of the Failure", format : String = "xml") : Result = {

     import play.mvc.results.{RenderXml, RenderJson}

     def toXML : String = {
      val response =
        <results>
         <error>
           <title>{error}</title>
           <description>{errorMessage}</description>
         </error>
       </results>
    "<?xml version='1.0' encoding='utf-8' ?>\n" + prettyPrinter.format(response)
    }

    def toJSON : String = {
      import net.liftweb.json.JsonAST._
      import net.liftweb.json.{Extraction, Printer}
      import collection.immutable.ListMap
      //      aro.response setContentType ("text/javascript")
      implicit val formats = net.liftweb.json.DefaultFormats
      val docMap = ListMap("status" -> error, "message" -> errorMessage)
      Printer pretty (render(Extraction.decompose(docMap)))
    }

    val response = format match {
       case x : String if x.startsWith("json") || x.startsWith("simile") => new RenderJson(toJSON)
       case _ => new RenderXml(toXML)
     }

//    aro.response setStatus (HttpServletResponse.SC_BAD_REQUEST)
     // todo set error response
    response
  }

}

case class SearchSummary(result : BriefItemView, language: String = "en", chResponse: CHResponse) {

  import collection.mutable.LinkedHashMap
  import xml.Elem

  private val pagination = result.getPagination
  private val searchTerms = pagination.getPresentationQuery.getUserSubmittedQuery

  def minusAmp(link : String) = link.replaceAll("amp;", "").replaceAll(" ","%20").replaceAll("qf=","qf[]=")

  def localiseKey(metadataField: String, defaultLabel: String = "unknown", language: String = "en"): String = {
    import java.util.Locale
    val locale = new Locale(language)
//    val localizedName: String = aro.lookup.toLocalizedName(metadataField.replace(":", "_"), locale)
    val localizedName: String = metadataField.replace(":", "_")
    if (localizedName != null && !defaultLabel.startsWith("#")) localizedName else defaultLabel
  }

  val layoutMap = LinkedHashMap[String, String]("#thumbnail" -> "europeana:object", "#title" -> "dc:title", "#uri" -> "europeana:uri",
    "#isShownAt" -> "europeana:isShownAt", "#description" -> "dc:description", "Creator" -> "dc:creator",
    "Subject(s)" -> "dc:subject", "County" -> "abm:county", "Municipality" -> "abm:municipality", "Place" -> "abm:namedPlace",
    "Person(s)" -> "abm:aboutPerson")

  def renderAsXML(authorized : Boolean) : Elem = {

    val response : Elem =
      <results xmlns:icn="http://www.icn.nl/" xmlns:europeana="http://www.europeana.eu/schemas/ese/" xmlns:dc="http://purl.org/dc/elements/1.1/"
               xmlns:raw="http://delving.eu/namespaces/raw" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:ese="http://www.europeana.eu/schemas/ese/"
               xmlns:abm="http://to_be_decided/abm/" xmlns:abc="http://www.ab-c.nl/" xmlns:delving="http://www.delving.eu/schemas/">
        <query numFound={pagination.getNumFound.toString}>
            <terms>{searchTerms}</terms>
            <breadCrumbs>
              {pagination.getBreadcrumbs.map(bc => <breadcrumb field={bc.field} href={minusAmp(bc.href)} value={bc.value}>{bc.display}</breadcrumb>)}
            </breadCrumbs>
        </query>
        <pagination>
            <start>{pagination.getStart}</start>
            <rows>{pagination.getRows}</rows>
            <numFound>{pagination.getNumFound}</numFound>
            {if (pagination.isNext) <nextPage>{pagination.getNextPage}</nextPage>}
            {if (pagination.isPrevious) <previousPage>{pagination.getPreviousPage}</previousPage>}
            <currentPage>{pagination.getStart}</currentPage>
            <links>
              {pagination.getPageLinks.map(pageLink =>
              <link start={pageLink.start.toString} isLinked={pageLink.isLinked.toString}>{pageLink.display}</link>)}
            </links>
{'fraction_non_alphanumeric': 0.13611573569091223, 'fraction_numerical': 0.0031000631494345256, 'mean_word_length': 3.5036194415718716, 'pattern_counts': {'":': 4, '<': 81, '<?xml version=': 4, '>': 135, 'https://': 0, 'lorem ipsum': 0, 'www.': 9, 'xml': 32}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2222945', 'n_tokens_mistral': 5311, 'n_tokens_neox': 5168, 'n_words': 1052}