package com.ejie.m62fb.dao.registroVPP;

import java.math.BigDecimal;
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.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.ejie.m62fb.utils.constants.IberErrorsMsgConstants;
import com.ejie.m62fb.utils.error.UFException;
import com.ejie.m62fb.dao.ComboP28Dao;
import com.ejie.m62fb.dao.SQLGenericas;
import com.ejie.m62fb.dao.registroVPP.plsql.M62FuncionesPLSQL;
import com.ejie.m62fb.model.Elemento;
import com.ejie.m62fb.model.InformacionSuelo;
import com.ejie.m62fb.model.RegistroPropiedad;
import com.ejie.m62fb.model.Vivienda;
import com.ejie.m62fb.model.tipos.TipoElemento;
import com.ejie.m62fb.model.tipos.TipoSiNo;
import com.ejie.m62fb.model.tipos.TipoVinculacion;
import com.ejie.m62fb.utils.sql.BDUtils;
import com.ejie.m62fb.utils.sql.Utilidades;
import com.ejie.m62fb.utils.sql.UtilsResulSet;
import com.ejie.t17i.dao.PaisDao;
import com.ejie.x38.dao.RowNumResultSetExtractor;
import com.ejie.x38.dto.JQGridManager;
import com.ejie.x38.dto.JQGridRequestDto;
import com.ejie.x38.dto.TableRowDto;

/**
 * ElementosDaoImpl
 * 
XXXX
 */

@Repository
@Transactional
public class ElementosDaoImpl implements ElementosDao {
	protected static final Elemento UtilsResultSet = null;

	private JdbcTemplate jdbcTemplate;

	@Autowired
	private ComboP28Dao comboP28Dao;
	@Autowired
	PaisDao paisDao;
	@Autowired
	DireccionesDao direccionesDao;
	@Autowired
	InformacionSueloDao informacionSueloDao;
	/*
	 * ROW_MAPPERS
	 */
	private final RowMapper<Elemento> rwMap = new RowMapper<Elemento>() {
		@Override
		public Elemento mapRow(ResultSet resultSet, int rowNum)
				throws SQLException {
			Elemento elemento = new Elemento();
			elemento.setIdeElemento(resultSet.getBigDecimal("IDE_ELEMENTO"));
			TipoElemento tipoElemento = new TipoElemento(
					resultSet.getString("COD_TIPO_ELEM"));
			elemento.setTipoElemento((TipoElemento) comboP28Dao
					.find(tipoElemento));

			// Direccion
			elemento.setDireccion(UtilsResulSet.getDireccionCompleta(resultSet,
					null, direccionesDao));

			elemento.setCodElemento(resultSet.getString("COD_ELEMENTO"));
			elemento.setNumFijoIbiElem(resultSet.getString("NUM_FIJO_IBI_ELEM"));
			elemento.setSuperficieUtil(resultSet.getBigDecimal("SUP_UTIL_ELEM"));
			TipoSiNo indUsoIndiv = new TipoSiNo(
					resultSet.getString("IND_USO_INDIV"));
			elemento.setIndUsoIndiv((TipoSiNo) comboP28Dao.find(indUsoIndiv));
			// elemento.setIndUsoIndiv(BeanUtils.getBoolean(resultSet.getString("IND_USO_INDIV")));
			TipoVinculacion tipoVinculacion = new TipoVinculacion(
					resultSet.getString("COD_VINCUL_ELEM"));
			elemento.setTipoVinculacion((TipoVinculacion) comboP28Dao
					.find(tipoVinculacion));
			Vivienda vivienda = new Vivienda(
					resultSet.getBigDecimal("NUM_VIVIENDA"));
			elemento.setVivienda(vivienda);
			elemento.setFecIniGestion(resultSet.getDate("FEC_INI_GESTION"));
			elemento.setFecFinGestion(resultSet.getDate("FEC_FIN_GESTION"));
			elemento.setNumOrganoGestor(resultSet.getLong("NUM_ORGANO_GESTOR"));
			elemento.setFecEnvOrgGestor(resultSet.getDate("FEC_ENV_ORG_GESTOR"));
			elemento.setNumExpediente(resultSet.getString("NUM_EXPEDIENTE"));

			elemento.setFechaEscriturasSuelo(resultSet
					.getDate("FEC_ESCRITURA_SUEL"));
			elemento.setCodRefCatastral(resultSet
					.getString("COD_REF_CATASTRAL"));
			return elemento;
		}
	};

