package javacodebook.xml.processing.jdom.parse;

import java.io.*;
import org.jdom.*;
import org.jdom.input.SAXBuilder;

import javacodebook.xml.processing.dom.parse.ErrorCollector;

public class ValidatingJDOMParseUtil {

  private static final String USAGE =
      "\nBenutzerhinweis: javacodebook.xml.processing.jdom.parse.ValidatingJDOMParseUtil " +
      "<uri>\n\nwobei\n\n<uri>\n" +
      "die URI ist, unter der ein XML-Dokument zu finden ist das geparst und validiert werden soll.\n";

  public static void main(String[] args) {

    if (args.length != 1) {
      System.out.println(getUsage());
      return;
    }
    String documentLocation = args[0];

    // Da JDOM JAXP benutzt, was widerum als Default-Parser den Crimson Parser benutzt,
    // wir aber Xerces verwenden wollen, muss folgende System-Property gesetzt werden, damit
    // JAXP und somit JDOM den Xerces Parser verwendet.
    // Im Gegensatz zu Crimson validiert Xerces sowohl gegen DTDs als auch gegen Schemata
    System.setProperty("javax.xml.parsers.SAXParserFactory","org.apache.xerces.jaxp.SAXParserFactoryImpl");


    ValidatingJDOMParseUtil validatingJDOMParseUtil = new
        ValidatingJDOMParseUtil();

    // Es wird ein ErrorCollector aus dem processing.dom.parse-Beispiel
    // instanziiert.
    ErrorCollector errorCollector = new ErrorCollector();

    // parsen des Dokuments
    Document document = validatingJDOMParseUtil.parseDocument(documentLocation,
        errorCollector);

    // Eventuell aufgetretene Fehler werden verarbeitet
    boolean isValid = validatingJDOMParseUtil.processErrors(errorCollector);

    // Falls das Dokument valide ist, wird es verarbeitet
    if (isValid) {
      validatingJDOMParseUtil.processDocument(document);
    }
    else {
      System.out.println(
          "Dokument wurde nicht verarbeitet, da es nicht valide ist");
    }

  }

  /**
   * Diese Methode parst eine URI in ein JDOM-Document und
   * validiert es dabei.
   *
   * @param documentLocation
   * @return org.jdom.Document
   */
  public Document parseDocument(String documentLocation,
                                ErrorCollector errorCollector) {

    // Ein SAXBuilder-Objekt wird erzeugt.
    // Dadurch dass true an den Konstruktor übergeben wird
    // ist die Validierung eingeschaltet.
    SAXBuilder builder = new SAXBuilder(true);


    // Beim SAXBuilder wird der ErrorCollector registriert.
    builder.setErrorHandler(errorCollector);

    try {
      // Der SAXBuilder erstellt von der URI ein Document-Object
      Document document = builder.build(documentLocation);

      if (document != null) {
        // Falls keine Exceptions aufgetreten sind ist das Dokument valide.
        System.out.println(documentLocation + " ist valide");
      }
      return document;
    }
    // Hier werden well-formedness or Validitätsfehler gefangen.
    catch (JDOMException e) {
      System.out.println(documentLocation + " ist nicht valide.");
      System.out.println(e.getMessage());
    }
    catch (Exception e) {
      System.out.println("Fehler bei der Verarbeitung des Dokuments: " + e);
    }
    return null;
  }

  /**
   * Die Methode liefert die Pseudoverarbeitung eines Dokuments.
   * Es wird der Dokumententyp in den Ausgabestrom geschrieben.
   *
   * @param document
   */
  public void processDocument(Document document) {
    // Das Dokument kann nun verarbeitet werden
    if(document==null)return;
    if(document.getDocType()!=null)
    {
      System.out.println("Der Dokumententyp (SystemID) ist: " +
                         document.getDocType().getSystemID());
    }
  }

  /**
   * Die Methode verarbeitet Fehlermeldungen, die vom ErrorCollector-Objekt
   * gesammelt wurden. Sie liefert einen boolschen Wert zurück, der besagt,
   * ob das Dokument valide war oder nicht.
   *
   * @param errorCollector
   * @return boolean
   */
  public boolean processErrors(ErrorCollector errorCollector) {

    // Falls Probleme aufgetreten sind, werden die entsprechenden
    // Meldungen in die Standardausgabe geschrieben.
    if (errorCollector.anyProblems()) {
      System.out.println(errorCollector.getWarningsMessagesAsText());
      System.out.println(errorCollector.getErrorMessagesAsText());
      System.out.println(errorCollector.getFatalErrorMessagesAsText());
      return false;
    }
    else {
      System.out.println("Das Dokument entspricht Schema bzw. DTD");
      return true;
    }
  }

  public static String getUsage() {
    return USAGE;
  }
}