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

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

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70Traza;
import es.ejie.frmk.presentacion.operacion.Q70OperacionDePresentacionException;
import es.ejie.frmk.presentacion.operacion.datos.Q70OPForm;
import es.ejie.frmk.presentacion.operacion.datos.Q70OPValidatorForm;

/**
 * Clase que implementa un paso OP que redirige el flujo hacia otros según el valor de un atributo de la petición.
 * <p>
 * Esta clase no necesita ser extendida por la aplicación.
 * Internamente implementa un paso de OP que reencamina el flujo hacia una transición (ActionForward) identificada
 * con el valor de un atributo del bean de formulario cuyo nombre coincide con el atributo <code>parameter</code>
 * de la configuración del paso. 
 * 
 * Se usa para reencaminar una petición basándose en un valor de un parámetro de la request, el cual desencadenará 
 * un encaminamiento hacia un ActionForward cuyo "<code>path</code>" coincide con el valor de un parámetro de la request 
 * (o lo que es lo mismo, de un atributo del bean de formulario). El tipo del paso de OP de destino debe ser
 * <code>Q70ForwardConfigDispatchOPDeclarativo</code>
 * <p>
 * Por ejemplo: si el atributo "parameter" se configura en el fichero de configuración de la OP con valor "accion",
 * la clase acudirá a analizar el valor que llega en el atributo acción del bean de formulario. Supongamos que puede tener valores
 * “valor1” y “valor2”: en ese caso, el paso de OP lanzará un encaminamiento cuyo path valga “valor1” o “valor2”. Para ello,
 * la OP deberá tener configurados dos pasos de OP identificados con sendos paths "valor1" y "valor2" hacia los que reencaminará
 * el flujo.
 * No debe confundirse con el paso de OP <code>DispatchAction</code> de Struts, que ejecutaría el método valor1() o valor2() implementado por una clase de la aplicación que extendiese de DispatchAction e implementase esos dos métodos. 
 */

public class Q70ActionDispatchOPDeclarativo extends Action {

	/**
	 * 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();

	/**
	 * El método obtiene el valor de un atributo del bean de formulario de entrada y devuelve un <code>ActionForward</code>
	 * hacia un paso identificado con el valor de dicho atributo.
	 * <p>
	 * Para ello recoge el  valor <code>parameter</code> del fichero de configuración de la OP, acude al bean de formulario
	 * y consulta el valor del atributo identificado con el valor anterior.
	 * A continuación, invoca al método <code>dispatch()</code> y delega en él el procesamiento de la petición.
	 * 
	 * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
	{	
		ActionForward forward = null;
		String parameter = null;
		String parameterValue = null;
		if (null != form)
		{
			if (tr.isTraceActive())
			{
				if (form instanceof Q70OPValidatorForm)
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Formulario recibido en Q70ActionDispatchOPDeclarativo(con validator):\n"+((Q70OPValidatorForm)form).toString());
				}
				else if (form instanceof Q70OPForm)
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Formulario en Q70ActionDispatchOPDeclarativo:\n"+((Q70OPForm)form).toString());
				}
			}
		}
		try
		{
			parameter = mapping.getParameter();
			if (null == parameter)
			{
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Q70ActionDispatchOPDeclarativo: Falta el atributo parameter del Q70ActionDispatchOPDeclarativo en el fichero de configuración de Struts correspondiente.");
				}
				throw new Q70OperacionDePresentacionException (this.getClass().toString(),"execute","Falta el atributo parameter del Q70ActionDispatchOPDeclarativo en el fichero de configuración de Struts correspondiente.",null);
			}
			else
			{
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Atributo para dispatch (parameter)= "+parameter);
				}
				String path = null;
				if (form instanceof Q70OPValidatorForm)
				{
					parameterValue = (String)((Q70OPValidatorForm)form).get(parameter);
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Obteniendo valor para dispatch (Q70OPValidatorForm)="+parameterValue);
					}
					path = dispatch(parameterValue,mapping);
				}
				else if (form instanceof Q70OPForm)
				{
					parameterValue = (String)((Q70OPForm)form).get(parameter);
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Obteniendo valor para dispatch (Q70OPForm)="+parameterValue);
					}
					path = dispatch(parameterValue,mapping);
				}
				
				forward = new ActionForward(path);
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Salida de dispatch = " + forward.getPath());
				}
			}
		}
		catch(Exception e)
		{
			throw new Q70OperacionDePresentacionException (this.getClass().toString(),"execute","Excepción en Paso de Operacion de Presentacion",e);
		}
		return forward;
	}
	
	/**
	 * Método que devuelve el path correspondiente al paso identificado con el valor "value" pasado como parámetro.
	 * <p>
	 * Para ello se encarga de encontrar en el fichero de configuración de la OP
	 * el paso de tipo <code>Q70ForwardConfigDispatchOPDeclarativo</code> identificado con 
	 * el <code>value</code> que se le pasa como parámetro. A continuación devuelve el <code>ActionForward</code> 
	 * correspondiente. 
	 * 
	 * @param value Identificador del paso
	 * @param mapping Configuración de los pasos de una operacion de presentacion.
	 * @return Path correspondiente al paso
	 * @throws Exception
	 */
	public String dispatch(String value, ActionMapping mapping) throws Exception
	{
		String forwardPath = null;
		
		try {
			ActionForward forward = (ActionForward)mapping.findForward(value);
			forwardPath = (String)forward.getPath();
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Valor para dispatch ("+value+")= "+forwardPath);
			}
		} 
		catch (Exception e) {
			throw new Q70OperacionDePresentacionException (this.getClass().toString(),"dispatch","ERROR al buscar el <forward> adecuado para ["+value+"].",e);
		}
		return forwardPath;
	}	
}
