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

import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;

import org.threeten.bp.LocalDate;

import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdWithDates;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolutionResult;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.tuple.Pair;

/**
 * Represents a cache item for storing {@link HistoricalTimeSeriesResolutionResult} instances for the same
 * {@link ExternalId} with differing validity periods.
 */
public class HistoricalTimeSeriesResolutionCacheItem {

  private final ExternalId _externalId;
  private final AtomicBoolean _allInvalid = new AtomicBoolean();
  private final Set<LocalDate> _invalidDates = Collections.newSetFromMap(new ConcurrentHashMap<LocalDate, Boolean>());
  private final Collection<Pair<ExternalIdWithDates, HistoricalTimeSeriesResolutionResult>> _results = new ConcurrentLinkedQueue<>();
  
  public HistoricalTimeSeriesResolutionCacheItem(ExternalId externalId) {
    _externalId = externalId;
  }

  //-------------------------------------------------------------------------
  public boolean isInvalid(LocalDate validityDate) {
    if (_allInvalid.get()) {
      return true;
    }
    if (validityDate == null) {
      return false;
    }
    return _invalidDates.contains(validityDate);
  }
  
  public void putInvalid(LocalDate validityDate) {
    if (validityDate == null) {
      if (_results.size() != 0) {
        throw new OpenGammaRuntimeException("Already have " + _results.size() + " valid results for " + _externalId + " but attempted to mark every date as invalid");
      }
      _allInvalid.set(true);
      _invalidDates.clear();
    } else {
      _invalidDates.add(validityDate);
    }
  }
  
  //-------------------------------------------------------------------------
  public HistoricalTimeSeriesResolutionResult get(LocalDate validityDate) {
    for (Pair<ExternalIdWithDates, HistoricalTimeSeriesResolutionResult> result : _results) {
      if (result.getFirst().isValidOn(validityDate)) {
        return result.getSecond();
      }
    }
    return null;
  }
  
  public void put(ExternalIdWithDates externalIdWithDates, HistoricalTimeSeriesResolutionResult result) {
    ArgumentChecker.notNull(externalIdWithDates, "externalIdWithDates");
    ArgumentChecker.notNull(result, "result");
    if (!_externalId.equals(externalIdWithDates.getExternalId())) {
      throw new IllegalArgumentException(externalIdWithDates + " is not compatible with " + _externalId);
    }
    if (!result.getHistoricalTimeSeriesInfo().getExternalIdBundle().contains(externalIdWithDates)) {
      throw new IllegalArgumentException("Result " + result + " does not contain " + externalIdWithDates);
    }
    _results.add(Pair.of(externalIdWithDates, result));
  }
  
}

@@ -212,24 +212,25 @@
 l.Collection
+s
 ;%0Aimport jav
@@ -232,35 +232,27 @@
 t java.util.
-Collections
+Map
 ;%0Aimport jav
@@ -348,27 +348,19 @@
 ncurrent
-LinkedQueue
+Map
 ;%0Aimport
@@ -701,46 +701,8 @@
 ker;
-%0Aimport com.opengamma.util.tuple.Pair;
 %0A%0A/*
@@ -1171,21 +1171,19 @@
 l Co
-llection%3CPair
+ncurrentMap
 %3CExt
@@ -1237,17 +1237,16 @@
 nResult%3E
-%3E
  _result
@@ -1267,19 +1267,15 @@
 rent
-LinkedQueue
+HashMap
 %3C%3E()
@@ -2265,20 +2265,25 @@
    for (
-Pair
+Map.Entry
 %3CExterna
@@ -2351,16 +2351,27 @@
 _results
+.entrySet()
 ) %7B%0A    
@@ -2390,13 +2390,11 @@
 .get
-First
+Key
 ().i
@@ -2448,14 +2448,13 @@
 .get
-Second
+Value
 ();%0A
@@ -3128,19 +3128,19 @@
 lts.
-add(Pair.of
+putIfAbsent
 (ext
@@ -3164,17 +3164,16 @@
  result)
-)
 ;%0A  %7D%0A  

Use a map as duplicate entries are possible otherwise