package com.ejie.m62fb.dao.registroVPP;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.springframework.dao.support.DataAccessUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.ejie.m62fb.model.SolicitudReserva;
import com.ejie.m62fb.model.tipos.EstadoTramitacion;
import com.ejie.m62fb.utils.constants.AppConstantes;
import com.ejie.m62fb.utils.sql.BDUtils;
import com.ejie.m62fb.utils.sql.UtilsResulSet;
import com.ejie.x38.dto.JQGridManager;
import com.ejie.x38.dto.JQGridRequestDto;

/**
 * SolicitudReservaDaoImpl.
 * 
XXXX
 */
@Repository
@Transactional
public class SolicitudReservaDaoImpl implements SolicitudReservaDao {
	private JdbcTemplate jdbcTemplate;

	/*
	 * ROW_MAPPERS
	 */
	private final RowMapper<SolicitudReserva> rwMap = new RowMapper<SolicitudReserva>() {
		@Override
		public SolicitudReserva mapRow(ResultSet resultSet, int rowNum)
				throws SQLException {

			SolicitudReserva solicitudReserva = new SolicitudReserva();
			// Identificador Solicitud Reserva
			solicitudReserva.setIdM62r38t0(UtilsResulSet.getInteger(resultSet,
					"IDM62R38T0"));
			// Numero Expediente (folderNumber) Platea
			solicitudReserva.setNumExpedientePlatea(resultSet
					.getString("NUMEXPEDIENTEPLATEA"));
			// Identificador (folderId) Platea
			solicitudReserva.setIdExpedientePlatea(resultSet
					.getString("IDEXPEDIENTEPLATEA"));
			// Fecha Solicitud
			solicitudReserva.setFecSolicitud(resultSet
					.getTimestamp("FECSOLICITUD"));
			// Descripcion Entidad Solicitud
			solicitudReserva.setDesEntidadSolic(resultSet
					.getString("DESENTIDADSOLIC"));
			// Descripcion Departamento Solicitud
			solicitudReserva.setDesDptoSolic(resultSet
					.getString("DESDPTOSOLIC"));
			// Descripcion Interlocutor
			solicitudReserva.setDesInterlocutor(resultSet
					.getString("DESINTERLOCUTOR"));
			// Estado
			EstadoTramitacion estado = new EstadoTramitacion();
			estado.setCodTabla(resultSet.getString("CODESTADO"));
			estado.setDescripcionEs(resultSet.getString("DESCESTADOES"));
			estado.setDescripcionEu(resultSet.getString("DESCESTADOEU"));
			solicitudReserva.setEstado(estado);
			// Numero de viviendas
			solicitudReserva.setNumViviendas(UtilsResulSet.getLong(resultSet,
					"NUMVIVIENDAS"));
			// Descripcion Direccion
			solicitudReserva.setDesDireccion(resultSet
					.getString("DESDIRECCION"));
			// Direccion Email
			solicitudReserva.setDirEmail(resultSet.getString("DIREMAIL"));
			// Numero Telefono
			solicitudReserva.setNumTelefono(resultSet.getString("NUMTELEFONO"));

			return solicitudReserva;
		}
	};