	private final RowMapper<Elemento> rwMapDetail = new RowMapper<Elemento>() {
		@Override
		public Elemento mapRow(ResultSet resultSet, int rowNum)
				throws SQLException {
			Elemento elemento = new Elemento();
			elemento.setIdeElemento(resultSet.getBigDecimal("IDE_ELEMENTO"));
			TipoElemento tipoElemento = new TipoElemento(
					resultSet.getString("COD_TIPO_ELEM"));
			elemento.setTipoElemento(tipoElemento);
					
//					(TipoElemento) comboP28Dao
//					.find(tipoElemento));

			// Direccion
			elemento.setDireccion(UtilsResulSet.getDireccionCompleta(resultSet,
					null, direccionesDao));

			elemento.setCodElemento(resultSet.getString("COD_ELEMENTO"));
			elemento.setNumFijoIbiElem(resultSet.getString("NUM_FIJO_IBI_ELEM"));
			elemento.setSuperficieUtil(resultSet.getBigDecimal("SUP_UTIL_ELEM"));
			TipoSiNo indUsoIndiv = new TipoSiNo(
					resultSet.getString("IND_USO_INDIV"));
			//PRUEBA PARA PROBAR PRECARAG AUTOCOMPLETES
//			elemento.setIndUsoIndiv((TipoSiNo) comboP28Dao.find(indUsoIndiv));
			elemento.setIndUsoIndiv(indUsoIndiv);
			TipoVinculacion tipoVinculacion = new TipoVinculacion(
					resultSet.getString("COD_VINCUL_ELEM"));
//			elemento.setTipoVinculacion((TipoVinculacion) comboP28Dao
//					.find(tipoVinculacion));
			elemento.setTipoVinculacion(tipoVinculacion);
			Vivienda vivienda = new Vivienda(
					resultSet.getBigDecimal("NUM_VIVIENDA"));
			elemento.setVivienda(vivienda);
			elemento.setFecIniGestion(resultSet.getDate("FEC_INI_GESTION"));
			elemento.setFecFinGestion(resultSet.getDate("FEC_FIN_GESTION"));
			elemento.setNumOrganoGestor(resultSet.getLong("NUM_ORGANO_GESTOR"));
			elemento.setFecEnvOrgGestor(resultSet.getDate("FEC_ENV_ORG_GESTOR"));
			elemento.setNumExpediente(resultSet.getString("NUM_EXPEDIENTE"));
			RegistroPropiedad registroPropiedad = new RegistroPropiedad();
			registroPropiedad.setNombre(resultSet
					.getString("NOM_REGISTRO_PROP"));
			registroPropiedad.setNumero(UtilsResulSet.getLong(resultSet,
					"NUM_REGISTRO_PROP"));
			registroPropiedad.setTomo(resultSet.getString("DES_TOMO"));
			registroPropiedad.setLibro(resultSet.getString("DES_LIBRO"));
			registroPropiedad.setFolio(resultSet.getString("DES_FOLIO"));
			registroPropiedad.setFinca(resultSet.getString("DES_FINCA"));
			registroPropiedad.setInscripcion(resultSet
					.getString("DES_INSCRIPCION"));
			elemento.setRegistroPropiedad(registroPropiedad);
			// Información Suelo
			if (informacionSueloDao.findAllCount(new InformacionSuelo(elemento
					.getTipoElemento(), elemento.getIdeElemento())) > 0) {
				elemento.setInformacionSuelo(informacionSueloDao
						.find(new InformacionSuelo(elemento.getTipoElemento(),
								elemento.getIdeElemento())));
			}
			elemento.setFechaEscriturasSuelo(resultSet
					.getDate("FEC_ESCRITURA_SUEL"));
			elemento.setCodRefCatastral(resultSet
					.getString("COD_REF_CATASTRAL"));
			UtilsResulSet.getAbstractClass(resultSet, elemento, null);
			return elemento;
		}
	};

	private final RowMapper<Elemento> rwMapPK = new RowMapper<Elemento>() {
		@Override
		public Elemento mapRow(ResultSet resultSet, int rowNum)
				throws SQLException {
			return new Elemento(resultSet.getBigDecimal("IDE_ELEMENTO"));
		}
	};

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

