/*
Copyright (c) 2002, Matthias Bauer, LIVINGLOGIC AG, BAYREUTH
All rights reserved.econdary

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are 
met:

    1. Redistributions of source code must retain the above copyright 
       notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright 
       notice, this list of conditions and the following disclaimer in the 
       documentation and/or other materials provided with the distribution.
    3. The end-user documentation included with the redistribution, if
       any, must include the following acknowlegement:
       "This product includes software developed by 
        Matthias Bauer, LIVINGLOGIC AG, BAYREUTH 
        (http://www.livinglogic.de/)."
       Alternately, this acknowlegement may appear in the software itself,
       if and wherever such third-party acknowlegements normally appear.
    4. Neither the name of Matthias Bauer, nor the LIVINGLOGIC AG nor the 
       names of the other contributors may be used to endorse or promote 
       products derived from this software without specific prior written
       permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
 */

package es.ejie.frmk.presentacion.base;


import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.Vector;

import org.apache.struts.action.ActionMapping;


/**
 * <p>
 * Implementation of enhanced <code>ActionMapping</code>.
 * It defines the following custom properties:
 * <ul>
 * <li><b>primary</b> - The label of the workflow this action mapping
 *     belongs to.</li>
 * <li><b>secondary</b> - The label of a further workflow this action
 *     can depend on.</li>
 * <li><b>prevState</b> - The label of a state which may precede in the given 
 *     workflow. This property can be set multiple times to allow multiple 
 *     valid prevStates for a workflow.</li>
 * <li><b>newState</b> - The label of the state this action leads to in
 *     the given workflow. If not specified for a workflow the state is not
 *     changed upon action execution.</li>
 * <li><b>nextState</b> - The label of a state which may follow in the given 
 *     workflow. This property can be set multiple times to allow multiple valid 
 *     nextStates for an action.</li>
 * <li><b>end</b> - If "true" (case insensitive string), the given workflow
 *     ends with this action. If this property is not given, it defaults to 
 *     false.</li>
 * <li><b>noWorkflowChecks</b> - If "true" (case insensitive string), this action
 *     is ignored in terms of workflow checks, i. e. this action can be executed
 *     even if a currently active workflow defines a certain nextState condition,
 *     this action does not lead to. If this property is set, no other workflow
 *     properties are allowed to be set. It defaults to false.</li> 
 * <li><b>authClass</b> - The name of the authentication class which checks if the
 *     user is allowed to execute the action.</li>
 * </ul>
 * </p>
 *
 * @author M. Bauer, A. Lamm
 */

public class Q70PasosOPMapping extends ActionMapping
{
	/**
	 * The label of the latest registered workflow
	 */
	private String latestRegisteredWorkflowLabel;

	/**
	 * The data of the latest registered workflow
	 */
	private WorkflowData latestRegisteredWorkflow;

	/**
	 * The workflows for this mapping
	 */
	private Hashtable workflows = new Hashtable();

	/**
	 * The workflow names for this mapping (kept separately to ensure correct order)
	 */
	private Vector workflowNames = new Vector();

	/**
	 * Returns the labels of all workflows for this mapping.
	 */
	public Collection getWorkflows()
	{
		return workflowNames;
	}

	/**
	 * The label of the workflow this mapping belongs to
	 */
	private String primary;

	/**
	 * Returns the label of the workflow this mapping belongs to.
	 */
	public String getPrimary()
	{
		return primary;
	}

	/**
	 * Register the label of the workflow this mapping belongs to.
	 * @param primary the label of the workflow this
	 *     mapping belongs to.
	 */
	public void setPrimary(String primary)
	{
		this.primary = primary;
		addWorkflow(primary);
	}

	/**
	 * Register the label of a further workflow for this mapping.
	 * @param secondary the label of a further workflow
	 *     for this mapping
	 */
	public void setSecondary(String secondary)
	{
		addWorkflow(secondary);
	}

	/**
	 * Register the label of a further workflow for this mapping.
	 * @param workflow the label of the additional workflow for this mapping
	 */
	protected void addWorkflow(String workflow)
	{
		if ((null == workflow) || (0 == workflow.length()))
		{
			throw new IllegalArgumentException("A workflow label must not be empty.");
		}
		if (noWorkflowChecks)
		{
			throw new IllegalArgumentException("It is illegal to define workflows and set noWorkflowChecks=true within a single action mapping.");
		}

		latestRegisteredWorkflow = new WorkflowData();
		latestRegisteredWorkflowLabel = workflow;
		workflows.put(workflow, latestRegisteredWorkflow);
		workflowNames.add(workflow);
	}

