/*
 * 
 * Datei:   FehlerAusgabe.java
 * 
 * ---------------------------------
 * 
 * Datum:           $Date: 2004/05/13 10:14:19 $
 * Autor:           Simon Tiffert 
 * Prüfungsnummer:  40
 * Firma:           T-Systems
 * eMail-Adresse:   simon.tiffert@t-systems.com
 * Version:         $Revision: 1.7 $
 * 
 * ---------------------------------
 * 
 */

package main.ausgabe;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

import main.Main;
import main.NoInputException;
import main.WrongParameterException;
import main.eingabe.TooFewCharactersException;
import main.eingabe.TooFewSperrfelderException;
import main.eingabe.UnexpectedCharacterException;
import main.eingabe.UnexpectedLineException;
import main.eingabe.UnknownCharacterException;
import main.tools.file.OutputFileExistsException;
import main.verarbeitung.IsSperrfeldException;
import main.verarbeitung.IsStartpunktException;
import main.verarbeitung.OutOfMatrixException;
import main.verarbeitung.WrongDimensionException;

/**
 * Klasse, die zur Verarbeitung und Ausgabe von Fehlern dient.
 * Dabei bekommt die Klasse ein Objekt des Typs Exception übergeben, 
 * welches dann genauer untersucht wird und eine hier definierte
 * Ausgabe auf Datei bzw. im Debugmodus auch auf dem Bildschirm 
 * ausgegeben wird.
 * Folgende Exceptions werden untersucht:
 * <dl>
 *  <dt>UnexpectedCharacterException</dt>
 *  <dd>Zeilenlänge überschritten</dd>
 *  <dt>UnexpectedLineException</dt>
 *  <dd>Es treten noch Zeichen am Zeilenende auf</dd>
 *  <dt>UnknownCharacterException</dt>
 *  <dd>Es ist ein unbekanntes Zeichen in der Eingabe aufgetreten</dd>
 *  <dt>TooFewCharactersException</dt>
 *  <dd>Es sind zuwenig Zeichen in der Zeile angegeben</dd>
 *  <dt>TooFewSperrfelderException</dt>
 *  <dd>Es sind zuwenig Sperrfelder angegeben</dd>
 *  <dt>WrongDimensionException</dt>
 *  <dd>Falsche Dimensionsangaben für Matrix</dd>
 *  <dt>OutOfMatrixException</dt>
 *  <dd>Punkt außerhalb der Matrix</dd>
 *  <dt>IsStartpunktException</dt>
 *  <dd>Sperrfeld soll auf Startpunkt gesetzt werden</dd>
 *  <dt>IsSperrfeldException</dt>
 *  <dd>Doppelte Definition eines Sperrfelds</dd>
 *  <dt>NoWayFoundException</dt>
 *  <dd>Die Rekursion war nicht erfolgreich</dd>
 *  <dt>FileNotFoundException</dt>
 *  <dd>Eingabedatei wurde nicht gefunden</dd>
 *  <dt>OutputFileExistsException</dt>
 *  <dd>Ausgabedatei existiert bereits (ohne -overwrite)</dd>
 *  <dt>WrongParameterException</dt>
 *  <dd>Falsche Eingabe der Programmparameter</dd>
 *  <dt>IOException</dt>
 *  <dd>Fehler bei der Ausgabe</dd>
 *  <dt>Exception</dt>
 *  <dd>Der Defaultfall, der unerwartete Fehler auffängt</dd>
 * </dl>
 * 
 * @version $Revision: 1.7 $
 * @author Simon Tiffert
 */
public class FehlerAusgabe
{
  /** Name der Eingabedatei, um diese im Fehlerfall mit auszugeben */
  String eingabeDateiName;

  /** BufferedWriter der Ausgabedatei */
  BufferedWriter bw;

  /** Exception, die genauer untersucht wird */
  Exception exception;

