/*
 * Creado el 20-ene-04
 *
 * 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.contexto.persistencia;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.collections.CollectionUtils;

import es.ejie.frmk.Q70Factoria;
import es.ejie.frmk.control.excepciones.Q70FrameworkException;
import es.ejie.frmk.control.excepciones.Q70GestorDeExcepcionesServidor;
import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70TrazaInterface;
import es.ejie.frmk.infraestructura.utilidades.general.Q70ObjectInputStream;
import es.ejie.frmk.presentacion.sesiondatos.Q70ContextoEJIEDynaClass;
import es.ejie.frmk.presentacion.sesiondatos.utilidades.Q70ContextoUtilidades;

/**
 * @version 1.0
 * Fecha: 20-ene-04
 */
public class Q70PersistenciaDesdeBDMultifila extends Q70PersistenciaBloqueandoRegistrosDesdeBD
{

	private static final String ID_COMPONENTE = "PERSISTENCIA_DESDE_BD_MULTIFILA";
	private transient String atributoAModificar;

	private static final String SQL_TIPO_CONTEXTO = "TIPO_CTX";
	private static final String SQL_ID_CONTEXTO = "ID_CTX";
	private static final String SQL_NOMBRE_ATRIBUTO = "ATRIBUTO_CTX";
	private static final String SQL_DATOS_ATRIBUTO = "DATOS_CTX";

	/**
	 * 
	 */
	public Q70PersistenciaDesdeBDMultifila(Object datos) throws Q70PersistenciaMalInicializadaException
	{
		super(datos);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.ManejadorPersistenciaContextoEJIE#isContextoCambiado()
	 */
	public boolean isMismoContexto()
	{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** INICIO isMismoContexto() *****************************");
		}

		if (getManejadorPersistencia() == null)
		{
			if (getContextoEJIEParent().getListaModificados() == null || getContextoEJIEParent().getListaModificados().size() == 0)
			{
				if (traza.isTraceActive())
				{
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** FIN    isMismoContexto():true *****************************");
				}
				return true;
			}
			else
			{
				if (traza.isTraceActive())
				{
					traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** FIN    isMismoContexto():false *****************************");
				}
				return false;
			}
		}
		boolean rdo = getManejadorPersistencia().isMismoContexto();

		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** FIN    isMismoContexto():" + rdo + " *****************************");
		}
		return rdo;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia.ManejadorPersistenciaContextoEJIE#doSaveContexto(java.lang.String)
	 */
	public void doSaveContexto()
	{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** INICIO doSaveContexto() *****************************");
		}

		if (getContextoEJIEParent().getListaModificados() == null || getContextoEJIEParent().getListaModificados().size() == 0)
		{
			if (traza.isTraceActive())
			{
				traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** FIN    doSaveContexto() *****************************");
			}
			return;
		}

		try
		{
			doSaveSincronizado();
		}
		catch (RuntimeException e)
		{
			Q70GestorDeExcepcionesServidor.getSingleton().recogerThrowable(new Q70FrameworkException(ID_COMPONENTE,this.getClass().toString(),"doSaveContexto","Se ha producido un error al salvar el contexto",e));
		}