	/**
	 * Method use to set the datasource.
	 * 
	 * @param dataSource
	 *            DataSource
	 * @return
	 */
	@Resource
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}

	/*
	 * OPERACIONES CRUD
	 */

	/**
	 * Inserts a single row in the SolicitudReserva table.
	 * 
	 * @param solicitudReserva
	 *            SolicitudReserva
	 * @return SolicitudReserva
	 */
	@Override
	public SolicitudReserva add(final SolicitudReserva solicitudReserva) {

		KeyHolder keyHolder = new GeneratedKeyHolder();
		this.jdbcTemplate.update(new PreparedStatementCreator() {
			@Override
			public PreparedStatement createPreparedStatement(
					Connection connection) throws SQLException {
				// Sentencia SQL que realiza la INSERT y array con ids que son
				// primary jey
				PreparedStatement ps = connection.prepareStatement(
						SolicitudReservaDaoSQL.SQL_INSERT,
						new String[] { "ID_M62R38T0" });

				// DesEntidadSolic
				ps.setString(1, solicitudReserva.getDesEntidadSolic());
				// DesDptoSolic
				ps.setString(2, solicitudReserva.getDesDptoSolic());
				// DesDireccion
				ps.setString(3, solicitudReserva.getDesDireccion());

				// DesInterlocutor
				ps.setString(4, solicitudReserva.getDesInterlocutor());
				// NumTelefono
				ps.setString(5, solicitudReserva.getNumTelefono());
				// DirEmail
				ps.setString(6, solicitudReserva.getDirEmail());

				// IdExpedientePlatea
				ps.setString(7, solicitudReserva.getIdExpedientePlatea());
				// EstadoTramitacion
				ps.setString(8, EstadoTramitacion.CREADO);

				// AbstractM62FBModel (UsuarioPlatea)
				ps.setString(9, AppConstantes.USUARIO_APP_PLATEA);

				return ps;
			}
		}, keyHolder);

		// Obtener Pk generada por el trigger
		solicitudReserva.setIdM62r38t0(Integer.valueOf(keyHolder.getKeys()
				.get("ID_M62R38T0").toString()));

		return solicitudReserva;
	}

	/**
	 * Actualiza el estado de la solicitud a "APERTURADO(2)" e informa el
	 * numExpedientePlatea introducido en la apertura
	 * 
	 * @param solicitudReserva
	 *            SolicitudReserva(idExpedientePlatea(folderId),
	 *            numExpedientePlatea(folderNumber))
	 */
	@Override
	public void updateEstadoApertura(SolicitudReserva solicitudReserva) {
		String query = SolicitudReservaDaoSQL.SQL_UPDATE_ESTADO_NUM_EXP_PLATEA;

		// Preparar Parametros
		List<Object> params = new ArrayList<Object>();

		// EstadoTramitacion
		params.add(EstadoTramitacion.APERTURADO);

		// NumExpedientePlatea(folderNumber)
		params.add(solicitudReserva.getNumExpedientePlatea());

		// AbstractM62FBModel (UsuarioPlatea)
		params.add(AppConstantes.USUARIO_APP_PLATEA);

		// IdExpedientePlatea(folderId)
		params.add(solicitudReserva.getIdExpedientePlatea());

		// Realizar Update
		this.jdbcTemplate.update(query, params.toArray());
	}

	/**
	 * Actualiza el estado de la solicitud a "NOTIFICADO(3)"
	 * 
	 * @param solicitudReserva
	 *            SolicitudReserva(idExpedientePlatea(folderId))
	 */
	@Override
	public void updateEstadoNotificacion(SolicitudReserva solicitudReserva) {
		String query = SolicitudReservaDaoSQL.SQL_UPDATE_ESTADO;

		// Preparar Parametros
		List<Object> params = new ArrayList<Object>();

		// EstadoTramitacion
		params.add(EstadoTramitacion.NOTIFICADO);

		// AbstractM62FBModel (UsuarioPlatea)
		params.add(AppConstantes.USUARIO_APP_PLATEA);

		// IdExpedientePlatea(folderId)
		params.add(solicitudReserva.getIdExpedientePlatea());

		// Realizar Update
		this.jdbcTemplate.update(query, params.toArray());
	}

	/**
	 * Finds a single row in the SolicitudReserva table.
	 * 
	 * @param solicitudReserva
	 *            SolicitudReserva
	 * @return SolicitudReserva
	 */
	@Override
	@Transactional(readOnly = true)
	public SolicitudReserva find(SolicitudReserva solicitudReserva) {
		String query = SolicitudReservaDaoSQL.SQL_FIND;

		List<SolicitudReserva> solicitudesreservaList = this.jdbcTemplate
				.query(query, this.rwMap, solicitudReserva.getIdM62r38t0());
		return DataAccessUtils.uniqueResult(solicitudesreservaList);
	}

	/**
	 * Finds a list of rows in the SolicitudReserva table.
	 * 
	 * @param solicitudReserva
	 *            SolicitudReserva
	 * @param jqGridRequestDto
	 *            JQGridRequestDto
	 * @return List<SolicitudReserva>
	 */
	@Override
	@Transactional(readOnly = true)
	public List<SolicitudReserva> findAll(SolicitudReserva solicitudesreserva,
			JQGridRequestDto jqGridRequestDto) {
		StringBuilder query = new StringBuilder(
				SolicitudReservaDaoSQL.SQL_FIND_ALL);

		// Where clause & Params
		Map<String, ?> mapaWhere = this.getWhereMap(solicitudesreserva);
		StringBuilder where = new StringBuilder(
				SolicitudReservaDaoSQL.SQL_WHERE_ALL);
		where.append(mapaWhere.get("query"));
		query.append(where);

		List<?> params = (List<?>) mapaWhere.get("params");

		if (jqGridRequestDto != null) {
			query = JQGridManager.getPaginationQuery(jqGridRequestDto, query);
		}

		return this.jdbcTemplate.query(query.toString(), this.rwMap,
				params.toArray());
	}

	/**
	 * Finds rows in the SolicitudReserva table using like.
	 * 
	 * @param solicitudReserva
	 *            SolicitudReserva
	 * @param jqGridRequestDto
	 *            JQGridRequestDto
	 * @param startsWith
	 *            Boolean
	 * @return List<SolicitudReserva>
	 */
	@Override
	@Transactional(readOnly = true)
	public List<SolicitudReserva> findAllLike(
			SolicitudReserva solicitudReserva,
			JQGridRequestDto jqGridRequestDto, Boolean startsWith) {
		StringBuilder query = new StringBuilder(
				SolicitudReservaDaoSQL.SQL_FIND_ALL);

		// Where clause & Params
		Map<String, ?> mapaWhere = this.getWhereLikeMap(solicitudReserva,
				startsWith);

		StringBuilder where = new StringBuilder(
				SolicitudReservaDaoSQL.SQL_WHERE_ALL);
		where.append(mapaWhere.get("query"));
		query.append(where);

		List<?> params = (List<?>) mapaWhere.get("params");

		if (jqGridRequestDto != null) {
			query = JQGridManager.getPaginationQuery(jqGridRequestDto, query);
		}

		return this.jdbcTemplate.query(query.toString(), this.rwMap,
				params.toArray());
	}

	/*
	 * OPERACIONES RUP_TABLE
	 */

	/**
	 * Counts rows in the SolicitudReserva table.
	 * 
	 * @param solicitudReserva
	 *            SolicitudReserva
	 * @return Long
	 */
	@Override
	@Transactional(readOnly = true)
	public Long findAllCount(SolicitudReserva solicitudReserva) {
		StringBuilder query = new StringBuilder(
				SolicitudReservaDaoSQL.SQL_FIND_ALL_COUNT);

		// Where clause & Params
		Map<String, ?> mapaWhere = this.getWhereMap(solicitudReserva);
		StringBuilder where = new StringBuilder(
				SolicitudReservaDaoSQL.SQL_WHERE_ALL);
		where.append(mapaWhere.get("query"));
		query.append(where);

		List<?> params = (List<?>) mapaWhere.get("params");

		return this.jdbcTemplate.queryForLong(query.toString(),
				params.toArray());
	}

	/**
	 * Counts rows in the SolicitudReserva table using like.
	 * 
	 * @param solicitudReserva
	 *            SolicitudReserva
	 * @param startsWith
	 *            Boolean
	 * @return Long
	 */
	@Override
	@Transactional(readOnly = true)
	public Long findAllLikeCount(SolicitudReserva solicitudReserva,
			Boolean startsWith) {
		StringBuilder query = new StringBuilder(
				SolicitudReservaDaoSQL.SQL_FIND_ALL_COUNT);

		// Where clause & Params
		Map<String, ?> mapaWhere = this.getWhereLikeMap(solicitudReserva,
				startsWith);
		StringBuilder where = new StringBuilder(
				SolicitudReservaDaoSQL.SQL_WHERE_ALL);
		where.append(mapaWhere.get("query"));
		query.append(where);

		List<?> params = (List<?>) mapaWhere.get("params");

		return this.jdbcTemplate.queryForLong(query.toString(),
				params.toArray());
	}

	/*
	 * MÉTODOS PRIVADOS
	 */

	/**
	 * Returns a map with the needed value to create the conditions to filter by
	 * the SolicitudReserva entity
	 * 
	 * @param solicitudReserva
	 *            SolicitudReserva Bean with the criteria values to filter by.
	 * @return Map created with two keys key query stores the sql query syntax
	 *         key params stores the parameter values to be used in the
	 *         condition sentence.
	 */
	// CHECKSTYLE:OFF CyclomaticComplexity - Generación de código de UDA
	private Map<String, ?> getWhereMap(SolicitudReserva solicitudReserva) {

		StringBuilder where = new StringBuilder(
				SolicitudReservaDaoSQL.STRING_BUILDER_INIT);
		List<Object> params = new ArrayList<Object>();

		if (solicitudReserva != null) {
			// Identificador Solicitud Reserva
			if (solicitudReserva.getIdM62r38t0() != null) {
				BDUtils.crearFiltroIgual(where, params,
						"SOLICRESER.ID_M62R38T0",
						solicitudReserva.getIdM62r38t0());
			}
			// Numero Expediente (folderNumber) Platea
			if (solicitudReserva.getNumExpedientePlatea() != null) {
				BDUtils.crearFiltroIgual(where, params,
						"SOLICRESER.NUM_EXPEDIENTE_PLATEA",
						solicitudReserva.getNumExpedientePlatea());
			}
			// Identificador (folderId) Platea
			if (solicitudReserva.getIdExpedientePlatea() != null) {
				BDUtils.crearFiltroIgual(where, params,
						"SOLICRESER.ID_EXPEDIENTE_PLATEA",
						solicitudReserva.getIdExpedientePlatea());
			}
			// Fecha Solicitud
			if (solicitudReserva.getFecSolicitud() != null) {
				BDUtils.crearFiltroIgual(where, params,
						"SOLICRESER.FEC_SOLICITUD",
						solicitudReserva.getFecSolicitud());
			}
			// Descripcion Entidad Solicitud
			if (solicitudReserva.getDesEntidadSolic() != null) {
				BDUtils.crearFiltroIgual(where, params,
						"SOLICRESER.DES_ENTIDAD_SOLIC",
						solicitudReserva.getDesEntidadSolic());
			}
			// Descripcion Departamento Solicitud
			if (solicitudReserva.getDesDptoSolic() != null) {
				BDUtils.crearFiltroIgual(where, params,
						"SOLICRESER.DES_DPTO_SOLIC",
						solicitudReserva.getDesDptoSolic());
			}
			// Descripcion Interlocutor
			if (solicitudReserva.getDesInterlocutor() != null) {
				BDUtils.crearFiltroIgual(where, params,
						"SOLICRESER.DES_INTERLOCUTOR",
						solicitudReserva.getDesInterlocutor());
			}
			// Estado
			if (solicitudReserva.getEstado() != null
					&& solicitudReserva.getEstado().getCodTabla() != null) {
				BDUtils.crearFiltroIgual(where, params,
						"SOLICRESER.COD_ESTADO", solicitudReserva.getEstado()
								.getCodTabla());
			}
			// Numero de viviendas
			if (solicitudReserva.getNumViviendas() != null) {
				BDUtils.crearFiltroIgual(where, params,
						"SOLICRESER.NUM_VIVIENDAS",
						solicitudReserva.getNumViviendas());
			}
			// Descripcion Direccion
			if (solicitudReserva.getDesDireccion() != null) {
				BDUtils.crearFiltroIgual(where, params,
						"SOLICRESER.DES_DIRECCION",
						solicitudReserva.getDesDireccion());
			}
		}

		Map<String, Object> mapWhere = new HashMap<String, Object>();
		mapWhere.put("query", where);
		mapWhere.put("params", params);

		return mapWhere;
	}

	// CHECKSTYLE:ON CyclomaticComplexity - Generación de código de UDA

	/**
	 * Returns a map with the needed value to create the conditions to filter by
	 * the SolicitudReserva entity
	 * 
	 * @param solicitudReserva
	 *            SolicitudReserva Bean with the criteria values to filter by.
	 * @param startsWith
	 *            Boolean
	 * @return Map created with two keys key query stores the sql query syntax
	 *         key params stores the parameter values to be used in the
	 *         condition sentence.
	 */
	// CHECKSTYLE:OFF CyclomaticComplexity - Generación de código de UDA
	private Map<String, Object> getWhereLikeMap(
			SolicitudReserva solicitudReserva, Boolean startsWith) {

		StringBuilder where = new StringBuilder(
				SolicitudReservaDaoSQL.STRING_BUILDER_INIT);
		List<Object> params = new ArrayList<Object>();

		if (solicitudReserva != null) {
			// Identificador Solicitud Reserva
			if (solicitudReserva.getIdM62r38t0() != null) {
				BDUtils.crearFiltroLike(where, params,
						"SOLICRESER.NUM_VIVIENDA", solicitudReserva
								.getIdM62r38t0().toString(), startsWith);
			}
			// Numero Expediente (folderNumber) Platea
			if (solicitudReserva.getNumExpedientePlatea() != null) {
				BDUtils.crearFiltroLike(where, params,
						"SOLICRESER.NUM_EXPEDIENTE_PLATEA",
						solicitudReserva.getNumExpedientePlatea(), startsWith);
			}
			// Identificador (folderId) Platea
			if (solicitudReserva.getIdExpedientePlatea() != null) {
				BDUtils.crearFiltroLike(where, params,
						"SOLICRESER.ID_EXPEDIENTE_PLATEA",
						solicitudReserva.getIdExpedientePlatea(), startsWith);
			}
			// Fecha Solicitud
			if (solicitudReserva.getFecSolicitud() != null) {
				BDUtils.crearFiltroLike(where, params,
						"SOLICRESER.FEC_SOLICITUD", solicitudReserva
								.getFecSolicitud().toString(), startsWith);
			}

			// Fecha Solicitud Desde
			if (solicitudReserva.getFecSolicitudDesde() != null) {
				BDUtils.crearFiltroDesde(where, params,
						"SOLICRESER.FEC_SOLICITUD",
						solicitudReserva.getFecSolicitudDesde());
			}

			// Fecha Solicitud Hasta
			if (solicitudReserva.getFecSolicitudHasta() != null) {
				BDUtils.crearFiltroHasta(where, params,
						"SOLICRESER.FEC_SOLICITUD",
						solicitudReserva.getFecSolicitudHasta());
			}

			// Descripcion Entidad Solicitud
			if (solicitudReserva.getDesEntidadSolic() != null) {
				BDUtils.crearFiltroLike(where, params,
						"SOLICRESER.DES_ENTIDAD_SOLIC",
						solicitudReserva.getDesEntidadSolic(), startsWith);
			}
			// Descripcion Departamento Solicitud
			if (solicitudReserva.getDesDptoSolic() != null) {
				BDUtils.crearFiltroLike(where, params,
						"SOLICRESER.DES_DPTO_SOLIC",
						solicitudReserva.getDesDptoSolic(), startsWith);
			}
			// Descripcion Interlocutor
			if (solicitudReserva.getDesInterlocutor() != null) {
				BDUtils.crearFiltroLike(where, params,
						"SOLICRESER.DES_INTERLOCUTOR",
						solicitudReserva.getDesInterlocutor(), startsWith);
			}
			// Estado
			if (solicitudReserva.getEstado() != null
					&& solicitudReserva.getEstado().getCodTabla() != null) {
				BDUtils.crearFiltroLike(where, params, "SOLICRESER.COD_ESTADO",
						solicitudReserva.getEstado().getCodTabla(), startsWith);
			}
			// Numero de viviendas
			if (solicitudReserva.getNumViviendas() != null) {
				BDUtils.crearFiltroLike(where, params,
						"SOLICRESER.NUM_VIVIENDAS", solicitudReserva
								.getNumViviendas().toString(), startsWith);
			}
			// Descripcion Direccion
			if (solicitudReserva.getDesDireccion() != null) {
				BDUtils.crearFiltroLike(where, params,
						"SOLICRESER.DES_DIRECCION",
						solicitudReserva.getDesDireccion(), startsWith);
			}
		}

		Map<String, Object> mapWhere = new HashMap<String, Object>();
		mapWhere.put("query", where);
		mapWhere.put("params", params);

		return mapWhere;
	}

	// CHECKSTYLE:ON CyclomaticComplexity - Generación de código de UDA
}