private HistoricalTimeSeriesInfoDocument getOrLoadTimeSeries(
      final ExternalId ticker, final ExternalIdBundle idBundle) {

    final ExternalIdBundle searchBundle =
        idBundle.withoutScheme(
            ExternalSchemes
                .ISIN); // For things which move country, e.g. ISIN(VALE5 BZ Equity) == ISIN(RIODF
                        // US Equity)
    final HistoricalTimeSeriesInfoSearchRequest htsRequest =
        new HistoricalTimeSeriesInfoSearchRequest(searchBundle);
    htsRequest.setDataField("PX_LAST");
    final HistoricalTimeSeriesInfoSearchResult htsSearch =
        getToolContext().getHistoricalTimeSeriesMaster().search(htsRequest);
    switch (htsSearch.getDocuments().size()) {
      case 0:
        return loadTimeSeries(idBundle);
      case 1:
        break;
      default:
        throw new OpenGammaRuntimeException("Multiple time series match " + htsSearch);
    }
    final HistoricalTimeSeriesInfoDocument timeSeriesInfo = htsSearch.getDocuments().get(0);
    s_logger.debug("Loaded time series info {} for underlying {}", timeSeriesInfo, ticker);
    return timeSeriesInfo;
  }
  public void getHistoricalTimeSeriesByExternalIdWithMetaData() throws Exception {
    HistoricalTimeSeriesInfoSearchRequest request =
        new HistoricalTimeSeriesInfoSearchRequest(IDENTIFIERS);
    request.setValidityDate(LocalDate.now());
    request.setDataSource(BBG_DATA_SOURCE);
    request.setDataProvider(CMPL_DATA_PROVIDER);
    request.setDataField(CLOSE_DATA_FIELD);

    HistoricalTimeSeriesInfoSearchResult searchResult = new HistoricalTimeSeriesInfoSearchResult();
    HistoricalTimeSeriesInfoDocument doc = new HistoricalTimeSeriesInfoDocument();
    doc.setUniqueId(UID);

    when(_mockResolver.resolve(
            IDENTIFIERS,
            LocalDate.now(),
            BBG_DATA_SOURCE,
            CMPL_DATA_PROVIDER,
            CLOSE_DATA_FIELD,
            null))
        .thenReturn(new HistoricalTimeSeriesResolutionResult(doc.getInfo()));

    doc.getInfo().setTimeSeriesObjectId(UID.getObjectId());
    searchResult.getDocuments().add(doc);
    when(_mockMaster.search(request)).thenReturn(searchResult);

    ManageableHistoricalTimeSeries hts = new ManageableHistoricalTimeSeries();
    hts.setUniqueId(UID);
    hts.setTimeSeries(randomTimeSeries());
    when(_mockMaster.getTimeSeries(
            UID.getObjectId(),
            VersionCorrection.LATEST,
            HistoricalTimeSeriesGetFilter.ofRange(null, null)))
        .thenReturn(hts);

    HistoricalTimeSeries test =
        _tsSource.getHistoricalTimeSeries(
            IDENTIFIERS, BBG_DATA_SOURCE, CMPL_DATA_PROVIDER, CLOSE_DATA_FIELD);
    verify(_mockMaster, times(1))
        .getTimeSeries(
            UID.getObjectId(),
            VersionCorrection.LATEST,
            HistoricalTimeSeriesGetFilter.ofRange(null, null));

    assertEquals(UID, test.getUniqueId());
  }
  public void getHistoricalWithInclusiveExclusiveDates() throws Exception {
    LocalDate end = DateUtils.previousWeekDay();
    LocalDate start = end.minusDays(7);

    HistoricalTimeSeriesInfoSearchRequest request =
        new HistoricalTimeSeriesInfoSearchRequest(IDENTIFIERS);
    request.setValidityDate(LocalDate.now());
    request.setDataSource(BBG_DATA_SOURCE);
    request.setDataProvider(CMPL_DATA_PROVIDER);
    request.setDataField(CLOSE_DATA_FIELD);
    LocalDateDoubleTimeSeries timeSeries = randomTimeSeries();

    HistoricalTimeSeriesInfoSearchResult searchResult = new HistoricalTimeSeriesInfoSearchResult();
    HistoricalTimeSeriesInfoDocument doc = new HistoricalTimeSeriesInfoDocument();
    doc.setUniqueId(UID);
    doc.getInfo().setTimeSeriesObjectId(UID.getObjectId());
    searchResult.getDocuments().add(doc);

    when(_mockResolver.resolve(
            IDENTIFIERS,
            LocalDate.now(),
            BBG_DATA_SOURCE,
            CMPL_DATA_PROVIDER,
            CLOSE_DATA_FIELD,
            null))
        .thenReturn(new HistoricalTimeSeriesResolutionResult(doc.getInfo()));

    for (boolean includeStart : new boolean[] {true, false}) {
      for (boolean includeEnd : new boolean[] {true, false}) {
        // Also test max points limit for various values
        for (Integer maxPoints : new Integer[] {null, -10, -1, 1, 0, -2, 2, 10}) {
          LocalDate startInput = start;
          LocalDate endInput = end;
          if (!includeStart) {
            startInput = start.plusDays(1);
          }
          if (!includeEnd) {
            endInput = end.minusDays(1);
          }

          ManageableHistoricalTimeSeries hts = new ManageableHistoricalTimeSeries();
          LocalDateDoubleTimeSeries lddts =
              (maxPoints == null)
                      || (Math.abs(maxPoints)
                          >= timeSeries.subSeries(start, includeStart, end, includeEnd).size())
                  ? timeSeries.subSeries(start, includeStart, end, includeEnd)
                  : (maxPoints >= 0)
                      ? timeSeries.subSeries(start, includeStart, end, includeEnd).head(maxPoints)
                      : timeSeries.subSeries(start, includeStart, end, includeEnd).tail(-maxPoints);
          hts.setUniqueId(UID);
          hts.setTimeSeries(lddts);
          when(_mockMaster.getTimeSeries(
                  UID.getObjectId(),
                  VersionCorrection.LATEST,
                  HistoricalTimeSeriesGetFilter.ofRange(startInput, endInput, maxPoints)))
              .thenReturn(hts);
          when(_mockMaster.search(request)).thenReturn(searchResult);

          HistoricalTimeSeries test =
              (maxPoints == null)
                  ? _tsSource.getHistoricalTimeSeries(
                      IDENTIFIERS,
                      BBG_DATA_SOURCE,
                      CMPL_DATA_PROVIDER,
                      CLOSE_DATA_FIELD,
                      start,
                      includeStart,
                      end,
                      includeEnd)
                  : _tsSource.getHistoricalTimeSeries(
                      IDENTIFIERS,
                      BBG_DATA_SOURCE,
                      CMPL_DATA_PROVIDER,
                      CLOSE_DATA_FIELD,
                      start,
                      includeStart,
                      end,
                      includeEnd,
                      maxPoints);

          assertEquals(UID, test.getUniqueId());
          assertEquals(hts.getTimeSeries(), test.getTimeSeries());
        }
      }
    }
  }
  /**
   * Adds or updates a time-series in the master. Can be a sub-set of the data points present and
   * will not 'erase' points that are missing, only supplement them.
   *
   * @param description a description of the time-series for display purposes, not null
   * @param dataSource the data source, not null
   * @param dataProvider the data provider, not null
   * @param dataField the data field, not null
   * @param observationTime the descriptive observation time key, e.g. LONDON_CLOSE, not null
   * @param externalIdBundle the external identifiers with which the time-series is associated, not
   *     null
   * @param externalIdSearchType the external identifier search type for matching an existing
   *     time-series, null to use the default
   * @param timeSeries the time-series, not null
   * @return the unique identifier of the time-series
   */
  public UniqueId writeTimeSeries(
      String description,
      String dataSource,
      String dataProvider,
      String dataField,
      String observationTime,
      ExternalIdBundle externalIdBundle,
      ExternalIdSearchType externalIdSearchType,
      LocalDateDoubleTimeSeries timeSeries) {
    ArgumentChecker.notNull(description, "description");
    ArgumentChecker.notNull(dataSource, "dataSource");
    ArgumentChecker.notNull(dataProvider, "dataProvider");
    ArgumentChecker.notNull(dataField, "dataField");
    ArgumentChecker.notNull(observationTime, "observationTime");
    ArgumentChecker.notNull(externalIdBundle, "externalIdBundle");
    ArgumentChecker.notNull(timeSeries, "timeSeries");

    HistoricalTimeSeriesInfoSearchRequest htsSearchReq =
        new HistoricalTimeSeriesInfoSearchRequest();
    ExternalIdSearch idSearch = ExternalIdSearch.of(externalIdBundle);
    if (externalIdSearchType != null) {
      idSearch = idSearch.withSearchType(externalIdSearchType);
    }
    htsSearchReq.setExternalIdSearch(idSearch);
    htsSearchReq.setDataSource(dataSource);
    htsSearchReq.setDataProvider(dataProvider);
    htsSearchReq.setDataField(dataField);
    htsSearchReq.setObservationTime(observationTime);
    HistoricalTimeSeriesInfoSearchResult searchResult = _htsMaster.search(htsSearchReq);
    if (searchResult.getDocuments().size() > 0) {
      if (searchResult.getDocuments().size() > 1) {
        s_logger.warn(
            "Found multiple time-series matching search. Will only update the first. Search {} returned {}",
            htsSearchReq,
            searchResult.getInfoList());
      }
      // update existing time series
      HistoricalTimeSeriesInfoDocument existingTsDoc = searchResult.getFirstDocument();
      return writeTimeSeries(
          description,
          dataSource,
          dataProvider,
          dataField,
          observationTime,
          existingTsDoc.getObjectId(),
          timeSeries);
    } else {
      // add new time series
      ManageableHistoricalTimeSeriesInfo info = new ManageableHistoricalTimeSeriesInfo();
      info.setDataField(dataField);
      info.setDataSource(dataSource);
      info.setDataProvider(dataProvider);
      info.setObservationTime(observationTime);
      info.setExternalIdBundle(ExternalIdBundleWithDates.of(externalIdBundle));
      info.setName(description);
      HistoricalTimeSeriesInfoDocument htsInfoDoc = new HistoricalTimeSeriesInfoDocument();
      htsInfoDoc.setInfo(info);

      HistoricalTimeSeriesInfoDocument addedInfoDoc = _htsMaster.add(htsInfoDoc);
      s_logger.debug(
          "Adding time series "
              + externalIdBundle
              + " from "
              + timeSeries.getEarliestTime()
              + " to "
              + timeSeries.getLatestTime());
      return _htsMaster.updateTimeSeriesDataPoints(
          addedInfoDoc.getInfo().getTimeSeriesObjectId(), timeSeries);
    }
  }