/*
 * Creado el 24-nov-03
 *
 * Para cambiar la plantilla para este archivo generado vaya a
 * Ventana&gt;Preferencias&gt;Java&gt;Generación de código&gt;Código y comentarios
 */
package es.ejie.frmk.presentacion.sesiondatos;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaClass;

import es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.Q70ManejadorPersistenciaContextoEJIE;
import es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.Q70PersistenciaMalInicializadaException;

/**
 * @version 1.0
 * Fecha: 24-nov-03
 * 
 * Implementacion de un contexto que ademas de contener sus datos basicos contiene 
 * una lista de contextos de antecesores, que sabe recorrer para buscar los datos
 * demandados por las clases clientes.
 * 
 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoBasico
 */
public class Q70ContextoOperacion extends Q70ContextoBasico implements Externalizable
{
	private List contextoSesion;
	private static final int NUMERO_DE_CONTEXTOSESION = 8;

	/**
	 * @version 1.0
	 * Fecha: 22-dic-03
	 * 
	 * Clase abstracta que nos ayuda a recorrer la lista de contextos
	 */
	private abstract class ContextoBlock
	{
		/**
		 * Sobreescribiendo este metodo se consigue realizar diferentes tratamientos a la hora 
		 * de tratar la lista de contextos.
		 * 
		 * @param dynaBean Un contexto, null si no es necesario
		 * @param name Nombre del valor a buscar, null si no es necesario
		 * @param key Clave del valor a buscar si el tipo de valor es un Map, null si no es necesario
		 * @param index Indice del valor a buscar si el tipo de valor es una List, null si no es necesario
		 * @param value Valor a modificar, null si no es necesario
		 * @return Devuelve un Object a tratar por el metodo invocador segun corresponda
		 */
		public abstract Object execDynaBean(DynaBean dynaBean, String name, String key, int index, Object value);
	}

	/**
	 * Necesario porque es una clase Externalizable, debe tener un constructor sin argumentos
	 */
	public Q70ContextoOperacion()
	{
		super();
		contextoSesion = new ArrayList(NUMERO_DE_CONTEXTOSESION);
	}

	/**
	 * Construye un nuevo <code>Q70ContextoOperacion</code> asociado a la instancia de 
	 * <code>DynaClass</code> especificada.
	 *
	 * @param dynaClass La DynaClass asociada
	 */
	public Q70ContextoOperacion(DynaClass dynaClass)
	{
		super(dynaClass);
		contextoSesion = new ArrayList(NUMERO_DE_CONTEXTOSESION);
	}

