/*
 * Creado el 23-ene-04
 *
 */
package es.ejie.frmk.presentacion.sesiondatos;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaClass;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.collections.CollectionUtils;

import es.ejie.frmk.Q70Factoria;
import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70TrazaInterface;
import es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.Q70ManejadorPersistenciaContextoEJIE;

/**
 * Esta clase sirve de base para los clases de Contextos que pretenden persistir. 
 * La funcionalidad que proporciona es llevar la lista de atributos modificados en un contexto y por tanto 
 * deben persistit y ademas, noticar cualquiera de estas modificaciones a la lista de observadores
 * de estos Contextos (estos observadores se definen via fichero de configuracion xml del contexto).
 * 
 * @version 1.0
 * Fecha: 23-ene-04
 */
public abstract class Q70ContextoPersistente extends Q70ContextoBasico {

	private transient Collection listeners = new HashSet(3);
	private transient Set listaModificados;

	/**
	 * Necesario porque es una clase Externalizable, debe tener un constructor sin argumentos
	 */
	public Q70ContextoPersistente() {
		super();
	}

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

	/**
	 * Construye un nuevo <code>Q70ContextoPersistente</code> a partir de una instancia de 
	 * <code>ManejadorPersistenciaContextoEJIE</code> asignadole un tipo de contexto y un identificativo de contexto.
	 *
	 * @param aDynaBean 
	 * @param aManejadorPersistencia
	 * @param aTipoContexto
	 * @param aIdContexto
	 */
	public Q70ContextoPersistente(
		DynaBean aDynaBean,
		Q70ManejadorPersistenciaContextoEJIE aManejadorPersistencia,
		String aTipoContexto,
		String aIdContexto) {
		super(aDynaBean, aManejadorPersistencia, aTipoContexto, aIdContexto);

		getManejadorPersistencia().doGetContexto();
		if (!getManejadorPersistencia().isMismoContexto()) {
			getManejadorPersistencia().doSaveContexto();
		}
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE#getListaModificados()
	 */
	public Set getListaModificados() {
		if (listaModificados == null) {
			DynaProperty[] propAux = ((Q70ContextoEJIEDynaClass) getContextoDynaClass()).getPropiedadesDePrimerNivel();
			listaModificados = Collections.synchronizedSet(new HashSet(propAux.length));
		}
		return listaModificados;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE#addContextoListener(es.ejie.frmk.presentacion.sesiondatos.Q70ContextoEJIEObservador)
	 */
	public void addContextoListener(Q70ContextoEJIEObservador aListener) {
		listeners.add(aListener);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE#removeContextoListener(es.ejie.frmk.presentacion.sesiondatos.Q70ContextoEJIEObservador)
	 */
	public void removeContextoListener(Q70ContextoEJIEObservador aListener) {
		listeners.remove(aListener);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.Q70ContextoBasico#notifyChanges(java.lang.String, java.lang.Object, java.util.List)
	 */
	protected void notifyChanges(String nombreCampoModificado, Object nuevoValorCampoModificado, List listaSinNotificar) {
		getListaModificados().add(nombreCampoModificado);

		if (listeners == null)
			return;

		Collection listaANotificar = new ArrayList(listeners.size());
		if (listaSinNotificar == null) {
			listaANotificar = listeners;
		} else {
			listaANotificar = CollectionUtils.subtract(listeners, listaSinNotificar);
		}
		if (listaANotificar != null) {
			Iterator it = listaANotificar.iterator();
			while (it.hasNext()) {
				Q70ContextoEJIEObservador observador = null;
				try {
					observador = (Q70ContextoEJIEObservador) it.next();
					observador.update(this, getTipoContexto(), getIdContexto(), nombreCampoModificado, nuevoValorCampoModificado);
				} catch (RuntimeException e) {
					Q70TrazaInterface traza = Q70Factoria.getTraza();
					if (traza.isTraceActive()) {
						traza.trace(ID_COMPONENTE, Q70TraceLevel.ERROR, "Observador ha dado error:" + observador + "..." + e.getMessage());
					}
				}
			}
		}
	}

	/**
	 * Los clases de Contextos que extienden esta clases SOLO serializan la informacion para identificar
	 * el contexto, concretamente, el tipo de contexto y el identificativo de contexto.
	 * 
	 * @serialData Only the serializable fields of the class are written.
	 *             No optional data written. 
	 */
	public void writeExternal(ObjectOutput out) throws IOException {
		trazaSerializable();
		out.writeObject(getTipoContexto());
		out.writeObject(getIdContexto());
	}

	/**
	 * Los clases de Contextos que extienden esta clases SOLO deserializan la informacion para identificar
	 * el contexto, concretamente, el tipo de contexto y el identificativo de contexto.
	 * 
	 * @serialData No optional data is read.
	 */
	public void readExternal(ObjectInput is) throws IOException, ClassNotFoundException {
		setTipoContexto((String) is.readObject());
		setIdContexto((String) is.readObject());
		trazaDeserializable();
	}
}
