/*
 * 
 * Datei:   Main.java
 * 
 * ---------------------------------
 * 
 * Datum:           $Date: 2004/05/13 09:16:13 $
 * Autor:           Simon Tiffert 
 * Prüfungsnummer:  40
 * Firma:           T-Systems
 * eMail-Adresse:   simon.tiffert@t-systems.com
 * Version:         $Revision: 1.16 $
 * 
 * ---------------------------------
 * 
 */
package main;

import java.io.BufferedWriter;
import java.io.IOException;
import main.ausgabe.Ausgabe;
import main.ausgabe.FehlerAusgabe;
import main.eingabe.Eingabe;
import main.tools.file.OutputFile;
import main.verarbeitung.Matrix;
import main.verarbeitung.Verarbeitung;

/**
 * Diese Klasse steuert den Ablauf des Programms.
 * Hier kann man in der main-Funktion den Ablauf des EVA Prinzips 
 * erkennen. Da hier auch zentral Fehler abgefangen werden, war es
 * nötig, die Ausgabedatei schon sehr früh im Programmablauf zu öffnen,
 * da Exceptions sonst nicht in Datei geschrieben werden könnten.
 * In dieser Klasse befindet sich auch das zentrale Matrix-Element, 
 * welches per Referenz an die Unterteile Eingabe, Verarbeitung und
 * Ausgabe übergeben wird.<br><br>
 * Zudem befindet sich hier der Parser für die Eingabeparameter.
 * Dieser sorgt dafür, dass wichtige Flags in dieser Klasse gesetzt 
 * sind.
 * Abgefangen werden:
 * <ul>
 *  <li>
 *    -d DATEINAME (erkennt den Parameter und setzt den Dateinamen)
 *  </li>
 *  
 *  <li>
 *    -debug (setzt das Programm in den Debugmodus, bei dem die 
 *            Ausgaben auch auf dem Bildschirm ausgegeben werden).
 *  </li>
 * 
 *  <li>
 *    -overwrite (überschreibt eine vorhandene Ausgabedatei. Dies 
 *                erleichtert das Testen, kann aber im normalen
 *                Ablauf unerwünscht sein)
 *  </li>
 * 
 *  <li>
 *    -h (zeigt die Hilfe an, wie das Programm aufgerufen wird. Die
 *        Hilfe wird auch automatisch angezeigt, wenn Parameter falsch
 *        angegeben wurden)
 *  </li>
 * </ul>
 * 
 *  
 * @version $Revision: 1.16 $
 * @author Simon Tiffert
 */
public class Main
{
  /** maximale Größe der Matrix */
  public static final int maxDimension = 6;

  /** setzt den Debug-Modus */
  public static boolean debug = false;

  /** setzt den Overwrite-Modus */
  public static boolean overwrite = false;

  /** Die zentrale Datenstruktur mit der Matrix */
  public static Matrix matrix = new Matrix();

  /**
   * main-Funktion des Programms.
   * Hier wird die Verarbeitung des Programms gesteuert und
   * die Fehlerabfrage durchgeführt, die zur weiteren Verarbeitung
   * weitergereicht wird.
   * 
   * @param args Programmparameter -d DATEINAME [-h]
   *        [-debug][-overwrite]
   */
  public static void main(String[] args)
  {
    // Dateiname der Eingabedatei
    String dateiName = null;

    // Erstelle einen Writer, für die Ausgabedatei
    BufferedWriter bw = null;

    try
    {
      // Überprüft, ob ein Dateiname mit angegeben wurde.
      dateiName = parameterParser(args);

      // öffne Ausgabedatei und setze den Writer darauf
      bw = new OutputFile(dateiName, ".out").getAusgabeDatei();

      // EVA-Prinzip:

      // Erstelle eine Instanz der Eingabe
      new Eingabe(matrix, dateiName);

      // rufe die Verarbeitung mit den RoesselSprüngen auf
      new Verarbeitung(matrix);

      // erzeuge die Ausgabe
      new Ausgabe(matrix, bw);

    }
    catch (Exception e)
    {
      // die Fehler werden dann in der Datei ausgewertet
      new FehlerAusgabe(bw, e, dateiName);
    }
    finally
    {
      // schliesse die Ausgabedatei und fange einen Fehler dabei auf
      try
      {
        if (bw != null)
        {
          bw.close();
        }
      }
      catch (IOException e)
      {
        System.err.println(
          "Ausgabedatei konnte nicht geschrieben werden.");
      }
    }

  }

