/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.master.timeseries.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

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

import com.opengamma.core.config.ConfigSource;
import com.opengamma.id.IdentifierBundle;
import com.opengamma.master.timeseries.TimeSeriesDocument;
import com.opengamma.master.timeseries.TimeSeriesMaster;
import com.opengamma.master.timeseries.TimeSeriesInfo;
import com.opengamma.master.timeseries.TimeSeriesInfoResolver;
import com.opengamma.master.timeseries.TimeSeriesSearchRequest;
import com.opengamma.master.timeseries.TimeSeriesSearchResult;
import com.opengamma.util.ArgumentChecker;

/**
 * Simple time-series resolver, returns the best match from the time-series info in the data store.
 * <p>
 * This resolver relies on configuration in the config database.
 * 
 * @param <T> the type of the time-series, such as LocalDate/LocalDateTime
 */
public class DefaultTimeSeriesInfoResolver<T> implements TimeSeriesInfoResolver {

  /** Logger. */
  private static final Logger s_logger = LoggerFactory.getLogger(DefaultTimeSeriesInfoResolver.class);

  /**
   * The time-series master.
   */
  private final TimeSeriesMaster<T> _tsMaster;
  /**
   * The source of configuration.
   */
  private final ConfigSource _configSource;

  /**
   * Creates an instance from a master and config source.
   * 
   * @param timeSeriesMaster  the time-series master, not null
   * @param configSource  the config source, not null
   */
  public DefaultTimeSeriesInfoResolver(TimeSeriesMaster<T> timeSeriesMaster, ConfigSource configSource) {
    ArgumentChecker.notNull(timeSeriesMaster, "timeseries master");
    ArgumentChecker.notNull(configSource, "configSource");
    _configSource = configSource;
    _tsMaster = timeSeriesMaster;
  }

  //-------------------------------------------------------------------------
  @Override
  public TimeSeriesInfo getInfo(IdentifierBundle securityBundle, String configName) {
    ArgumentChecker.notNull(securityBundle, "securityBundle");
    ArgumentChecker.notNull(configName, "configName");
    
    TimeSeriesSearchRequest<T> searchRequest = new TimeSeriesSearchRequest<T>(securityBundle);
    searchRequest.setLoadTimeSeries(false);
    TimeSeriesSearchResult<T> searchResult = _tsMaster.search(searchRequest);
    
    // load rules from config datastore
    TimeSeriesInfoConfiguration ruleSet = _configSource.getLatestByName(TimeSeriesInfoConfiguration.class, configName);
    if (ruleSet != null) {
      List<TimeSeriesInfo> infos = extractTimeSeriesInfo(searchResult);
      return bestMatch(infos, ruleSet);
    } else {
      s_logger.warn("can not resolve time-series info because rules set with name {} can not be loaded from config database", configName);
      return null;
    }
  }

  private List<TimeSeriesInfo> extractTimeSeriesInfo(TimeSeriesSearchResult<T> searchResult) {
    List<TimeSeriesDocument<T>> documents = searchResult.getDocuments();
    List<TimeSeriesInfo> infoList = new ArrayList<TimeSeriesInfo>(documents.size());
    for (TimeSeriesDocument<T> document : documents) {
      if (document.getDataField().equals(DEFAULT_DATA_FIELD)) {
        infoList.add(document.toInfo());
      }
    }
    return infoList;
  }

  private TimeSeriesInfo bestMatch(List<TimeSeriesInfo> infoList, TimeSeriesInfoRateProvider ruleSet) {
    TreeMap<Integer, TimeSeriesInfo> scores = new TreeMap<Integer, TimeSeriesInfo>();
    for (TimeSeriesInfo info : infoList) {
      int score = ruleSet.rate(info);
      s_logger.debug("score: {} for info: {} using rules: {} ", new Object[]{score, info, ruleSet});
      scores.put(score, info);
    }
    if (!scores.isEmpty()) {
      Integer max = scores.lastKey();
      return scores.get(max);
    }
    return null;
  }

}

@@ -969,24 +969,31 @@
 n the config
+uration
  database.%0A 
@@ -1495,16 +1495,28 @@
  from a 
+time-series 
 master a
@@ -1520,24 +1520,31 @@
 r and config
+uration
  source.%0A   
@@ -1645,16 +1645,23 @@
 e config
+uration
  source,
@@ -2277,24 +2277,48 @@
 ame%22);%0A    %0A
+    // find time-series%0A
     TimeSeri
@@ -2396,24 +2396,76 @@
 ityBundle);%0A
+    searchRequest.setDataField(DEFAULT_DATA_FIELD);%0A
     searchRe
@@ -2586,20 +2586,31 @@
 %0A    // 
-load
+pick best using
  rules f
@@ -2623,18 +2623,15 @@
 nfig
- datastore
+uration
 %0A   
@@ -2920,23 +2920,25 @@
 r.warn(%22
-can not
+Unable to
  resolve
@@ -3066,24 +3066,232 @@
 %0A    %7D%0A  %7D%0A%0A
+  /**%0A   * Converts the time-series results to the simpler info object for matching purposes.%0A   * %0A   * @param searchResult  the search result, not null%0A   * @return the list of info objects, not null%0A   */%0A
   private Li
@@ -3597,145 +3597,299 @@
    i
-f (document.getDataField().equals(DEFAULT_DATA_FIELD)) %7B%0A        infoList.add(document.toInfo());%0A      %7D%0A    %7D
+nfoList.add(document.toInfo());%0A    %7D%0A    return infoList;%0A  %7D%0A%0A  /**%0A   * Choose the best match using the configured rules.%0A   * %0A   * @param infoList  the list of info objects, not null%0A   * @param ruleSet  the configured rules, not null
 %0A   
- 
+* @
 return 
-infoList;%0A  %7D%0A
+the best match, null if no match%0A   */
 %0A  p
@@ -3985,24 +3985,79 @@
  ruleSet) %7B%0A
+    if (infoList.isEmpty()) %7B%0A      return null;%0A    %7D%0A
     TreeMap%3C
@@ -4233,17 +4233,17 @@
 .debug(%22
-s
+S
 core: %7B%7D
@@ -4357,122 +4357,44 @@
     
-if (!scores.isEmpty()) %7B%0A      Integer max = scores.lastKey();%0A      return scores.get(max);%0A    %7D%0A    return null
+return scores.lastEntry().getValue()
 ;%0A  

Refactor time-series master; Enhance info resolver