package at.gv.egovernment.moa.id;

import java.io.PrintStream;
import java.io.PrintWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import at.gv.egovernment.moa.id.util.MOAIDMessageProvider;
import at.gv.egovernment.moa.util.Constants;

/**
 * Base class of technical MOA exceptions.
 * 
 * Technical exceptions are exceptions that originate from system failure (e.g.,
 * a database connection fails, a component is not available, etc.)
 * 
 * @author Patrick Peck, Ivancsics Paul
 * @version $Id$
 */
public class MOAIDException extends Exception {
  /** message ID */
  private String messageId;
  /** wrapped exception */
  private Throwable wrapped;

  /**
   * Create a new <code>MOAIDException</code>.
   * 
   * @param messageId The identifier of the message associated with this 
   * exception.
   * @param parameters Additional message parameters.
   */
  public MOAIDException(String messageId, Object[] parameters) {
    super(MOAIDMessageProvider.getInstance().getMessage(messageId, parameters));
    this.messageId = messageId;
  }

  /**
   * Create a new <code>MOAIDException</code>.
   * 
   * @param messageId The identifier of the message associated with this 
   * <code>MOAIDException</code>.
   * @param parameters Additional message parameters.
   * @param wrapped The exception wrapped by this
   * <code>MOAIDException</code>.
   */
  public MOAIDException(
    String messageId,
    Object[] parameters,
    Throwable wrapped) {
      
    super(MOAIDMessageProvider.getInstance().getMessage(messageId, parameters));
    this.messageId = messageId;
    this.wrapped = wrapped;
  }

  /**
   * Print a stack trace of this exception to <code>System.err</code>.
   * 
   * @see java.lang.Throwable#printStackTrace()
   */
  public void printStackTrace() {
    printStackTrace(System.err);
  }

  /**
   * Print a stack trace of this exception, including the wrapped exception.
   * 
   * @param s The stream to write the stack trace to.
   * @see java.lang.Throwable#printStackTrace(java.io.PrintStream)
   */
  public void printStackTrace(PrintStream s) {
    if (getWrapped() == null)
      super.printStackTrace(s);
    else {
      s.print("Root exception: ");
      getWrapped().printStackTrace(s);
    }
  }

  /**
   * Print a stack trace of this exception, including the wrapped exception.
   * 
   * @param s The stream to write the stacktrace to.
   * @see java.lang.Throwable#printStackTrace(java.io.PrintWriter)
   */
  public void printStackTrace(PrintWriter s) {
    if (getWrapped() == null)
      super.printStackTrace(s);
    else {
      s.print("Root exception: ");
      getWrapped().printStackTrace(s);
    }
  }

  /**
   * @return message ID
   */
  public String getMessageId() {
    return messageId;
  }

  /**
   * @return wrapped exception
   */
  public Throwable getWrapped() {
    return wrapped;
  }

  /**
   * Convert this <code>MOAIDException</code> to an <code>ErrorResponse</code>
   * element from the MOA namespace.
   * 
   * @return An <code>ErrorResponse</code> element, containing the subelements
   * <code>ErrorCode</code> and <code>Info</code> required by the MOA schema.
   */
  public Element toErrorResponse() {
    DocumentBuilder builder;
    DOMImplementation impl;
    Document doc;
    Element errorResponse;
    Element errorCode;
    Element info;

    // create a new document
    try {
      builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
      impl = builder.getDOMImplementation();
    } catch (ParserConfigurationException e) {
      return null;
    }

    // build the ErrorResponse element
    doc = impl.createDocument(Constants.MOA_NS_URI, "ErrorResponse", null);
    errorResponse = doc.getDocumentElement();

    // add MOA namespace declaration
    errorResponse.setAttributeNS(
      Constants.XMLNS_NS_URI,
      "xmlns",
      Constants.MOA_NS_URI);

    // build the child elements    
    errorCode = doc.createElementNS(Constants.MOA_NS_URI, "ErrorCode");
    errorCode.appendChild(doc.createTextNode(messageId));
    info = doc.createElementNS(Constants.MOA_NS_URI, "Info");
    info.appendChild(doc.createTextNode(toString()));
    errorResponse.appendChild(errorCode);
    errorResponse.appendChild(info);
    return errorResponse;
  }

}