	/*
	 * OPERACIONES CRUD
	 */
	// Metodo para rellenar los params con todos los campos del bean
	public void getParams(List<Object> params, Elemento elemento) {
		if (elemento == null) {
			return;
		}
		// COD_TIPO_ELEM
		if (elemento.getTipoElemento() != null) {
			params.add(elemento.getTipoElemento().getCodTabla());
		} else {
			params.add(null);
		}
		// COD_ELEMENTO
		params.add(elemento.getCodElemento());
//		
		// NUM_FIJO_IBI_ELEM
		params.add(elemento.getNumFijoIbiElem());
		// SUP_UTIL_ELEM
		params.add(elemento.getSuperficieUtil());
		// IND_USO_INDIV
		if (elemento.getIndUsoIndiv() != null && !elemento.getIndUsoIndiv().getCodTabla().isEmpty()) {
			params.add(elemento.getIndUsoIndiv().getCodTabla());
		} else {
			params.add(BDUtils.FALSE);
		}
		// NUM_VIVIENDA
		if (elemento.getVivienda()!= null && elemento.getVivienda().getNumVivienda()!=null) {
			params.add(elemento.getVivienda().getNumVivienda());
		} else {
			params.add(null);
		}
		// COD_VINCUL_ELEM
		if (elemento.getTipoVinculacion() != null) {
			params.add(elemento.getTipoVinculacion().getCodTabla());
		} else {
			params.add(null);
		}
		// NUM_EXPEDIENTE
		params.add(elemento.getNumExpediente());
		// REGISTRO_PROP
		if (elemento.getRegistroPropiedad() != null) {
			// NOM_REGISTRO_PROP
			params.add(elemento.getRegistroPropiedad().getNombre());
			// NUM_REGISTRO_PROP
			params.add(elemento.getRegistroPropiedad().getNumero());
			// DES_TOMO
			params.add(elemento.getRegistroPropiedad().getTomo());
			// DES_LIBRO
			params.add(elemento.getRegistroPropiedad().getLibro());
			// DES_FOLIO
			params.add(elemento.getRegistroPropiedad().getFolio());
			// DES_FINCA
			params.add(elemento.getRegistroPropiedad().getFinca());
			// DES_INSCRIPCION
			params.add(elemento.getRegistroPropiedad().getInscripcion());

		} else {
			params.add(null);
			params.add(null);
			params.add(null);
			params.add(null);
			params.add(null);
			params.add(null);
			params.add(null);
		}
		// FEC_ESCRITURA_SUEL
		params.add(elemento.getFechaEscriturasSuelo());
		//descalle
		if(elemento.getDireccion().getCalle().getId()== null){
			params.add(elemento.getDireccion().getCalle().getNombreEs());
		}else {
			params.add(null);
		}
		/***
		 * INI DIRECCION
		 */
		SQLGenericas.getParamsDireccion(params, elemento.getDireccion());

		// SQLGenericas.ABSTRACT_CLASS_SQL
		SQLGenericas.getParamsAbstractClass(params, elemento);
	}

	/**
	 * Inserts a single row in the M62r12t0 table.
	 * 
	 * @param elemento
	 *            Elemento
	 * @return Elemento
	 */
	@Override
	public Elemento add(Elemento elemento) {
		String query = ElementosDaoSql.SQL_INSERT;

		// Campos para la generación de un elemento
		// Preparar Parametros
		List<Object> params = new ArrayList<Object>();
		getParams(params, elemento);
		this.jdbcTemplate.update(query, params.toArray());
		return elemento;
	}

	/**
	 * Updates a single row in the M62r12t0 table.
	 * 
	 * @param elemento
	 *            Elemento
	 * @return Elemento
	 */
	// TODO los updates serán especificos en funcion de los parametros
	// recibidos.
	// Abrá un update generic
	@Override
	public Elemento update(Elemento elemento) {
		String query = ElementosDaoSql.SQL_UPDATE;

		// Campos para la generación de un elemento
		// Preparar Parametros
		List<Object> params = new ArrayList<Object>();
		getParams(params, elemento);
		// IDE_ELEMENTO (metemos el id al final por la update)
		params.add(elemento.getIdeElemento());
		this.jdbcTemplate.update(query, params.toArray());

		return elemento;
	}

