package es.ejie.frmk.presentacion.sesiondatos.contexto.persistencia;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;

import es.ejie.frmk.presentacion.sesiondatos.utilidades.Q70ContextoUtilidades;
import es.ejie.frmk.presentacion.sesiondatos.utilidades.Q70DatosDeSqlCampo;

public class Q70PersistenciaGlobalDesdeBD extends Q70PersistenciaDesdeBD {

	private transient StringBuffer auxiliarSB;
	private static final String STR_SELECT = "select ";
	private static final String STR_INSERT = "insert into ";
	private static final String STR_UPDATE = "update ";
	private static final String STR_DELETE = "delete ";
	private static final String STR_FROM = " from ";
	private static final String STR_WHERE = " where ";
	private static final String STR_UPDATE_SET = " set ";
	private static final String STR_INSERT_VALUES = " values (";
	private static final String STR_INSERT_FIN = ")";
	private static final String STR_SEPARADOR = ", ";
	private static final String STR_IGUAL = "=";
	private static final String STR_AND = " and ";
	private static final String STR_INTERROGANTE = "?";

	private transient String strSelectSentence;
	private transient String strInsertSentence;
	private transient String strUpdateSentence;
	private transient String strDeleteSentence;
	private transient String strWhereCondiction;

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

	/**
	 * @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(Q70PersistenciaGlobalDesdeBD.MSG_FIN_LISTA_SENTENCIAS);

		int i = 1;
		if (!existeEnBaseDatos) {
			pstmt.setObject(i++, getContextoEJIEParent().getIdContexto());
		}
		Iterator it = getListaSqlCampos().iterator();
		while (it.hasNext()) {
			Q70DatosDeSqlCampo datosAux = (Q70DatosDeSqlCampo) it.next();
			setSqlField(pstmt, i++, datosAux);
		}
		if (existeEnBaseDatos) {
			pstmt.setObject(i++, getContextoEJIEParent().getIdContexto());
			it = getListaSqlCampos().iterator();
			while (it.hasNext()) {
				Q70DatosDeSqlCampo datosAux = (Q70DatosDeSqlCampo) it.next();
				if (datosAux.isKey()) {
					setSqlField(pstmt, i++, datosAux);
				}
			}
		}
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#doCompararDatos(java.sql.ResultSet)
	 */
	protected boolean doCompararDatos(ResultSet rdo) throws SQLException {
		Iterator it = getListaSqlCampos().iterator();
		while (it.hasNext()) {
			Q70DatosDeSqlCampo datosAux = (Q70DatosDeSqlCampo) it.next();
			//TODO Jgrey Utilizar ConvertUtils para mapear campos de sql a contexto.
			//TODO Jgrey Los objetos guardados en bd deben ser comparables por equals.
			Object objRdo = rdo.getObject(datosAux.getNombreSqlCampo());
			if (objRdo instanceof String) {
				objRdo = ((String) objRdo).trim();
			}
			if (!Q70ContextoUtilidades.compare(getContextoEJIEParent().get(datosAux.getNombreContextoEquivalente()), objRdo)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#doRecogerDatos(java.sql.ResultSet)
	 */
	protected boolean doRecogerDatos(ResultSet rdo) throws SQLException {
		HashMap mapaRdo = new HashMap(getListaSqlCampos().size());
		Iterator it = getListaSqlCampos().iterator();
		while (it.hasNext()) {
			Q70DatosDeSqlCampo datosAux = (Q70DatosDeSqlCampo) it.next();
			//TODO Jgrey: Utilizar ConvertUtils para mapear campos de sql a contexto.
			Object objRdo = rdo.getObject(datosAux.getNombreSqlCampo());
			if (objRdo instanceof String) {
				objRdo = ((String) objRdo).trim();
			}
			mapaRdo.put(datosAux, objRdo);
		}
		rdo.close();
		it = getListaSqlCampos().iterator();
		while (it.hasNext()) {
			Q70DatosDeSqlCampo datosAux = (Q70DatosDeSqlCampo) it.next();
			getContextoEJIEParent().set(datosAux.getNombreContextoEquivalente(), mapaRdo.get(datosAux));
		}
		return true;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.ContextoEJIEContraBD#doFindKey(java.sql.PreparedStatement, int, java.lang.String)
	 */
	protected void doSaveKey(PreparedStatement pstmt, int index) throws SQLException {
		doSelectKey(pstmt, index);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.ContextoEJIEContraBD#doDeleteKey(java.sql.PreparedStatement, int)
	 */
	protected void doDeleteKey(PreparedStatement pstmt, int index) throws SQLException {
		doSelectKey(pstmt, index);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#doSelectKey(java.sql.PreparedStatement)
	 */
	protected void doSelectKey(PreparedStatement pstmt, int index) throws SQLException {
		int i = 1;
		pstmt.setObject(i++, getContextoEJIEParent().getIdContexto());
		Iterator it = getListaSqlCampos().iterator();
		while (it.hasNext()) {
			Q70DatosDeSqlCampo datosAux = (Q70DatosDeSqlCampo) it.next();
			if (datosAux.isKey()) {
				setSqlField(pstmt, i++, datosAux);
			}
		}
	}

	private void setSqlField(PreparedStatement pstmt, int index, Q70DatosDeSqlCampo datosSql) throws SQLException {
		//TODO Jgrey: Utilizar ConvertUtils para mapear campos de contexto a sql.
		Object objAux = getContextoEJIEParent().get(datosSql.getNombreContextoEquivalente());
		pstmt.setObject(index, objAux);
	}

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

		if (strDeleteSentence != null) {
			setUltimaSenteciaSqlEjecutada(strDeleteSentence);
			trazaSenteciaEjecutable(strDeleteSentence);
			return strDeleteSentence;
		}

		auxiliarSB = new StringBuffer(100);
		auxiliarSB.append(STR_DELETE);
		auxiliarSB.append(STR_FROM);
		auxiliarSB.append(getSqlTabla());
		getWhereCondicion();

		strDeleteSentence = auxiliarSB.toString();
		setUltimaSenteciaSqlEjecutada(strDeleteSentence);
		trazaSenteciaEjecutable(strDeleteSentence);
		return strDeleteSentence;
	}

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

		if (strInsertSentence != null) {
			setUltimaSenteciaSqlEjecutada(strInsertSentence);
			trazaSenteciaEjecutable(strInsertSentence);
			return strInsertSentence;
		}

		auxiliarSB = new StringBuffer(100);
		auxiliarSB.append(STR_INSERT);
		auxiliarSB.append(getSqlTabla());
		auxiliarSB.append(STR_INSERT_VALUES);
		Iterator it = getListaSqlCampos().iterator();
		auxiliarSB.append(STR_INTERROGANTE);
		while (it.hasNext()) {
			it.next();
			auxiliarSB.append(STR_SEPARADOR);
			auxiliarSB.append(STR_INTERROGANTE);
		}
		auxiliarSB.append(STR_INSERT_FIN);

		strInsertSentence = auxiliarSB.toString();
		setUltimaSenteciaSqlEjecutada(strInsertSentence);
		trazaSenteciaEjecutable(strInsertSentence);
		return strInsertSentence;
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.ContextoEJIEContraBD#getFindSentence(int)
	 */
	protected String getFindSentence(int index) {
		return getSelectSentence(index);
	}

	/**
	 * @see es.ejie.frmk.presentacion.sesiondatos.utilidades.ContextoEJIEContraBD#getSelectSentence()
	 */
	protected String getSelectSentence(int index) {
		if (strSelectSentence != null) {
			setUltimaSenteciaSqlEjecutada(strSelectSentence);
			trazaSenteciaEjecutable(strSelectSentence);
			return strSelectSentence;
		}

		auxiliarSB = new StringBuffer(100);
		auxiliarSB.append(STR_SELECT);

		Iterator it = getListaSqlCampos().iterator();
		if (it.hasNext()) {
			auxiliarSB.append(((Q70DatosDeSqlCampo) it.next()).getNombreSqlCampo());
		}
		while (it.hasNext()) {
			auxiliarSB.append(STR_SEPARADOR);
			auxiliarSB.append(((Q70DatosDeSqlCampo) it.next()).getNombreSqlCampo());
		}

		auxiliarSB.append(STR_FROM);
		auxiliarSB.append(getSqlTabla());
		getWhereCondicion();
		strSelectSentence = auxiliarSB.toString();
		setUltimaSenteciaSqlEjecutada(strSelectSentence);
		trazaSenteciaEjecutable(strSelectSentence);
		return strSelectSentence;
	}

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

		if (strUpdateSentence != null) {
			setUltimaSenteciaSqlEjecutada(strUpdateSentence);
			trazaSenteciaEjecutable(strUpdateSentence);
			return strUpdateSentence;
		}

		auxiliarSB = new StringBuffer(100);
		auxiliarSB.append(STR_UPDATE);
		auxiliarSB.append(getSqlTabla());
		auxiliarSB.append(STR_UPDATE_SET);

		Iterator it = getListaSqlCampos().iterator();
		if (it.hasNext()) {
			auxiliarSB.append(((Q70DatosDeSqlCampo) it.next()).getNombreSqlCampo());
			auxiliarSB.append(STR_IGUAL);
			auxiliarSB.append(STR_INTERROGANTE);
		}
		while (it.hasNext()) {
			auxiliarSB.append(STR_SEPARADOR);
			auxiliarSB.append(((Q70DatosDeSqlCampo) it.next()).getNombreSqlCampo());
			auxiliarSB.append(STR_IGUAL);
			auxiliarSB.append(STR_INTERROGANTE);
		}

		getWhereCondicion();
		strUpdateSentence = auxiliarSB.toString();
		setUltimaSenteciaSqlEjecutada(strUpdateSentence);
		trazaSenteciaEjecutable(strUpdateSentence);
		return strUpdateSentence;
	}

	private void getWhereCondicion() {
		if (strWhereCondiction != null) {
			auxiliarSB.append(strWhereCondiction);
			return;
		}

		StringBuffer auxWhere = new StringBuffer(30);
		auxWhere.append(STR_WHERE);
		auxWhere.append(getSqlWhere());

		boolean esWhereVacia = true;
		if (!getSqlWhere().equals("")) {
			esWhereVacia = false;
			auxWhere.append(STR_AND);
		}
		auxWhere.append("ID=?");
		esWhereVacia = false;
		
		Iterator it = getListaSqlCampos().iterator();
		while (it.hasNext()) {
			Q70DatosDeSqlCampo datosAux = (Q70DatosDeSqlCampo) it.next();
			if (datosAux.isKey()) {
				if (!esWhereVacia) {
					auxWhere.append(STR_AND);
				}
				auxWhere.append(datosAux.getNombreSqlCampo());
				auxWhere.append(STR_IGUAL);
				auxWhere.append(STR_INTERROGANTE);
				esWhereVacia = false;
			}
		}

		strWhereCondiction = auxWhere.toString();
		auxiliarSB.append(strWhereCondiction);
	}

}
