package gw.solr

uses com.guidewire.pl.web.controller.UserDisplayableException
uses gw.api.system.PLLoggerCategory
uses gw.plugin.InitializablePlugin
uses gw.plugin.PluginParameter
uses gw.solr.request.AbstractSearchRequest
uses gw.solr.utils.PLSolrUtils
uses org.apache.solr.client.solrj.SolrQuery
uses org.slf4j.Logger


/**
 * Base class for a Solr search plugin.  This type of plugin handles creating
 * and submitting Solr queries.
 */
@ReadOnly
@PluginParameter(:name="debug", :type=Boolean)
@PluginParameter(:name="fetchSize", :type=Integer)
@PluginParameter(:name="chunkSize", :type=Integer)
@PluginParameter(:name="pageIteratorCacheTimeout", :type=Integer)
class AbstractSolrSearchPlugin implements InitializablePlugin {

  static final var DEBUG_PARAM = "debug"
  static final var FETCH_SIZE_PARAM = "fetchSize"
  static final var CHUNK_SIZE_PARAM = "chunkSize"
  static final var PAGE_ITERATOR_CACHE_TIMEOUT_PARAM = "pageIteratorCacheTimeout"

  private static var _instance : AbstractSolrSearchPlugin
  
  final protected var _logger : Logger = PLLoggerCategory.SOLR_QUERY
  final protected var _resultMap : Map = new HashMap<String, String>()
  private var _pluginName : String as PluginName
  private var _debug : boolean as Debug
  private var _fetchSize : int as FetchSize
  private var _chunkSize : int as ChunkSize
  private var _pageIteratorCacheTimeout : int as PageIteratorCacheTimeout

  construct(name : String) {
    _pluginName = name
    _instance = this
    _logger.info("***** ${_pluginName} is initialized. *****")
  }

  // Accessed reflectively from tests.
  private static function getInstance() : AbstractSolrSearchPlugin {
    return _instance
  }
  
  /**
   * Constructs a solr query URL
   * 
   * @param searchRequest Describes the query terms, filters, etc.
   * 
   * @return URL for this query
   */
  function constructSearchQuery(searchRequest : AbstractSearchRequest) : SolrQuery {
    var solrQuery : SolrQuery = null
    searchRequest.generateQuery()
    var searchQuery = searchRequest.getQueryString(false)
    var searchFilter = searchRequest.getQueryFilter(false)
    var groupField = searchRequest.getGroupField()
    var groupLimit = searchRequest.getGroupLimit()
    if((searchQuery != null && searchQuery.length() > 0)) {
      solrQuery = PLSolrUtils.buildSearchParams(searchQuery, searchFilter, groupField, groupLimit, FetchSize, Debug)
    }
    return solrQuery
  }  

  /**
   * Constructs a solr query URL for a specific result subset
   * 
   * @param searchRequest Describes the query terms, filters, etc.
   * @param startWith Starting row of result set desired
   * @param dynamicFetchSize Total number of rows to fetch
   * 
   * @return URL for this query
   */
  function constructPagingSearchQuery(searchRequest : AbstractSearchRequest, startWith : int, dynamicFetchSize : int) : SolrQuery {
    var solrQuery : SolrQuery = null
    searchRequest.generateQuery()
    var searchQuery = searchRequest.getQueryString(false)
    var searchFilter = searchRequest.getQueryFilter(false)
    var groupField = searchRequest.getGroupField()
    var groupLimit = searchRequest.getGroupLimit()
    var sortOrder = searchRequest.getSortString (false)
    if((searchQuery != null && searchQuery.length() > 0)) {
      solrQuery = PLSolrUtils.buildPagingSearchParams(searchQuery, searchFilter, groupField, groupLimit, sortOrder, startWith, dynamicFetchSize, Debug)
    }
    return solrQuery
  }  
  
  override property set Parameters(params : Map<Object,Object>) {
    var s = params.get(DEBUG_PARAM) as String
    _debug = Boolean.parseBoolean(s)

    var fetchSizeStr = params.get(FETCH_SIZE_PARAM)
    if(fetchSizeStr != null) {
      try {
        _fetchSize = Integer.parseInt(fetchSizeStr as String)
        if(_fetchSize < 1) {
          throw new UserDisplayableException("The value of the \"${FETCH_SIZE_PARAM}\" param in ${PluginName}.xml must be a positive integer.")
        }
      } catch(e : NumberFormatException) {
        throw new UserDisplayableException("The value of the \"${FETCH_SIZE_PARAM}\" param in ${PluginName}.xml must be a positive integer.", e)
      }
    } else {
      _logger.trace("Plugin parameter \"${FETCH_SIZE_PARAM}\" was not declared.  Using default value of 100.")
      _fetchSize = 100
    }

    var chunkSizeStr = params.get(CHUNK_SIZE_PARAM)
    if(chunkSizeStr != null) {
      try {
        _chunkSize = Integer.parseInt(chunkSizeStr as String)
        if(_chunkSize < 1) {
          throw new UserDisplayableException("The value of the \"${CHUNK_SIZE_PARAM}\" param in ${PluginName}.xml must be a positive integer.")
        }
      } catch(e : NumberFormatException) {
        throw new UserDisplayableException("The value of the \"${CHUNK_SIZE_PARAM}\" param in ${PluginName}.xml must be a positive integer.", e)
      }
    } else {
      _logger.trace("Plugin parameter \"${CHUNK_SIZE_PARAM}\" was not declared.  Using default value of 25.")
      _chunkSize = 25
    }

    var pageIteratorCacheTimeoutStr = params.get(PAGE_ITERATOR_CACHE_TIMEOUT_PARAM)
    if(pageIteratorCacheTimeoutStr != null) {
      try {
        _pageIteratorCacheTimeout = Integer.parseInt(pageIteratorCacheTimeoutStr as String)
      } catch(e : NumberFormatException) {
        throw new UserDisplayableException("The value of the \"${PAGE_ITERATOR_CACHE_TIMEOUT_PARAM}\" param in ${PluginName}.xml must be an integer.", e)
      }
    } else {
      _logger.trace("Plugin parameter \"${PAGE_ITERATOR_CACHE_TIMEOUT_PARAM}\" was not declared.  Using default value of 5 minutes.")
      _pageIteratorCacheTimeout = 300 // 5 minutes
    }

  }

}