		if (traza.isTraceActive())
		{
			traza.trace(ID_COMPONENTE, Q70TraceLevel.DEBUG, "*** FIN    doSaveContexto() *****************************");
		}
	}
	private synchronized void doSaveSincronizado()
	{
		Iterator it = getContextoEJIEParent().getListaModificados().iterator();
		while (it.hasNext())
		{
			atributoAModificar = (String) it.next();
			super.doSaveContexto();
			atributoAModificar = null;
		}
		getContextoEJIEParent().getListaModificados().clear();
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#doGuardarDatos(java.sql.PreparedStatement, boolean)
	 */
	protected void doGuardarDatos(PreparedStatement pstmt, int index, boolean existeEnBaseDatos) throws SQLException
	{
		if (index != 0)
			throw new ArrayIndexOutOfBoundsException(Q70PersistenciaDesdeBD.MSG_FIN_LISTA_SENTENCIAS);

		ByteArrayOutputStream byteArrayO = new ByteArrayOutputStream(1024);
		try
		{
			ObjectOutputStream so = new ObjectOutputStream(byteArrayO);
			so.writeObject(getContextoEJIEParent().get(atributoAModificar));
			so.flush();
			so.close();
		}
		catch (IOException e)
		{
			trazaExcepciones(e, "Error en doGuardarDatos() ", null);
		}
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (traza.isTraceActive())
		{
			traza.trace(
				ID_COMPONENTE,
				Q70TraceLevel.DEBUG,
				"doGuardarDatos() espacio ocupado por la serializacion de " + atributoAModificar + ": " + byteArrayO.toByteArray().length);
		}
		pstmt.setString(1, getContextoEJIEParent().getTipoContexto());
		pstmt.setString(2, getContextoEJIEParent().getIdContexto());
		pstmt.setString(3, atributoAModificar);
		pstmt.setBytes(4, byteArrayO.toByteArray());
		if (existeEnBaseDatos)
		{
			pstmt.setString(5, getContextoEJIEParent().getTipoContexto());
			pstmt.setString(6, getContextoEJIEParent().getIdContexto());
			pstmt.setString(7, atributoAModificar);
		}
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#doCompararDatos(java.sql.ResultSet)
	 */
	protected boolean doCompararDatos(ResultSet rdo) throws SQLException
	{
		do
		{
			try
			{
				Q70ObjectInputStream si = new Q70ObjectInputStream(rdo.getBinaryStream(SQL_DATOS_ATRIBUTO));
				if (!Q70ContextoUtilidades.compare(getContextoEJIEParent().get(rdo.getString(SQL_NOMBRE_ATRIBUTO).trim()), si.readObject()))
				{
					return false;
				}
			}
			catch (IllegalArgumentException e)
			{
				trazaExcepcionesNivel(e, "El atributo de bbdd no existe en xml del contexto(metodo doCompararDatos()) ", rdo.getString(SQL_NOMBRE_ATRIBUTO), Q70TraceLevel.WARN);
			}
			catch (NullPointerException e)
			{
				trazaExcepciones(e, "Error en doCompararDatos() ", rdo.getString(SQL_NOMBRE_ATRIBUTO));
			}
			catch (ConversionException e)
			{
				trazaExcepciones(e, "Error en doCompararDatos() ", rdo.getString(SQL_NOMBRE_ATRIBUTO));
			}
			catch (IOException e)
			{
				trazaExcepciones(e, "Error en doCompararDatos() ", null);
			}
			catch (ClassNotFoundException e)
			{
				trazaExcepciones(e, "Error en doCompararDatos() ", null);
			}
		}
		while (rdo.next());

		return true;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#doRecogerDatos(java.sql.ResultSet)
	 */
	protected boolean doRecogerDatos(ResultSet rdo) throws SQLException
	{
		pasarPropiedadesAListaModificados();
		ArrayList listaSeleccionados = new ArrayList(getContextoEJIEParent().getListaModificados().size());
		do
		{
			try
			{
				Q70ObjectInputStream si = new Q70ObjectInputStream(rdo.getBinaryStream(SQL_DATOS_ATRIBUTO));
				getContextoEJIEParent().set(rdo.getString(SQL_NOMBRE_ATRIBUTO).trim(), si.readObject());
				listaSeleccionados.add(rdo.getString(SQL_NOMBRE_ATRIBUTO).trim());

			}
			catch (IllegalArgumentException e)
			{
				trazaExcepcionesNivel(e, "El atributo de bbdd no existe en xml del contexto(metodo doRecogerDatos()) ", rdo.getString(SQL_NOMBRE_ATRIBUTO), Q70TraceLevel.WARN);
			}
			catch (NullPointerException e)
			{
				trazaExcepciones(e, "Error en doRecogerDatos() ", rdo.getString(SQL_NOMBRE_ATRIBUTO));
			}
			catch (ConversionException e)
			{
				trazaExcepciones(e, "Error en doRecogerDatos() ", rdo.getString(SQL_NOMBRE_ATRIBUTO));
			}
			catch (IOException e)
			{
				trazaExcepciones(e, "Error en doRecogerDatos() ", null);
			}
			catch (ClassNotFoundException e)
			{
				trazaExcepciones(e, "Error en doRecogerDatos() ", null);
			}
		}
		while (rdo.next());

		Collection resta = CollectionUtils.subtract(getContextoEJIEParent().getListaModificados(), listaSeleccionados);
		getContextoEJIEParent().getListaModificados().clear();
		getContextoEJIEParent().getListaModificados().addAll(resta);
		return true;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#doSelectKey(java.sql.PreparedStatement)
	 */
	protected void doSelectKey(PreparedStatement pstmt, int index) throws SQLException
	{
		DynaProperty[] listaPropiedades = ((Q70ContextoEJIEDynaClass) getContextoEJIEParent().getDynaClass()).getPropiedadesDePrimerNivel();
		if (index >= listaPropiedades.length)
			throw new ArrayIndexOutOfBoundsException(Q70PersistenciaDesdeBD.MSG_FIN_LISTA_SENTENCIAS);

		pstmt.setString(1, getContextoEJIEParent().getTipoContexto());
		pstmt.setString(2, getContextoEJIEParent().getIdContexto());
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#doSaveKey(java.sql.PreparedStatement)
	 */
	protected void doSaveKey(PreparedStatement pstmt, int index) throws SQLException
	{
		if (index != 0)
			throw new ArrayIndexOutOfBoundsException(Q70PersistenciaDesdeBD.MSG_FIN_LISTA_SENTENCIAS);

		pstmt.setString(1, getContextoEJIEParent().getTipoContexto());
		pstmt.setString(2, getContextoEJIEParent().getIdContexto());
		pstmt.setString(3, atributoAModificar);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.ContextoEJIEContraBD#doDeleteKey(java.sql.PreparedStatement, int)
	 */
	protected void doDeleteKey(PreparedStatement pstmt, int index) throws SQLException
	{
		DynaProperty[] listaPropiedades = ((Q70ContextoEJIEDynaClass) getContextoEJIEParent().getDynaClass()).getPropiedadesDePrimerNivel();
		if (index >= listaPropiedades.length)
			throw new ArrayIndexOutOfBoundsException(Q70PersistenciaDesdeBD.MSG_FIN_LISTA_SENTENCIAS);

		pstmt.setString(1, getContextoEJIEParent().getTipoContexto());
		pstmt.setString(2, getContextoEJIEParent().getIdContexto());
		pstmt.setString(3, listaPropiedades[index].getName());
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#getFindSentence()
	 */
	protected String getFindSentence(int index)
	{
		if (isArrayIndexOutOfBoundsException(index))
			throw new ArrayIndexOutOfBoundsException(Q70PersistenciaDesdeBD.MSG_FIN_LISTA_SENTENCIAS);

		String strSentence =
			"select "
				+ SQL_TIPO_CONTEXTO
				+ ", "
				+ SQL_ID_CONTEXTO
				+ ", "
				+ SQL_NOMBRE_ATRIBUTO
				+ ", "
				+ SQL_DATOS_ATRIBUTO
				+ " from "
				+ getSqlTabla()
				+ " where "
				+ SQL_TIPO_CONTEXTO
				+ "=? and "
				+ SQL_ID_CONTEXTO
				+ "=? and "
				+ SQL_NOMBRE_ATRIBUTO
				+ "=?";
		setUltimaSenteciaSqlEjecutada(strSentence);
		trazaSenteciaEjecutable(strSentence);
		return strSentence;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#getSelectSentence()
	 */
	protected String getSelectSentence(int index)
	{
		if (isArrayIndexOutOfBoundsException(index))
			throw new ArrayIndexOutOfBoundsException(Q70PersistenciaDesdeBD.MSG_FIN_LISTA_SENTENCIAS);

		String strSentence =
			"select "
				+ SQL_TIPO_CONTEXTO
				+ ", "
				+ SQL_ID_CONTEXTO
				+ ", "
				+ SQL_NOMBRE_ATRIBUTO
				+ ", "
				+ SQL_DATOS_ATRIBUTO
				+ " from "
				+ getSqlTabla()
				+ " where "
				+ SQL_TIPO_CONTEXTO
				+ "=? and "
				+ SQL_ID_CONTEXTO
				+ "=?";
		setUltimaSenteciaSqlEjecutada(strSentence);
		trazaSenteciaEjecutable(strSentence);
		return strSentence;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#getDeleteSentence()
	 */
	protected String getDeleteSentence(int index)
	{
		if (index != 0)
			throw new ArrayIndexOutOfBoundsException(Q70PersistenciaDesdeBD.MSG_FIN_LISTA_SENTENCIAS);

		String strSentence = "delete from " + getSqlTabla() + " where " + SQL_TIPO_CONTEXTO + "=? and " + SQL_ID_CONTEXTO + "=?";
		trazaSenteciaEjecutable(strSentence);
		return strSentence;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#getInsertSentence()
	 */
	protected String getInsertSentence(int index)
	{
		if (index != 0)
			throw new ArrayIndexOutOfBoundsException(Q70PersistenciaDesdeBD.MSG_FIN_LISTA_SENTENCIAS);

		String strSentence = "insert into " + getSqlTabla() + " values (?,?,?,?)";
		setUltimaSenteciaSqlEjecutada(strSentence);
		trazaSenteciaEjecutable(strSentence);
		return strSentence;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#getUpdateSentence()
	 */
	protected String getUpdateSentence(int index)
	{
		if (index != 0)
			throw new ArrayIndexOutOfBoundsException(Q70PersistenciaDesdeBD.MSG_FIN_LISTA_SENTENCIAS);

		String strSentence =
			"update "
				+ getSqlTabla()
				+ " set "
				+ SQL_TIPO_CONTEXTO
				+ "=?, "
				+ SQL_ID_CONTEXTO
				+ "=?, "
				+ SQL_NOMBRE_ATRIBUTO
				+ "=?, "
				+ SQL_DATOS_ATRIBUTO
				+ "=? where "
				+ SQL_TIPO_CONTEXTO
				+ "=? and "
				+ SQL_ID_CONTEXTO
				+ "=? and "
				+ SQL_NOMBRE_ATRIBUTO
				+ "=?";
		setUltimaSenteciaSqlEjecutada(strSentence);
		trazaSenteciaEjecutable(strSentence);
		return strSentence;
	}

	private boolean isArrayIndexOutOfBoundsException(int index)
	{
		DynaProperty[] listaPropiedades = ((Q70ContextoEJIEDynaClass) getContextoEJIEParent().getDynaClass()).getPropiedadesDePrimerNivel();
		if (index >= listaPropiedades.length)
			return true;

		return false;
	}

	protected void setAtributoAModificar(String atributo) {
		atributoAModificar = atributo;
	}

	protected String getSelectForUpdateSentence(int i) {
		return getSelectSentence(-1) + " and " + SQL_NOMBRE_ATRIBUTO 
		+ " in (" + doObtenerParametrosDeListaModificados() + ") for update";
	}

	protected void doSelectForUpdateKey(PreparedStatement pstmt) throws SQLException {
		pstmt.setString(1, getContextoEJIEParent().getTipoContexto());
		pstmt.setString(2, getContextoEJIEParent().getIdContexto());
	}
}