	/**
	 * Returns the WorkflowData object of the specified workflow or null,
	 * if the specified workflow does not exist.
	 * @param workflow the label of the workflow
	 */
	public WorkflowData getWorkflowData(String workflow)
	{
		return (WorkflowData)workflows.get(workflow);
	}

	/**
	 * Set a prevState for the latest registered workflow of this mapping.
	 * @param prevState the prevState for this mapping
	 */
	public void setPrevState(String prevState)
	{
		if (null == latestRegisteredWorkflow)
		{
			throw new IllegalArgumentException("A prevState definition must belong to a workflow.");			
		}
		latestRegisteredWorkflow.prevStates.add(prevState);
	}

	/**
	 * Set a newState for the latest registered workflow of this mapping,
	 * if not yet set.
	 * @param newState the newState for this mapping
	 */
	public void setNewState(String newState)
	{
		if (null == latestRegisteredWorkflow)
		{
			throw new IllegalArgumentException("A newState definition must belong to a workflow.");			
		}
		if (latestRegisteredWorkflow.newState != null)
		{
			throw new IllegalStateException("Only one newState may be defined for an action.");
		}
		latestRegisteredWorkflow.newState = newState;
	}

	/**
	 * Set a nextState for the latest registered workflow of this mapping.
	 * @param nextState the nextState for this mapping
	 */
	public void setNextState(String nextState)
	{
		if ((null == latestRegisteredWorkflowLabel) || (null == primary) || (!primary.equals(latestRegisteredWorkflowLabel)))
		{
			throw new IllegalArgumentException("A nextState definition must belong to a primary workflow.");			
		}
		latestRegisteredWorkflow.nextStates.add(nextState);
	}

	/**
	 * Set the end property for the latest registered workflow
	 * of this mapping.
	 * @param end a String representing a boolean value:
	 *     "true" (case insensitive) for true, any other String for false.
	 */
	public void setEnd(String end)
	{
		if (null == latestRegisteredWorkflow)
		{
			throw new IllegalArgumentException("An end definition must belong to a workflow.");			
		}
		latestRegisteredWorkflow.endsWorkflow = new Boolean(end).booleanValue();
	}

	/**
	 * A boolean flag that is set to true, if this is an action on which no workflow 
	 * checks are performed. If an action is marked with this flag, it cannot define
	 * any workflows and thus cannot change the state of any workflow container. 
	 */
	private boolean noWorkflowChecks = false;

	/**
	 * Return the noWorkflowChecks value for this mapping.
	 */
	public boolean hasNoWorkflowChecksSet()
	{
		return noWorkflowChecks;
	}

	/**
	 * Set noWorkflowChecks value for this mapping.
	 * @param value a String representing a boolean value:
	 *     "true" (case insensitive) for true, any other String for false.
	 */
	public void setNoWorkflowChecks(String value)
	{
		this.noWorkflowChecks = new Boolean(value).booleanValue();
		if (this.noWorkflowChecks && (null != latestRegisteredWorkflow))
		{
			throw new IllegalArgumentException("It is illegal to define workflows and set noWorkflowChecks=true within a single action mapping.");
		}
	}
	
	/**
	 * Path de retorno tras finalizar SubOperación de Presentación
	 */
	private String subOpRetPath = null;
	
	/**
	 * Flag indicador de inicio/fin de SubOperación de Presentación
	 */
	private String subOp = null;
	
	/**
	 * Flag indicador de comienzo/fin de SubOperación de Presentación Remota
	 */
	private String callOpRemota = null;
	
	/**
	 * Flag indicador de comienzo/fin de Reenvío
	 */
	private String opReenvio = null;	
	
	/**
	 * Ambito de mensajes e internacionalización
	 */
	private String i18nKey = null;
		
	/**
	 * Clase que implementa la selección de ActionForward a la salida de un Q70ActionOIRouterDeclarativo
	 */
	private String routerClass = null;
	
	/**
	 * Nombre del mapeo que se realizará antes de ejecutar el action.
	 */
	private String mapa = null;
	
	/**
	 * Atributos del contexto que se quieren poner a un valor null, para
	 * liberar memoria.
	 */
	private String erase = null;
	
	/**
	 * Indica el permiso de seguridad que necesita este Paso de OP.
	 */
	private String secureId = null;

	/**
	 * Flag indicador de comienzo de una suboperacion que se va a realizar en Geremua version 1.x
	 */
	private String opVersion1 = null;

	/**
	 * Constructor
	 */
	public Q70PasosOPMapping()
	{
		super();
	}

	/**
	 * Class that holds mapping data for a labeled workflow
	 */
	public static class WorkflowData implements java.io.Serializable
	{
		/**
		 * The set of previous states allowed for this workflow
		 */
		private HashSet prevStates = new HashSet();

