package de.uni.karlsruhe.aifb.prog2.solutions;

/** Diese Klasse kann verwendet werden, um fehlgeschlagene
  * Versuche zu speichern.
  **/
public class CollectionOfFailures {

  /** Speichert alle Fehlschlaege nach ihrer Zugnummer ab. */
  private Scenario[][] failures = new Scenario[0][0];

  /** Besitzt die Sammlung fuer eine gewisse Zugnummer
    * bereits dieses Scenario als registrierten Fehlschlag?
    * @return -1, wenn das Scenario noch nicht bekannt ist,
    * den Index innerhalb des internen Feldes ansonsten
    **/
  private int contains(Scenario scenario, int index)
  {
    if (index >= failures.length || index < 0)
    {
      return -1;
    }
    for (int i = 0; i < failures[index].length; i++)
    {
      if (failures[index][i].equals(scenario))
      {
        return i;
      }
    }
    return -1;
  }

  /** Ist ein gewisses Scenario in der Sammlung ab einem
    * gewissen Index schon enthalten?
    * @param scenario das Szenario, das gesucht werden soll
    * @param maxIndex der Index, bis zu dem hoechstens
    * gesucht werden soll
    * @return den Zug, unter dem das Scenario abgespeichert
    *   wurde. -1, wenn es nicht gefunden wurde.
    */
  public int containsUntil(Scenario scenario,int maxIndex)
  {
    maxIndex = Math.min(maxIndex + 1,failures.length);
    for (int i = 0; i <= maxIndex; i++)
    {
      if (contains(scenario,i) > -1)
        return i;
    }
    return -1;
  }

  /** Loesche ein Scenario aus einem bestimmten Index */
  private void remove(Scenario scenario, int index)
  {
    int i = contains(scenario,index);
    if (i > -1)
    {
      Scenario[] old = failures[i];
      failures[i] = new Scenario[old.length - 1];
      if (i > 0)
        System.arraycopy(old,0,failures[i],0,i);
      if (i < old.length - 1)
        System.arraycopy(old,i+1,failures[i],i,
          old.length-i-1);
    }
  }


  /** Markiert ein Szenario als Fehlschlag.
    * @param scenario das Szenario, das nicht zur Loesung
    *  fuehrte
    * @param move die Nummer des Zuges, in der das Szenario
    *  aufgetreten ist. Es wird mit 0 zu zaehlen begonnen.
    **/
  public void addFailure(Scenario scenario, int move) {
    // Befindet sich das Scenario bereits in der Sammlung?
    int index = contains(scenario,failures.length);
    if (index > -1)
    {
      // Fall: das Scenario war schon bei einem frueheren
      // Zug ein Fehlschlag, ist also bekannt.
      if (index <= move)
        return;
      // Fall: der Zug war bislang erst spaeter als Fehlschlag
      // bekannt, muss also verschoben werden.
      remove(scenario,index);
    }
    // Prueft, ob das Array bis zu der gewuenschten
    // move-Nummer reicht. Andernfalls wird das Array erweitert
    if (move >= failures.length)
    {
      // Kopiere das alte Feld in ein neues.
      Scenario[][] old = failures;
      failures = new Scenario[move + 1][];
      System.arraycopy(old,0,failures,0,old.length);
      // Fuelle den Rest mit leeren Feldern.
      for (int i = old.length; i <= move; i++)
      {
        failures[i] = new Scenario[0];
      }
    }
    // Erweitere das Array an der gewuenschten Stelle.
    Scenario[] old = failures[move];
    failures[move] = new Scenario[old.length + 1];
    // Kopiere die alten Werte hinein und fuege den neuen an.
    System.arraycopy(old,0,failures[move],1,old.length);
    failures[move][0] = scenario;
  }

}