package es.ejie.frmk.control.excepciones;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * Clase base para el desarrollo de excepciones de Geremua, identifica las excepciones
 * del mismo. Geremua puede usarla lanzando una excepcion de este tipo o 
 * extendiendo la clase para los diferentes Componentes de Geremua.
 * 
 * @version 1.0 Fecha: 12-ene-04
 */
public class Q70FrameworkException extends Exception {

	private String componente = null;
	private String clase = null;
	private String metodo = null;
	private Throwable throwable = null;

	/**
	 * <p>
	 * Constructor por defecto para la clase <code>Q70FrameworkException</code>, clase base
	 * para el desarrollo de excepciones de Geremua
	 * </p>
	 * 
	 * @param componente Componente de Geremua afectado por la incidencia
	 * @param clase Nombre de la clase afectada por la incidencia.
	 * @param metodo Nombre de Metodo afectado por la incidencia.
	 * @param s Descripción de la excepción.
	 * @param t Excepcion producida
	 */
	public Q70FrameworkException(String componente, String clase,
			String metodo, String s, Throwable t) {
		super(s);
		setComponente(componente);
		setClase(clase);
		setMetodo(metodo);
		setThrowable(t);
	}

	/**
	 * Devuelve el nombre de la clase afectada por la incidencia.
	 * @return clase Nombre de la clase afectada por la incidencia.
	 */
	public String getClase() {
		return clase;
	}

	/**
	 * Devuelve Nombre del Componente de Geremua afectado por la incidencia.
	 * @return componente Nombre del Componente de Geremua afectado por la incidencia.
	 */
	public String getComponente() {
		return componente;
	}

	/**
	 * Devuelve Nombre de Metodo afectado por la incidencia.
	 * @return metodo Nombre de Metodo afectado por la incidencia.
	 */
	public String getMetodo() {
		return metodo;
	}

	/**
	 * Establece el nombre de la clase afectada por la incidencia.
	 * @param string Nombre de la clase afectada por la incidencia.
	 */
	public void setClase(String string) {
		clase = string;
	}

	/**
	 * Establece Nombre del Componente de Geremua afectado por la incidencia.
	 * @param string Nombre del Componente de Geremua afectado por la incidencia.
	 */
	public void setComponente(String string) {
		componente = string;
	}

	/**
	 * Establece Nombre de Metodo afectado por la incidencia.
	 * @param string Nombre de Metodo afectado por la incidencia.
	 */
	public void setMetodo(String string) {
		metodo = string;
	}

	/**
	 * Devuelve Excepcion producida.
	 * @return throwable Excepcion producida.
	 */
	public Throwable getThrowable() {
		return throwable;
	}

	/**
	 * Establece Excepcion producida.
	 * @param throwable Excepcion producida.
	 */
	public void setThrowable(Throwable throwable) {
		this.throwable = throwable;
	}

	/**
	 * <p>
	 * Pinta la traza del Thowable anidado (pasado como parametro en la Exception)
	 * en caso de que no sea nulo. Finalmente pinta la traza de la propia excepción.
	 * </p>
	 */
	public void printStackTrace() {
		if (null != throwable)
			throwable.printStackTrace();
		super.printStackTrace();
	}

	/**
	 * <p>
	 * Método de impresion de la traza
	 * </p>
	 * 
	 * @see java.lang.Throwable#printStackTrace(java.io.PrintWriter)
	 */
	public void printStackTrace(PrintWriter s) {
		
		s.println("Excepcion:  " + this.getClass().toString());
		s.println("Q70Mensaje:    " + this.getMessage());
		s.println("Componente: " + componente);
		s.println("Clase:      " + clase);
		s.println("Método:     " + metodo);
		s.println("******************************");
		if (null != throwable) {
			StringWriter sw = new StringWriter();
			PrintWriter aux = new PrintWriter(sw);

			throwable.printStackTrace(aux);
			s.println(sw.toString());
		}
	}

	/**
	 * <p>
	 * Se desempaquetan todas las excepciones anidadas que sean de tipo
	 * Q70FrameworkException hasta que encontremos la Excepcion primaria.
	 * </p>
	 * 
	 * @return throwable
	 */
	public Throwable getPrimaryException() {

		Throwable throwablePrimaria = this;
		Throwable throwableAnidada = throwable;
		boolean esFrameworkException = true;
		
		// Si la throwableAnidada es null devolvemos la Q70FrameworkException
		while (null != throwableAnidada && esFrameworkException) {
			// Si la throwableAnidada es Q70FrameworkException, seguimos probando con la siguiente throwable anidada.
			if (throwableAnidada instanceof Q70FrameworkException) {
				throwablePrimaria = throwableAnidada;
				throwableAnidada = ((Q70FrameworkException) throwableAnidada).getThrowable();
			} else {
				// Retornamos la throwableAnidada si NO es null y NO es Q70FrameworkException
				throwablePrimaria = throwableAnidada;
				esFrameworkException = false;
			}
		}

		return throwablePrimaria;
	}
}