  /**
   * Diese Funktion parst die Eingabeparameter. Dabei wird überprüft, 
   * ob eine Eingabedatei angegeben wurde. Zudem werden weitere 
   * Parameter erkannt und fehlerhafte sowie doppelte Parameter werden 
   * erkannt und als Exception geworfen.
   * <br />
   * Erkannt werden:
   * <ul>
   *  <li>-d DATEINAME    (Pflichtparameter)</li>
   *  <li>-h              (Hilfe)</li>
   *  <li>-debug          (Debugmodus)</li>
   *  <li>-overwrite      (Overwrite-Modus, der die Ausgabedatei
   *                        überschreibt)</li>
   * </ul>
   * 
   * 
   * @param parameter Übergabeparameter der main-Funktion
   * @return Übergebenen Dateinamen
   * @throws WrongParameterException Fehlerhafte Parameter
   * @throws NoInputException Fehlende Parameter
   */
  private static String parameterParser(String[] parameter)
    throws WrongParameterException, NoInputException
  {
    // Dateiname der Eingabedatei
    String dateiName = null;

    // Flagge für Anzeige der Hilfe
    boolean hilfe = false;

    // überprüft, ob überhaupt Parameter angegeben wurden
    if (parameter.length == 0)
    {
      // werfe eigene Exception
      throw new NoInputException();
    }

    // laufe über alle Parameter
    for (int i = 0; i < parameter.length; i++)
    {
      // -d für Dateiname
      if (parameter[i].equalsIgnoreCase("-d"))
      {
        // wenn der Dateiname noch nicht gesetzt ist
        if (dateiName == null)
        {
          // setze den nächsten Parameter als Dateinamen, wenn noch
          // Parameter vorhanden sind. Ansonsten werfe Fehler, dass
          // der Dateiname fehlt 
          if (i < parameter.length - 1)
          {
            dateiName = parameter[++i];
          }
          else
          {
            throw new WrongParameterException(
              "Falscher Parameter - Dateiname fehlt");
          }

          // Falls danach wieder ein Parameter folgt, fehlt der 
          // Dateiname
          if (dateiName.startsWith("-"))
          {
            throw new WrongParameterException(
              "Falscher Parameter - Dateiname fehlt");
          }
        }
        // wenn der Dateiname schon gesetzt ist, wäre er doppelt 
        // definiert. Um Fehlern vorzubeugen wird hier eine Exception
        // geworfen
        else
        {
          throw new WrongParameterException(
            "Doppelter Parameter - Dateiname schon angegeben");
        }
      }

      // -debug Debug-Modus
      else if (parameter[i].equalsIgnoreCase("-debug"))
      {
        // wenn der Debugmodus noch nicht gesetzt ist, setze ihn jetzt
        if (debug == false)
        {
          debug = true;
        }
        // doppelter Parameter, der zu einer Exception führt
        else
        {
          throw new WrongParameterException(
            "Doppelter Parameter -debug");
        }
      }

      // -overwrite Overwrite-Modus
      else if (parameter[i].equalsIgnoreCase("-overwrite"))
      {
        // Wenn der Overwritemodus noch nicht gesetzt ist, setze ihn 
        // jetzt
        if (overwrite == false)
        {
          overwrite = true;
        }
        // doppelter Parameter, der zu einer Exception führt
        else
        {
          throw new WrongParameterException(
            "Doppelter Parameter -overwrite");
        }
      }

      // -h Hilfe
      else if (parameter[i].equalsIgnoreCase("-h"))
      {
        // überprüfe, ob die Hilfe schon angezeigt werden soll.
        // Ansonsten setze Flag zur Anzeige
        if (hilfe == false)
        {
          hilfe = true;
        }
        // doppelter Parameter, der zu einer Exception führt
        else
        {
          throw new WrongParameterException("Doppelter Parameter -h");
        }
      }

      // unbekannter Parameter, der zu einer Exception führt
      else
      {
        throw new WrongParameterException(
          "Fehlerhafter Parameter - " + parameter[i]);
      }

    }

    // wenn die Hilfe angezeigt werden soll, so unterbreche den 
    // Programmfluss mit einer Exception, die allerdings keinen Fehler
    // erzeugt, sondern die Hilfe anzeigt
    if (hilfe == true)
    {
      throw new WrongParameterException("");
    }
    // ist der Dateiname noch nicht gesetzt worden, so ist keine 
    // weitere Verarbeitung möglich und das Programm wird mit einer 
    // Exception abgebrochen
    else if (dateiName == null)
    {
      throw new WrongParameterException(
        "Falscher Aufruf - keine Eingabedatei angegeben");
    }

    // wenn alles richtig verarbeitet wurde, gib den Dateinamen zurück
    return dateiName;
  }

}