		/** Returns prevStates */
		public Set getPrevStates() { return prevStates; }		

		/**
		 * The label of the state this mapping leads to in this workflow.
		 */
		private String newState = null;
		
		/** Returns newState */
		public String getNewState() { return newState; }		

		/**
		 * The set of following states allowed for this workflow
		 */
		private HashSet nextStates = new HashSet();
		
		/** Returns nextStates */
		public Set getNextStates() { return nextStates; }		

		/**
		 * If true, this workflow ends with this action mapping.
		 */
		private boolean endsWorkflow = false;

		/** Returns endsWorkflow */
		public boolean getEndsWorkflow() { return endsWorkflow; }		
	}
	
	/**
	 * Devuelve el path de retorno de la suboperacion una vez finalizada.
	 * @return Path de retorno de la suboperacion
	 */
	public String getSubOpRetPath() {
		return subOpRetPath;
	}
	/**
	 * @param string
	 */
	public void setSubOpRetPath(String string) {
		subOpRetPath = string;
	}
	
	/**
	 * Devuelve el tipo de paso de operacion definido en el atributo 'subOp'.
	 * Valores posibles:
	 * <ul>
	 * <li>init</li>
	 * <li>end</li>
	 * <li>reset</li>
	 * </ul>
	 * @return Tipo de paso de operacion 
	 */
	public String getSubOp() {
		return subOp;
	}

	/**
	 * @param string
	 */
	public void setSubOp(String string) {
		subOp = string;
	}
	
	/**
	 * Devuelve el ambito de internacionalizacion definido en el atributo 'i18nKey'.
	 * @return Ambito de internacionalizacion
	 */
	public String getI18nKey() {
		return i18nKey;
	}

	/**
	 * @param string
	 */
	public void setI18nKey(String string) {
		i18nKey = string;
	}

	/**
	 * Devuelve la clase enrutadora que controla el flujo de navegacion definido en el atributo 'routerClass'.
	 * @return Nombre de la Clase enrutadora
	 */
	public String getRouterClass() {
		return routerClass;
	}

	/**
	 * @param string
	 */
	public void setRouterClass(String string) {
		routerClass = string;
	}
	
	/**
	 * Indica el incio, final de una suboperacion o un reenvio remoto definido en el atributo 'callOpRemota'.
	 * Valores posibles:
	 * <ul>
	 * <li>init</li>
	 * <li>end</li>
	 * <li>reenvio</li>
	 * </ul>
	 * @return String con el estado
	 */
	public String getCallOpRemota() {
		return callOpRemota;
	}

	/**
	 * @param string
	 */
	public void setCallOpRemota(String string) {
		callOpRemota = string;
	}

	/**
	 * Devuelve el nombre de atributo de contexto a inicializar a null, definido en el atributo 'erase'.
	 * @return Nombre de atributo de contexto
	 */
	public String getErase() {
		return erase;
	}

	/**
	 * Devuelve el mapa a aplicar en la transferencia de datos de contexto entre pasos de operacion, definido en el atributo 'mapa'.
	 * @return Mapa a aplicar en la transferencia de datos de contexto
	 */
	public String getMapa() {
		return mapa;
	}

	/**
	 * @param string
	 */
	public void setErase(String string) {
		erase = string;
	}

	/**
	 * @param string
	 */
	public void setMapa(String string) {
		mapa = string;
	}

	/**
	 * Indica el incio, final de un reenvio definido en el atributo 'opReenvio'.
	 * Valores posibles:
	 * <ul>
	 * <li>init</li>
	 * <li>end</li>
	 * </ul>
	 * @return String con el estado
	 */
	public String getOpReenvio() {
		return opReenvio;
	}

	/**
	 * @param opReenvio
	 */
	public void setOpReenvio(String opReenvio) {
		this.opReenvio = opReenvio;
	}
	
	/**
	 * @param secureId
	 */
	public void setSecureId(String secureId){
		this.secureId=secureId;
	}
	
	/**
	 * Devuelve el permiso definido para invocar este paso OP, definido en el atributo 'secureId'.
	 * @return Permiso para invocar este paso OP
	 */
	public String getSecureId(){
		return secureId;
	}

	/**
	 * Indica si se trata de una suboperacion que va a redirigirse a Geremua version 1.x., definido en el atributo 'opVersion1'.
	 * Valores posibles:
	 * <ul>
	 * <li>init</li>
	 * </ul>
	 * @return String con el estado
	 */
	public String getOpVersion1() {
		return opVersion1;
	}
	
	/**
	 * @param opVersion1
	 */
	public void setOpVersion1(String opVersion1) {
		this.opVersion1 = opVersion1;
	}
}