  /**
   * Der Konstruktor sorgt dafür, dass der Fehler verarbeitet wird
   * und das Attribut eingabeDateiName gesetzt wird.
   * 
   * @param bw BufferedWriter der Ausgabedatei
   * @param exception Exception, die genauer untersucht wird
   * @param dateiName Name der Eingabedatei
   */
  public FehlerAusgabe(
    BufferedWriter bw,
    Exception exception,
    String dateiName)
  {
    // BufferedWriter der Ausgabedatei
    this.bw = bw;

    // Exception, die zu untersuchen ist
    this.exception = exception;

    // Name der Eingabedatei, die im Fehlerfall ausgegeben wird
    eingabeDateiName = dateiName;

    // Aufruf der Ausgabefunktion
    printError();
  }

  /**
   * Diese Funktion dient der Auswertung von Fehlern, die im 
   * Programmablauf passieren können. Dabei wird eine Unterteilung in 
   * Fehlerklassen vorgenommen.
   * 
   */
  private void printError()
  {
    // Programmfehler
    if (exception instanceof UnexpectedCharacterException)
    {
      // Zeilenlänge überschritten
      schreibeFehler(
        "Zuviel Eingaben in Zeile " + exception.getMessage());
    }
    else if (exception instanceof UnexpectedLineException)
    {
      // Es treten noch Zeichen am Dateiende auf
      schreibeFehler(
        "Es folgen noch Zeichen nach der Eingabe in Zeile "
          + exception.getMessage());
    }
    else if (exception instanceof UnknownCharacterException)
    {
      // Es ist ein unbekanntes Zeichen in der Eingabe aufgetreten
      schreibeFehler(
        "Unbekanntes Zeichen in der Eingabe in Zeile "
          + exception.getMessage());
    }
    else if (exception instanceof TooFewCharactersException)
    {
      // Zuwenig Zeichen für die Matrix
      schreibeFehler(
        "Zu wenig Zeichen für Eingabe in Zeile "
          + exception.getMessage());
    }
    else if (exception instanceof TooFewSperrfelderException)
    {
      // Zuwenig Zeichen für die Matrix
      schreibeFehler("Es sind zu wenige Sperrfelder angegeben");
    }
    else if (exception instanceof WrongDimensionException)
    {
      // Falsche Dimensionsangabe für Matrix
      schreibeFehler("Falsche Dimensionsangaben für Matrix");
    }
    else if (exception instanceof OutOfMatrixException)
    {
      // Punkt außerhalb der Matrix definiert
      schreibeFehler(
        exception.getMessage() + " außerhalb der Matrix definiert");
    }
    else if (exception instanceof IsStartpunktException)
    {
      // Sperrfeld auf Startpunkt definiert
      schreibeFehler(
        "Sperrfeld auf Startpunkt"
          + exception.getMessage()
          + " definiert");
    }
    else if (exception instanceof IsSperrfeldException)
    {
      // Sperrfeld doppelt definiert
      schreibeFehler(
        "Sperrfeld " + exception.getMessage() + " doppelt definiert");
    }
    // Fehler, die nicht in Datei geschrieben werden können
    else if (exception instanceof FileNotFoundException)
    {
      // Die Eingabedatei wurde nicht gefunden
      System.out.println("Die Eingabedatei wurde nicht gefunden");
    }
    else if (exception instanceof OutputFileExistsException)
    {
      // Ausgabedatei existiert schon, somit muss die Fehlermeldung auf 
      // dem Bildschirm erscheinen
      System.out.println(
        "Die Datei " + exception.getMessage() + " existiert schon");
    }
    else if (exception instanceof NoInputException)
    {
      System.out.println(
        "Es wurde kein Parameter für das Programm übergeben.");
      hilfeAusgabe();
    }
    else if (exception instanceof WrongParameterException)
    {
      System.out.println(exception.getMessage());
      hilfeAusgabe();
    }
    // Fehler die nicht in den vorherigen Routinen behandelt wurden
    else if (exception instanceof IOException)
    {
      // Fehler konnte nicht in die Datei geschrieben werden
      schreibeFehler(
        "Es ist ein Fehler bei der Ausgabe aufgetreten:"
          + exception.getMessage());
    }
    else
    {
      // Allgemeiner Fehler
      schreibeFehler(
        "Es ist ein Fehler aufgetreten: " + exception.getMessage());
    }
  }