	/**
	 * Finds a single row in the M62r12t0 table.
	 * 
	 * @param elemento
	 *            Elemento
	 * @return Elemento
	 */
	@Override
	@Transactional(readOnly = true)
	public Elemento find(Elemento elemento) {
		String query = ElementosDaoSql.SQL_FIND;
		List<Elemento> elementoList = this.jdbcTemplate.query(query,
				this.rwMapDetail, elemento.getIdeElemento());
		return DataAccessUtils.uniqueResult(elementoList);
	}

	/**
	 * Removes a single row in the M62r12t0 table.
	 * 
	 * @param elemento
	 *            Elementos
	 * @return
	 */
	@Override
	public void remove(Elemento elemento) {
//		String query = ElementosDaoSql.SQL_DELETE;
//		this.jdbcTemplate.update(query, elemento.getIdeElemento());
		/*****
		Llamada  a function que implementa llamada a plsql

		****/
		M62FuncionesPLSQL m62FuncionesPLSQL = new M62FuncionesPLSQL(this.jdbcTemplate.getDataSource());
		m62FuncionesPLSQL.borrarElemento(elemento.getIdeElemento());
	}

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

		// Where clause & Params
		Map<String, ?> mapaWhere = this.getWhereMap(elemento);
		StringBuilder where = new StringBuilder(ElementosDaoSql.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 M62r12t0 table using like.
	 * 
	 * @param elemento
	 *            Elemento
	 * @param jqGridRequestDto
	 *            JQGridRequestDto
	 * @param startsWith
	 *            Boolean
	 * @return List<Elemento>
	 */
	@Override
	@Transactional(readOnly = true)
	public List<Elemento> findAllLike(Elemento elemento,
			JQGridRequestDto jqGridRequestDto, Boolean startsWith) {
		StringBuilder query = new StringBuilder(ElementosDaoSql.SQL_FIND_ALL);
		
		// Where clause & Params
		Map<String, ?> mapaWhere = this.getWhereLikeMap(elemento, startsWith);
		StringBuilder where = new StringBuilder(ElementosDaoSql.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 M62r12t0 table.
	 * 
	 * @param elemento
	 *            Elemento
	 * @return Long
	 */
	@Override
	@Transactional(readOnly = true)
	public Long findAllCount(Elemento elemento) {
		StringBuilder query = new StringBuilder(
				ElementosDaoSql.SQL_FIND_ALL_COUNT);

		// Where clause & Params
		Map<String, ?> mapaWhere = this.getWhereMap(elemento);
		StringBuilder where = new StringBuilder(ElementosDaoSql.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());
	}

	/**
	 * <p>
	 * Comprobar que el anejo no esté dado de alta ya en el sistema
	 * </p>
	 * 
	 * @param elemento
	 *            Elemento
	 * @return boolean
	 */
	@Override
	@Transactional(readOnly = true)
	public boolean hayElementoMismoEmplazamiento(Elemento elemento) {

		StringBuilder query = new StringBuilder(
				ElementosDaoSql.SQL_FIND_ALL_COUNT);

		// Where clause & Params
		StringBuilder where = new StringBuilder(ElementosDaoSql.SQL_WHERE_ALL);
		List<Object> params = new ArrayList<Object>();
		if (elemento != null && elemento.getIdeElemento() != null) {
			where.append(" AND IDE_ELEMENTO!= ?");
			params.add(elemento.getIdeElemento());
		}
		if (elemento != null && elemento.getTipoElemento() != null) {
			where.append(" AND COD_TIPO_ELEM= ?");
			params.add(elemento.getTipoElemento().getCodTabla());
		}
		if (elemento != null && elemento.getCodElemento() != null) {
			where.append(" AND COD_ELEMENTO= ?");
			params.add(elemento.getCodElemento());
		}
		if (elemento != null && elemento.getDireccion() != null) {
			BDUtils.crearFiltroDireccion(where, params, "",
					elemento.getDireccion());
		}
		query.append(where);

		return this.jdbcTemplate.queryForLong(query.toString(),
				params.toArray()) > 0 ? true : false;
	}
	 /**
     * <p>Desvincular un elemento a una vivienda</p>
     *
     * @param ideElemento BigDecimal
     * @param numVivienda BigDecimal
     * @return boolean
     */
	@Override
	public boolean desvincularElemento(BigDecimal  ideElemento,BigDecimal  numVivienda) {
		String query = ElementosDaoSql.SQL_DESVINCULAR_ELEMENTO;
		List<Object> params = new ArrayList<Object>();
		// SQLGenericas.ABSTRACT_CLASS_SQL
		SQLGenericas.getParamsAbstractClass(params,new Elemento( ideElemento));
		params.add(ideElemento);
		params.add(numVivienda);
		this.jdbcTemplate.update(query, params.toArray());
		return true;
	}
	/**
     * <p>Vincular un elemento a una vivienda</p>
     *
     * @param ideElemento BigDecimal
     * @param numVivienda BigDecimal
     * @return boolean
     */
	@Override
	public boolean vincularElemento(BigDecimal  ideElemento,BigDecimal numVivienda) {
		String query = ElementosDaoSql.SQL_VINCULAR_ELEMENTO;
		List<Object> params = new ArrayList<Object>();
		params.add(numVivienda);
		// SQLGenericas.ABSTRACT_CLASS_SQL
		SQLGenericas.getParamsAbstractClass(params,new Elemento( ideElemento));
		params.add(ideElemento);
		this.jdbcTemplate.update(query, params.toArray());
		return true;
	}
	/**
	 * <p>
	 * Comprobar si el anejo tiene contratos
	 * </p>
	 * 
	 * @param elemento
	 *            Elemento
	 * @return boolean
	 */
	@Override
	@Transactional(readOnly = true)
	public boolean existenContratos(Elemento elemento) {

		StringBuilder query = new StringBuilder(
				ElementosDaoSql.SQL_COUNT_CONTRATOS);


		return this.jdbcTemplate.queryForLong(query.toString(),elemento.getIdeElemento())> 0 ? true : false;
	}
	/**
	 * Counts rows in the M62r12t0 table using like.
	 * 
	 * @param elemento
	 *            Elemento
	 * @param startsWith
	 *            Boolean
	 * @return Long
	 */
	@Override
	@Transactional(readOnly = true)
	public Long findAllLikeCount(Elemento elemento, Boolean startsWith) {
		StringBuilder query = new StringBuilder(
				ElementosDaoSql.SQL_FIND_ALL_COUNT);

		// Where clause & Params
		Map<String, ?> mapaWhere = this.getWhereLikeMap(elemento, startsWith);
		StringBuilder where = new StringBuilder(ElementosDaoSql.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());
	}

	/**
	 * Reorder the data list of M62r12t0 selected for rup_table
	 * 
	 * @param elemento
	 *            Elemento
	 * @param jqGridRequestDto
	 *            JQGridRequestDto
	 * @param startsWith
	 *            Boolean
	 * @return List<TableRowDto<Elementos>>
	 */
	@Override
	public List<TableRowDto<Elemento>> reorderSelection(Elemento elemento,
			JQGridRequestDto jqGridRequestDto, Boolean startsWith) {
		// SELECT
		StringBuilder query = new StringBuilder(ElementosDaoSql.SQL_FIND_ALL);

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

		// Parámetros de filtrado
		@SuppressWarnings("unchecked")
		List<Object> filterParamList = (List<Object>) mapaWhere.get("params");

		// SQL para la reordenación
		StringBuilder sbReorderSelectionSQL = JQGridManager.getReorderQuery(
				query, jqGridRequestDto, Elemento.class, filterParamList,
				ElementosDaoSql.PK);

		return this.jdbcTemplate.query(sbReorderSelectionSQL.toString(),
				new RowNumResultSetExtractor<Elemento>(this.rwMapPK,
						jqGridRequestDto), filterParamList.toArray());
	}

	/*
	 * MÉTODOS PRIVADOS
	 */

	/**
	 * Returns a map with the needed value to create the conditions to filter by
	 * the Elementos entity
	 * 
	 * @param elemento
	 *            Elementos 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(Elemento elemento) {

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

		if (elemento != null && elemento.getIdeElemento() != null) {
			where.append(" AND IDE_ELEMENTO= ?");
			params.add(elemento.getIdeElemento());
		}
		if (elemento != null && elemento.getTipoElemento() != null) {
			where.append(" AND COD_TIPO_ELEM= ?");
			params.add(elemento.getTipoElemento().getCodTabla());
		}
		// Direccion
		if (elemento != null && elemento.getDireccion() != null) {
			BDUtils.crearFiltroDireccion(where, params, "",
					elemento.getDireccion());
		}
		if (elemento != null && elemento.getCodElemento() != null) {
			where.append(" AND COD_ELEMENTO= ?");
			params.add(elemento.getCodElemento());
		}
		if (elemento != null && elemento.getNumFijoIbiElem() != null) {
			where.append(" AND NUM_FIJO_IBI_ELEM= ?");
			params.add(elemento.getNumFijoIbiElem());
		}
		if (elemento != null && elemento.getSuperficieUtil() != null) {
			where.append(" AND SUP_UTIL_ELEM= ?");
			params.add(elemento.getSuperficieUtil());
		}
		if (elemento != null && elemento.getIndUsoIndiv() != null) {
			where.append(" AND IND_USO_INDIV= ?");
			params.add(elemento.getIndUsoIndiv());
		}
		if (elemento != null && elemento.getTipoVinculacion() != null) {
			where.append(" AND COD_VINCUL_ELEM= ?");
			params.add(elemento.getTipoVinculacion().getCodTabla());
		}
		if (elemento != null && elemento.getVivienda() != null) {
			where.append(" AND NUM_VIVIENDA= ?");
			params.add(elemento.getVivienda().getNumVivienda());
		}
		if (elemento != null && elemento.getFecIniGestion() != null) {
			where.append(" AND FEC_INI_GESTION= ?");
			params.add(elemento.getFecIniGestion());
		}
		if (elemento != null && elemento.getFecFinGestion() != null) {
			where.append(" AND FEC_FIN_GESTION= ?");
			params.add(elemento.getFecFinGestion());
		}
		if (elemento != null && elemento.getNumOrganoGestor() != null) {
			where.append(" AND NUM_ORGANO_GESTOR= ?");
			params.add(elemento.getNumOrganoGestor());
		}
		if (elemento != null && elemento.getFecEnvOrgGestor() != null) {
			where.append(" AND FEC_ENV_ORG_GESTOR= ?");
			params.add(elemento.getFecEnvOrgGestor());
		}
		if (elemento != null && elemento.getNumExpediente() != null) {
			where.append(" AND NUM_EXPEDIENTE= ?");
			params.add(elemento.getNumExpediente());
		}
		if (elemento != null && elemento.getRegistroPropiedad() != null) {
			if (elemento.getRegistroPropiedad().getNombre() != null) {
				where.append(" AND NOM_REGISTRO_PROP= ?");
				params.add(elemento.getRegistroPropiedad().getNombre());
			}
			if (elemento.getRegistroPropiedad().getNumero() != null) {
				where.append(" AND NUM_REGISTRO_PROP= ?");
				params.add(elemento.getRegistroPropiedad().getNumero());
			}
			if (elemento.getRegistroPropiedad().getTomo() != null) {
				where.append(" AND DES_TOMO= ?");
				params.add(elemento.getRegistroPropiedad().getTomo());
			}
			if (elemento.getRegistroPropiedad().getLibro() != null) {
				where.append(" AND DES_LIBRO= ?");
				params.add(elemento.getRegistroPropiedad().getLibro());
			}
			if (elemento.getRegistroPropiedad().getFolio() != null) {
				where.append(" AND DES_FOLIO= ?");
				params.add(elemento.getRegistroPropiedad().getFolio());
			}
			if (elemento.getRegistroPropiedad().getFinca() != null) {
				where.append(" AND DES_FINCA= ?");
				params.add(elemento.getRegistroPropiedad().getFinca());
			}
			if (elemento.getRegistroPropiedad().getInscripcion() != null) {
				where.append(" AND DES_INSCRIPCION= ?");
				params.add(elemento.getRegistroPropiedad().getInscripcion());
			}
		}

		if (elemento != null && elemento.getFechaEscriturasSuelo() != null) {
			where.append(" AND FEC_ESCRITURA_SUEL= ?");
			params.add(elemento.getFechaEscriturasSuelo());
		}
		if (elemento != null && elemento.getCodRefCatastral() != null) {
			where.append(" AND COD_REF_CATASTRAL= ?");
			params.add(elemento.getCodRefCatastral());
		}

		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 Elementos entity
	 * 
	 * @param elemento
	 *            Elementos 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(Elemento elemento,
			Boolean startsWith) {

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

		if (elemento != null && elemento.getIdeElemento() != null) {
			where.append(" AND IDE_ELEMENTO = ?");
				params.add(elemento.getIdeElemento() );
		}

		if (elemento != null && elemento.getNumExpediente() != null) {
			where.append(" AND UPPER(NUM_EXPEDIENTE) like ? ESCAPE  '\\'");
			if (startsWith) {
				params.add(BDUtils.formatComodinesFiltroToBD(elemento.getNumExpediente().toUpperCase()) + "%");
			} else {
				params.add("%" + BDUtils.formatComodinesFiltroToBD(elemento.getNumExpediente().toUpperCase())
						+ "%");
			}
			where.append(" AND NUM_EXPEDIENTE IS NOT NULL");
		}

		if (elemento != null && elemento.getTipoElemento() != null) {
			where.append(" AND COD_TIPO_ELEM= ?");
			params.add(elemento.getTipoElemento().getCodTabla());
		}

		if (elemento != null && elemento.getCodElemento() != null) {
			where.append(" AND COD_ELEMENTO= ?");
			params.add(elemento.getCodElemento());
		}
		if (elemento != null && elemento.getVivienda() != null) {
			where.append(" AND NUM_VIVIENDA= ?");
			params.add(elemento.getVivienda().getNumVivienda());
		}
		if (elemento != null && elemento.getSuperficieUtil() != null) {
			where.append(" AND SUP_UTIL_ELEM= ?");
			params.add(elemento.getSuperficieUtil());
		}

		if (elemento != null && elemento.getNumFijoIbiElem() != null) {
			where.append(" AND NUM_FIJO_IBI_ELEM= ?");
			params.add(elemento.getNumFijoIbiElem());
		}

		if (elemento != null && elemento.getIndUsoIndiv() != null) {
			where.append(" AND IND_USO_INDIV= ?");
			params.add(elemento.getIndUsoIndiv().getCodTabla());
		}
		if (elemento != null && elemento.getTipoVinculacion() != null) {
			where.append(" AND COD_VINCUL_ELEM= ?");
			params.add(elemento.getTipoVinculacion().getCodTabla());
		}
		if (elemento != null && elemento.getDireccion() != null && elemento.getDireccion().getProvincia() != null) {
			BDUtils.crearFiltroDireccion(where, params, "",
					elemento.getDireccion());
		}
		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
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Elemento findForUpdate(Elemento elemento) {
		Elemento elementoBD;
		try {
			elementoBD = this.jdbcTemplate.queryForObject(
					ElementosDaoSql.SQL_FIND_FOR_UPDATE, this.rwMapDetail,
					elemento.getIdeElemento(), elemento.getFecHorUltimaModif());
		} catch (EmptyResultDataAccessException e) {
			throw new UFException(IberErrorsMsgConstants.CONCURRENCY_MSG);
		}
		if (elementoBD == null) {
			throw new UFException(IberErrorsMsgConstants.CONCURRENCY_MSG);
		}

		return elementoBD;
	}

	/**
	 * Busca el elemento de la vivienda y el tipo dado. Si no se informa alguno
	 * de los dos datos no realiza la busqueda.
	 * 
	 * Solo deveria de devolver un unico registro, si no, falla
	 * 
	 * @param numVivienda
	 *            BigDecimal
	 * @param tipoElemento
	 *            String
	 * 
	 * @return Elemento
	 */
	@Override
	@Transactional(readOnly = true)
	public Elemento findByNumViviendaAndTipoElemento(BigDecimal numVivienda,
			String tipoElemento) {
		Elemento elemento = null;

		// Si no se informan el numVivienda y el tipoElemento, no buscar
		if (numVivienda != null && !Utilidades.isEmpty(tipoElemento)) {
			String query = ElementosDaoSql.SQL_FIND_BY_VIVIENDA_AND_TIPO;
			List<Elemento> elementoList = this.jdbcTemplate.query(query,
					this.rwMapDetail, numVivienda, tipoElemento);
			elemento = DataAccessUtils.uniqueResult(elementoList);
		}

		return elemento;
	}

	/**
	 * StringBuilder initilization value
	 */
	public static final int STRING_BUILDER_INIT = 4096;
}