	/**
	 * @param aDynaBean 
	 * @param aManejadorPersistencia
	 * @param aTipoContexto
	 * @param aIdContexto
	 */
	public Q70ContextoOperacion(DynaBean aDynaBean, Q70ManejadorPersistenciaContextoEJIE aManejadorPersistencia, String aTipoContexto, String aIdContexto)
	{
		super(aDynaBean, aManejadorPersistencia, aTipoContexto, aIdContexto);
		contextoSesion = new ArrayList(NUMERO_DE_CONTEXTOSESION);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE#getContextoSesion(int)
	 */
	public Q70ContextoJerarquicoEJIE getContextoSesion(int i)
	{
		if (contextoSesion == null)
		{
			return null;
		}
		if (i >= contextoSesion.size())
			return null;
		return (Q70ContextoJerarquicoEJIE) contextoSesion.get(i);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE#getContextoSesion(java.lang.String)
	 */
	public Q70ContextoJerarquicoEJIE getContextoSesion(String tipoContexto)
	{
		if (getTipoContexto().equals(tipoContexto))
			return this;

		if (contextoSesion == null)
		{
			return null;
		}
		for (int i = contextoSesion.size() - 1; i >= 0; i--)
			if (getContextoSesion(i).getTipoContexto().equals(tipoContexto))
				return (Q70ContextoJerarquicoEJIE) getContextoSesion(i);
		return null;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE#removeContextoSesion(es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE)
	 */
	public void removeContextoSesion(Q70ContextoJerarquicoEJIE contexto)
	{
		if (contextoSesion == null)
		{
			return;
		}
		contextoSesion.remove(contexto);
		List auxList = getContextoClassAncestors();
		((Q70ContextoEJIEDynaClass) getDynaClass()).setContextoAntecesoresClass(auxList);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE#addContextoSesion(es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE)
	 */
	public void addContextoSesion(Q70ContextoJerarquicoEJIE contexto)
	{
		if (contextoSesion == null)
		{
			contextoSesion = new ArrayList(NUMERO_DE_CONTEXTOSESION);
		}

		if (contextoSesion.contains(contexto))
			return;
		contextoSesion.add(contexto);

		List auxList = getContextoClassAncestors();
		((Q70ContextoEJIEDynaClass) getDynaClass()).setContextoAntecesoresClass(auxList);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE#setContextoLista(java.util.List)
	 */
	public void setContextoLista(List listaAncestros)
	{
		// TODO Jgrey setContextoLista() Recorrer la lista, comprobando tipos y devolviendo excepcion ??
		contextoSesion = listaAncestros;
		((Q70ContextoEJIEDynaClass) getDynaClass()).setContextoAntecesoresClass(getContextoClassAncestors());
	}

	private List getContextoClassAncestors()
	{
		if (contextoSesion == null || contextoSesion.size() == 0)
			return null;

		List auxDynaClass = new ArrayList(contextoSesion.size());

		Iterator it = contextoSesion.iterator();
		while (it.hasNext())
		{
			auxDynaClass.add(((DynaBean) it.next()).getDynaClass());
		}

		return auxDynaClass;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE#getContextoLista()
	 */
	public List getContextoLista()
	{
		return contextoSesion;
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#getDynaClass()
	 */
	public DynaClass getDynaClass()
	{
		return super.getDynaClass();
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#contains(java.lang.String, java.lang.String)
	 */
	public boolean contains(String name, String key)
	{
		if (super.contains(name, key))
			return true;

		ContextoBlock bl = new ContextoBlock()
		{
			public Object execDynaBean(DynaBean dynaBean, String name, String key, int index, Object value)
			{
				return Boolean.TRUE;
			}
		};

		if (((Boolean) recorrerContextos(bl, name, key, -1, null)).equals(Boolean.TRUE))
			return true;
		return false;
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#get(java.lang.String)
	 */
	public Object get(String name)
	{
		try
		{
			Object obj = super.get(name);
			return obj;
		}
		catch (IllegalArgumentException e)
		{}

		ContextoBlock bl = new ContextoBlock()
		{
			public Object execDynaBean(DynaBean dynaBean, String name, String key, int index, Object value)
			{
				return dynaBean.get(name);
			}
		};
		return recorrerContextos(bl, name, null, -1, null);
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#get(java.lang.String, int)
	 */
	public Object get(String name, int index)
	{
		try
		{
			return super.get(name, index);
		}
		catch (IllegalArgumentException e)
		{}

		ContextoBlock bl = new ContextoBlock()
		{
			public Object execDynaBean(DynaBean dynaBean, String name, String key, int index, Object value)
			{
				return dynaBean.get(name, index);
			}
		};
		return recorrerContextos(bl, name, null, index, null);
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#get(java.lang.String, java.lang.String)
	 */
	public Object get(String name, String key)
	{
		try
		{
			return super.get(name, key);
		}
		catch (IllegalArgumentException e)
		{}

		ContextoBlock bl = new ContextoBlock()
		{
			public Object execDynaBean(DynaBean dynaBean, String name, String key, int index, Object value)
			{
				Object obj = dynaBean.get(name, key);
				return obj;
			}
		};
		return recorrerContextos(bl, name, key, -1, null);
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#remove(java.lang.String, java.lang.String)
	 */
	public void remove(String name, String key)
	{
		try
		{
			super.remove(name, key);
		}
		catch (IllegalArgumentException e)
		{}

		ContextoBlock bl = new ContextoBlock()
		{
			public Object execDynaBean(DynaBean dynaBean, String name, String key, int index, Object value)
			{
				dynaBean.remove(name, key);
				return "";
			}
		};
		recorrerContextos(bl, name, key, -1, null);
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#set(java.lang.String, java.lang.Object)
	 */
	public void set(String name, Object value)
	{
		try
		{
			super.set(name, value);
			return;
		}
		catch (IllegalArgumentException e)
		{}

		ContextoBlock bl = new ContextoBlock()
		{
			public Object execDynaBean(DynaBean dynaBean, String name, String key, int index, Object value)
			{
				dynaBean.set(name, value);
				return "";
			}
		};
		recorrerContextos(bl, name, null, -1, value);
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#set(java.lang.String, int, java.lang.Object)
	 */
	public void set(String name, int index, Object value)
	{
		try
		{
			super.set(name, index, value);
			return;
		}
		catch (IllegalArgumentException e)
		{}

		ContextoBlock bl = new ContextoBlock()
		{
			public Object execDynaBean(DynaBean dynaBean, String name, String key, int index, Object value)
			{
				dynaBean.set(name, index, value);
				return "";
			}
		};
		recorrerContextos(bl, name, null, index, value);
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#set(java.lang.String, java.lang.String, java.lang.Object)
	 */
	public void set(String name, String key, Object value)
	{
		try
		{
			super.set(name, key, value);
			return;
		}
		catch (IllegalArgumentException e)
		{}

		ContextoBlock bl = new ContextoBlock()
		{
			public Object execDynaBean(DynaBean dynaBean, String name, String key, int index, Object value)
			{
				dynaBean.set(name, key, value);
				return "";
			}
		};
		recorrerContextos(bl, name, key, -1, value);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoBasico#equals(java.lang.Object)
	 */
	public boolean equals(Object obj)
	{
		if (!super.equals(obj))
			return false;

		if (contextoSesion == null)
		{
			if (((Q70ContextoJerarquicoEJIE) obj).getContextoLista() == null || ((Q70ContextoJerarquicoEJIE) obj).getContextoLista().size() == 0)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		Iterator it = contextoSesion.iterator();
		int i = 0;
		while (it.hasNext())
		{
			if (!it.next().equals(((Q70ContextoJerarquicoEJIE) obj).getContextoSesion(i++)))
				return false;
		}

		return true;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoBasico#equals(java.lang.Object)
	 */
	public String toString()
	{
		StringBuffer strAux = new StringBuffer(100);

		strAux.append("<contexto>");
		strAux.append("\n");

		strAux = toStringValoresClase(strAux);
		strAux.append("\n");

		strAux = toStringListaAtributos(strAux, super.getDynaClass());
		strAux.append("\n");

		if (contextoSesion != null)
		{
			strAux.append("<listaContextos>");
			strAux.append("\n");
			int sizeList = contextoSesion.size();
			for (int i = 0; i < sizeList; i++)
			{
				Q70ContextoJerarquicoEJIE ctxAux = (Q70ContextoJerarquicoEJIE) contextoSesion.get(i);
				//strAux.append(ctxAux.toString());
				strAux.append("<idContexto>");
				strAux.append(ctxAux.getIdContexto());
				strAux.append("</idContexto>");
				strAux.append("\n");
			}
			strAux.append("</listaContextos>");
			strAux.append("\n");
		}

		strAux.append("</contexto>");

		return strAux.toString();
	}

	/**
	 * Recorre de forma apropiada la lista de contextos de esta clase, realizando
	 * todos los tratamientos comunes en los diferentes metodos donde se necesita
	 * recorrer esta lista. 
	 * 
	 * @param ejecutable Una clase que sabe que hacer con cada elemento de la lista de contextos 
	 * @param name Nombre del valor a buscar, null si no es necesario
	 * @param key Clave del valor a buscar si el tipo de valor es un Map, null si no es necesario
	 * @param index Indice del valor a buscar si el tipo de valor es una List, null si no es necesario
	 * @param value Valor a modificar, null si no es necesario
	 * @return Devuelve un Object a tratar por el metodo invocador segun corresponda
	 */
	private Object recorrerContextos(ContextoBlock ejecutable, String name, String key, int index, Object value)
	{
		Iterator it = contextoSesion.iterator();
		while (it.hasNext())
		{
			DynaBean element = (DynaBean) it.next();
			Object obj = null;
			try
			{
				obj = ejecutable.execDynaBean(element, name, key, index, value);
				return obj;
			}
			catch (IllegalArgumentException e)
			{}
		}
		throw new IllegalArgumentException(
			"tipoContexto:'" + getTipoContexto() + "', idContexto:'" + getIdContexto() + "', nombreAtributo:'" + name + "'");
	}

	/**
	 * 
	 * @serialData Only the serializable fields of the class are written.
	 *             No optional data written. 
	 */
	public void writeExternal(ObjectOutput out) throws IOException
	{
		super.writeExternal(out);
		//Tambien hay que serializar la lista de contextos para preservar la misma 
		// estructura, para ello se necesita serializar el tamaño de dicha lista
		if (contextoSesion == null)
		{
			out.writeInt(0);
			return;
		}
		out.writeInt(contextoSesion.size());
		Iterator it = contextoSesion.iterator();
		while (it.hasNext())
		{
			Object obj = it.next();
			out.writeObject(obj);
		}
	}

	/**
	 *
	 * @serialData No optional data is read.
	 */
	public void readExternal(ObjectInput is) throws IOException, ClassNotFoundException
	{
		super.readExternal(is);
		int numeroContextos = is.readInt();
		for (int i = 0; i < numeroContextos; i++)
		{
			Object obj = is.readObject();
			if (obj instanceof Q70ContextoGlobal)
			{
				Q70ContextoGlobal ctxGlobal = (Q70ContextoGlobal) obj;
				obj = (Q70ContextoGlobal) Q70ContextosEnMemoriaManejador.getContexto(ctxGlobal.getTipoContexto(), ctxGlobal.getIdContexto());
			}
			if (obj instanceof Q70ContextoSesionUsuario)
			{
				Q70ContextoSesionUsuario ctxSesionUsuario = (Q70ContextoSesionUsuario) obj;
				try
				{
					if (ctxSesionUsuario.getTipoContexto().equals(Q70SesionDatos.CTX_SESION_USUARIO))
					{
						obj = Q70SesionDatosCrearUsarios.crearContextoSesionUsuario(ctxSesionUsuario.getIdContexto(), null);
//						((Q70ContextoSesionUsuario)obj).decrementarContadorSesiones();
					}
					else
					{
						if (ctxSesionUsuario.getTipoContexto().equals(Q70SesionDatos.CTX_GRUPO_APLICACIONES))
						{
							obj = Q70SesionDatosCrearUsarios.crearContextoGrupoAplicacion(ctxSesionUsuario.getIdContexto(), null);
//							((Q70ContextoSesionUsuario)obj).decrementarContadorSesiones();
						}
						else
						{}
					}
				}
				catch (Q70PersistenciaMalInicializadaException e)
				{
					throw new IOException(e.getMessage());
				}
			}
			contextoSesion.add(obj);
		}
		List auxList = getContextoClassAncestors();
		((Q70ContextoEJIEDynaClass) getDynaClass()).setContextoAntecesoresClass(auxList);
	}
}