  /**
   * Diese Funktion schreibt den gefundenen Fehler in die Ausgabedatei 
   * und fängt einen eventuellen Fehler ab. Zudem ist hier noch eine 
   * Debugausgabe implementiert, die den Fehler zusätzlich noch auf dem
   * Bildschirm ausgibt
   * 
   * @param s Der Text der in die Ausgabedatei geschrieben wird
   */
  private void schreibeFehler(String s)
  {
    // Hier wird die Ausgabe zusammengebaut
    StringBuffer eingabe = new StringBuffer("");

    // Zeilenumbruch nach Betriebssystem anpassen
    String lineEnd = System.getProperty("line.separator");

    //  Falls dies scheitert, setze Standard Zeilenumbruch
    if (lineEnd == null)
    {
      lineEnd = "\n";
    }

    // Tabulator
    String tabulator = "    ";

    // gib die Eingabedati nochmal aus, wenn es möglich ist
    try
    {
      // Öffne die Eingabedatei
      LineNumberReader line =
        new LineNumberReader(
          new FileReader(
            new File(eingabeDateiName)));

      // Header vor Eingabedatei
      eingabe.append(lineEnd + tabulator + "Eingabedaten: " + lineEnd);
      eingabe.append(tabulator + "*************" + lineEnd);

      // Lies die Datei aus und schreibe sie in den StringBuffer
      String zeile;
      while ((zeile = line.readLine()) != null)
      {
        // Sorge dafür, dass Zeilennummern richtig formatiert sind
        String whitespace = "  ";
        if (line.getLineNumber() >= 10)
        {
          whitespace = " ";
        }

        // Erstelle eine formatierte Zeile
        eingabe.append(
          whitespace
            + line.getLineNumber()
            + ":"
            + tabulator
            + zeile
            + lineEnd);
      }
    }
    // Fange die Exception
    catch (Exception e)
    {
      // Die Eingabedatei konnte nicht gelesen werden, was für manche
      // Fehler charakterisierend ist. Somit kann dieser Fall einfach
      // gefangen werden
    }

    // Gib den Fehler aus
    try
    {
      // Ist der Debugmodus gesetzt, dann gib die Meldung
      // zusätzlich auf dem Bildschirm aus
      if (Main.debug)
      {
        System.out.println(eingabe + lineEnd + lineEnd);
        System.out.println(tabulator + s);
      }
      // Schreibe in die Ausgabedatei
      bw.write(eingabe + lineEnd + lineEnd);
      bw.write(tabulator + s);
    }
    // Das Schreiben auf Datei war nicht erfolgreich
    catch (Exception e)
    {
      // Gib die Fehlermeldung aus
      System.err.println(
        "Die Ausgabedatei konnte nicht beschrieben werden.");
    }
  }

  /**
   * Diese Funktion erzeugt die Hilfeausgabe, die angezeigt wird, wenn
   * das Programm falsch aufgerufen wurde oder wenn der Parameter -h 
   * eingegeben wurde.
   *
   */
  private static void hilfeAusgabe()
  {
    // Einfache formatierte Ausgabe
    System.out.println(
      "Aufruf:\n"
        + "java -jar programm.jar -d Datei [-h][-debug][-overwrite]"
        + "\n\n"
        + "-h         zeigt diese Hilfe an\n"
        + "-debug     die Fehlerausgabe wird zusätzlich auf dem"
        + "  Bildschirm ausgeben\n"
        + "-overwrite eine vorhandene Ausgabedatei mit gleichem Namen "
        + " wird überschrieben\n");
  }
}
