package es.ejie.frmk.presentacion.operacion.paso;

import java.util.Iterator;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;

import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70Traza;
import es.ejie.frmk.negocio.operacioninterna.Q70ConstantesOI;
import es.ejie.frmk.negocio.operacioninterna.Q70FactoriaOperacionesInternas;
import es.ejie.frmk.negocio.operacioninterna.Q70OperacionInternaBase;
import es.ejie.frmk.negocio.operacioninterna.Q70OperacionInternaError;
import es.ejie.frmk.negocio.operacioninterna.Q70OperacionInternaErrors;
import es.ejie.frmk.presentacion.operacion.Q70OperacionDePresentacionException;
import es.ejie.frmk.presentacion.sesiondatos.Q70ContextoEJIE;

/**
 * Esta clase implementa la funcionalidad de paso de Operación de Presentación que va a acceder a lógica de negocio.
 * <p>
 * Encapsula las problemáticas de:
 * <UL>
 * <li>Petición de instancia de Operación Interna a la factoría de Operaciones Internas,</li>
 * <li>Paso del contexto hacia la Operación Interna,</li>
 * <li>Recepción del resultado una vez ejecutada la OI,</li>
 * <li>Mapping automático de errores de OI sobre errores de Operación de Presentación.</li>
 * </UL> 
 * <p>
 * La clase <b>deberá ser extendida por la aplicación</b>, de tal modo que:
 * <UL>  
 * <li>sobrecargue un método abstracto (<code>processOI</code>)  que es el lugar adecuado para manipular algún atributo del contexto previamente a la invocación a la OI,
 * invocar a la OI y después manipular algún atributo depositado en el contexto por la OI .</li>
 * <li>sobrecargue un método abstracto (<code>processForward</code>) para la decisión de encaminamiento posterior.</li>
 * </UL>
 * @version 1.0
 * Fecha: 09-ene-04
 */
public abstract class Q70ActionOI extends Q70ActionPasoOP {

	/**
	 * Etiqueta para errores de lógica de negocio.
	 */
	protected static final String OI_ERROR_KEY = Q70ConstantesOI.OI_ERROR_KEY;
	
	/**
	 * Constante que indica el componente al que pertenece la clase. Es
	 * necesario para el uso del log de trazas.
	 */
	private static final String COMPONENTE = "OPERACION_PRESENTACION";
	
	/**
	 * Instancia del log de trazas
	 */
	private static Q70Traza tr = Q70Traza.getSingleton();

	/**
	 * Método que aporta funcionalidad común a todas los pasos de OP que invocan a negocio.
	 * <p>
	 * 
	 * Se trata de un método que realiza una secuencia de operaciones comunes a todas las clases que desciendan de ella.
	 * <LU>
	 * <li>Invoca al método processOI de la clase hija, recogiendo la estructura de errores de Operación Interna</li>
	 * <li>Mapea los errores de OI sobre errores de presentación</li>
	 * </LU>
	 * 
	 * @see es.ejie.frmk.presentacion.operacion.paso.Q70ActionPasoOP#processOP(es.ejie.frmk.presentacion.sesiondatos.Q70ContextoEJIE, org.apache.struts.action.ActionErrors, org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	protected void processOP(Q70ContextoEJIE contexto, ActionErrors errores, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
	{
		Q70OperacionInternaErrors errorsOI = null;
		try
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Llamando al método processOI de la clase de Q70ActionOI...");
			}
			//Hijo
			errorsOI = processOI(contexto,mapping,form,request,response);
			//Hijo
		
			//Mapeo de errores de OI sobre errores de Presentación
			if (errorsOI != null)
			{
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Mapeando errores de negocio a errores de presentación.");
				}
				Iterator iter = errorsOI.get();
				while(iter.hasNext())
				{
					Q70OperacionInternaError serror =  (Q70OperacionInternaError)iter.next();
					errores.add(OI_ERROR_KEY, new ActionError (serror.getKey(),serror.getValues()));
				}
			}
		}
		catch (Exception e)
		{
			throw new Q70OperacionDePresentacionException (this.getClass().toString(),"processOP","Excepción recogida por Action invocador de Operación Interna.",e);
		}
	}

	/**
	 * Método a implementar por la clase hija que debe encargarse de resolver la llamada a la lógica de
	 * negocio (Operación Interna).
	 * <p>
	 * El método permite la posibilidad de modificar datos del contexto antes y después de invocar a 
	 * la lógica de negocio.
	 * La clase <code>Q70ActionOI</code> facilita el método <code>executeOI()</code> con una implementación
	 * de llamada a Operación Interna.Ejemplo: this.executeOI(nombre_OI,contexto).
	 *  
	 * @param contexto Estructura de contexto genérica. 
	 * @param mapping Configuración de los pasos de una operacion de presentacion.
	 * @param form Bean de Formulario de la página anterior.
	 * @param request Petición a atender
	 * @param response Respuesta a generar
	 * @return Estructura de errores de Operación Interna
	 * @throws Exception
	 */
	protected abstract Q70OperacionInternaErrors processOI(Q70ContextoEJIE contexto, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception;
	
	
	/**
	 * Método que facilita la invocación a una Operación Interna.
	 * <p>
	 * Para ello pide a la <b>Factoría de Operaciones Internas</b> una instancia de la OI necesaria.
	 * A continuación invocará la ejecución de la Operación Interna, esperando síncronamente como respuesta
	 * una estructura de errores de Operación Interna.
	 *  
	 * @param operacionInternaId Identificador de la Operación Interna
	 * @param contexto Estructura de contexto genérica.
	 * @return Estructura de errores de Operación Interna
	 * @throws Exception
	 */
	protected Q70OperacionInternaErrors executeOI (String operacionInternaId, Q70ContextoEJIE contexto) throws Exception
	{
		try {
			Q70OperacionInternaBase oi = Q70FactoriaOperacionesInternas.getSingleton().getOperacionInterna(operacionInternaId);
			return oi.processOI(contexto);
		} catch (Exception e) {
			throw new Q70OperacionDePresentacionException (this.getClass().toString(),"getOI","Excepción recogida por Action invocador de Operación Interna al obtener la Q70OperacionInternaBase: "+operacionInternaId+".",e);
		}
	}
}
