package com.ejie.m62fb.service.registroVPP;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ejie.m62fb.dao.registroVPP.ContratoAlquilerDao;
import com.ejie.m62fb.dao.registroVPP.ElementosDao;
import com.ejie.m62fb.dao.registroVPP.InformacionSueloDao;
import com.ejie.m62fb.dao.registroVPP.ViviendaDao;
import com.ejie.m62fb.model.ContratoAlquiler;
import com.ejie.m62fb.model.ContratoVivienda;
import com.ejie.m62fb.model.Elemento;
import com.ejie.m62fb.model.ExpedienteVivienda;
import com.ejie.m62fb.model.InformacionSuelo;
import com.ejie.m62fb.model.Vivienda;
import com.ejie.m62fb.model.ViviendaActMasiva;
import com.ejie.m62fb.model.direccion.Direccion;
import com.ejie.m62fb.model.tipos.TipoElemento;
import com.ejie.m62fb.utils.constants.AppConstantes;
import com.ejie.m62fb.utils.constants.IberErrorsMsgConstants;
import com.ejie.m62fb.utils.error.UFException;
import com.ejie.m62fb.utils.sql.Utilidades;
import com.ejie.t17i.model.Portal;
import com.ejie.x38.dto.JQGridRequestDto;
import com.ejie.x38.dto.JQGridResponseDto;

/**
 * ViviendaServiceImpl.
 * 
XXXX
 */
@Service(value = "viviendaService")
public class ViviendaServiceImpl implements ViviendaService {

	@Autowired
	private ElementosDao elementosDao;

	@Autowired
	private InformacionSueloDao indInformacionSueloDao;

	@Autowired
	private ContratoAlquilerDao contratoAlquilerDao;
	@Autowired
	private InquilinoService inquilinoService;

	@Autowired
	private ContratoViviendaService contratoViviendaService;
	@Autowired
	private PropietarioService propietarioService;
	@Autowired
	private ViviendaDao viviendaDao;

	@Autowired
	private ExpedienteViviendaService expedienteViviendaService;
	/**
	 * Inserts a single row in the Vivienda table.
	 * 
	 * @param vivienda
	 *            Vivienda
	 * @return Vivienda
	 */
	@Override
	@Transactional(rollbackFor = Throwable.class)
@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','create')")
	public Vivienda add(Vivienda vivienda) {
		return this.viviendaDao.add(vivienda);
	}

	/**
	 * Updates a single row in the Vivienda table.
	 * 
	 * @param vivienda
	 *            Vivienda
	 * @return Vivienda
	 */
	@Override
	@Transactional(rollbackFor = Throwable.class)
@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','write')")
	public Vivienda update(Vivienda vivienda) {

		// Comprobamos si se han realizado cambios
		this.viviendaDao.checkForUpdate(vivienda);

		// Realizamos las validaciones necesarias
		this.validateUpdate(vivienda);

		// Recuperamos la Vivienda de BBDD (Completa)
		Vivienda viviendaBD = this.find(vivienda);

		// Realizamos el Update
		vivienda = this.viviendaDao.update(vivienda);

		// Actualizamos la Cuota de Participacion
		if (viviendaBD.isExisteInfoSuelo()) {
			InformacionSuelo infoSueloAux = new InformacionSuelo(
					TipoElemento.VIVIENDA, vivienda.getNumVivienda());
			if (vivienda.getInformacionSuelo() != null) {
				infoSueloAux.setCuotaParticipacion(vivienda
						.getInformacionSuelo().getCuotaParticipacion());
			}
			vivienda.setInformacionSuelo(infoSueloAux);
			this.indInformacionSueloDao.update(vivienda.getInformacionSuelo());
		}

		// Si la vivienda de pantalla tiene Garaje y la de BD NO tiene
		if (vivienda.getGaraje() != null
				&& vivienda.getGaraje().getIdeElemento() != null
				&& viviendaBD.getGaraje() == null) {
			// Vincular GARAJE
			this.elementosDao.vincularElemento(vivienda.getGaraje()
					.getIdeElemento(), vivienda.getNumVivienda());
		}

		// Si la vivienda de pantalla tiene Trastero y la de BD NO tiene
		if (vivienda.getTrastero() != null
				&& vivienda.getTrastero().getIdeElemento() != null
				&& viviendaBD.getTrastero() == null) {
			// Vincular TRASTERO
			this.elementosDao.vincularElemento(vivienda.getTrastero()
					.getIdeElemento(), vivienda.getNumVivienda());
		}

		return vivienda;
	}

	/**
	 * Updates a single row in the Vivienda table.
	 * 
	 * @param vivienda
	 *            Vivienda
	 * @return Vivienda
	 */
	@Override
	@Transactional(rollbackFor = Throwable.class)
@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','read')")
	public Vivienda updateActMasiva(ViviendaActMasiva vivienda) {
		// Comprobamos si se han realizado cambios
		// this.viviendaDao.checkForUpdate(vivienda);
		Vivienda viviendaBD = null;
		String[] rowIds = vivienda.getRowIds().split(",");
		// Recorremos las viviendas
		for (String row : rowIds) {
			viviendaBD = new Vivienda(new BigDecimal(row));
			viviendaBD = viviendaDao.find(viviendaBD);
			this.makeModificationsActMasive(vivienda, viviendaBD);
			// Actualizamos la vivienda
			viviendaBD = this.viviendaDao.update(viviendaBD);
		}
		return viviendaBD;
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','read')")
	public Vivienda updateActMasivaContratos(ViviendaActMasiva vivienda) {
		String[] rowIds = vivienda.getRowIds().split(",");
		String type = vivienda.getType();

		ContratoAlquiler contratoAlquiler;
		ContratoVivienda contratoVivienda;
		ExpedienteVivienda exp;
		// Recorremos las viviendas
		for (String row : rowIds) {
			//REcuperar el expediente
			exp=expedienteViviendaService.findExpedienteVivienda(Integer.parseInt(row));
			if (type.equals(AppConstantes.ALT_MASV_CONTRATOS_ALQUILER)) {
				contratoAlquiler = vivienda.getContratoAlquiler();
				contratoAlquiler.setVivienda(vivienda);
				contratoAlquiler.setExpedienteVivienda(exp);
				contratoAlquiler.getVivienda().setNumVivienda(
						new BigDecimal(row));
				contratoAlquilerDao.add(contratoAlquiler);
				contratoAlquiler.getInquilino().setVivienda(contratoAlquiler.getVivienda());
				contratoAlquiler.getInquilino().setExpedienteVivienda(contratoAlquiler.getExpedienteVivienda());
				inquilinoService.add(contratoAlquiler.getInquilino());
			} else if (type.equals(AppConstantes.ALT_MASV_CONTRATOS_COMPRA)) {
				contratoVivienda = vivienda.getContratoVivienda();
				contratoVivienda.setVivienda(vivienda);
				contratoVivienda.setExpedienteVivienda(exp);
				contratoVivienda.getVivienda().setNumVivienda(
						new BigDecimal(row));
				contratoViviendaService.add(contratoVivienda);
				contratoVivienda.getPropietario().setVivienda(contratoVivienda.getVivienda());
				contratoVivienda.getPropietario().setExpedienteVivienda(contratoVivienda.getExpedienteVivienda());
				if(contratoVivienda.getPropietario().getPorTitularidad()==null){
					contratoVivienda.getPropietario().setPorTitularidad(new BigDecimal(100));
				}
				propietarioService.add(contratoVivienda.getPropietario() );
			}
		}
		return vivienda;
	}

@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','read')")
	public void makeModificationsActMasive(ViviendaActMasiva vivienda,
			Vivienda viviendaBD) {
		String type = vivienda.getType();
		Portal portalBD = null;
		Direccion direccionBD = null;
		if (type.equals(AppConstantes.PORTAL)) {
			if (vivienda.getDireccion().getPortal() != null
					&& vivienda.getDireccion().getPortal().getNumero() != null) {
				direccionBD = viviendaBD.getDireccion();
				portalBD = direccionBD.getPortal();
				portalBD.setNumero(vivienda.getDireccion().getPortal()
						.getNumero());
			}
			direccionBD.setPortal(portalBD);
			viviendaBD.setDireccion(direccionBD);
		} else if (type.equals(AppConstantes.COD_POSTAL)) {
			direccionBD = viviendaBD.getDireccion();
			direccionBD.setProvincia(vivienda.getDireccion().getProvincia());
			direccionBD.setMunicipio(vivienda.getDireccion().getMunicipio());
			direccionBD.setLocalidad(vivienda.getDireccion().getLocalidad());
			direccionBD.setCalle(vivienda.getDireccion().getCalle());

			if (vivienda.getDireccion().getPortal() != null
					&& vivienda.getDireccion().getPortal().getCodigoPostal() != null) {
				portalBD = direccionBD.getPortal();
				portalBD.setCodigoPostal(vivienda.getDireccion().getPortal()
						.getCodigoPostal());
			}
			direccionBD.setPortal(portalBD);
			viviendaBD.setDireccion(direccionBD);
		} else if (type.equals(AppConstantes.FEC_CALIFICACION)) {
			viviendaBD.setFecCalificacion(vivienda.getFecCalificacion());
		} else if (type.equals(AppConstantes.FEC_DESCALIFICACION)) {
			viviendaBD.setFecDescalificacion(vivienda.getFecDescalificacion());
		} else if (type.equals(AppConstantes.PLAZO_CALIFICACION)) {
			viviendaBD.setNumPlazoCalificacion(vivienda
					.getNumPlazoCalificacion());
		} else if (type.equals(AppConstantes.REF_CATASTRAL)) {
			viviendaBD.setCodRefCatastral(vivienda.getCodRefCatastral());
		} else if (type.equals(AppConstantes.IBI)) {
			viviendaBD.setNumFijoIbi(vivienda.getNumFijoIbi());
		} else if (type.equals(AppConstantes.REG_ACCESO)) {
			viviendaBD.setRegimenAcceso(vivienda.getRegimenAcceso());
		} else if (type.equals(AppConstantes.REG_TENENCIA)) {
			viviendaBD.setRegimenTenencia(vivienda.getRegimenTenencia());
		} else if (type.equals(AppConstantes.UNIFAMILIAR)) {
			viviendaBD.setIndVivUnifamiliar(vivienda.getIndVivUnifamiliar());
		} else if (type.equals(AppConstantes.FAMILIA_NUMEROSA)) {
			viviendaBD.setIndFamiliaNumer(vivienda.getIndFamiliaNumer());
		} else if (type.equals(AppConstantes.ARI)) {
			viviendaBD.setIndAri(vivienda.getIndAri());
		} else if (type.equals(AppConstantes.BAJA_DENSIDAD)) {
			viviendaBD.setIndBajaDensidad(vivienda.getIndBajaDensidad());
		} else if (type.equals(AppConstantes.FEC_INSCRIPCION)) {
			viviendaBD.setFecInscripDerSup(vivienda.getFecInscripDerSup());
		} else {
			updateClasificacion(vivienda, viviendaBD);
		}
	}

	/**
	 * Operacion updateClasificacion. Modificacion del bean indicado.
	 * 
	 * @param vivienda
	 *            Vivienda Bean que contiene la informacion a modificar.
	 * @param viviendaBD
	 *            Vivienda con la información de BD
	 * @return Vivienda Bean resultante de la modificacion.
	 */
@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','read')")
	public void updateClasificacion(ViviendaActMasiva vivienda,
			Vivienda viviendaBD) {
		String type = vivienda.getType();
		if (type.equals(AppConstantes.ADJ_PORQUE)) {
			viviendaBD.setTipoPorqueAdjudicacion(vivienda
					.getTipoPorqueAdjudicacion());
		} else if (type.equals(AppConstantes.ADJ_COMO)) {
			viviendaBD.setTipoComoAdjudicacion(vivienda
					.getTipoComoAdjudicacion());
		} else if (type.equals(AppConstantes.ADJ_QUIEN)) {
			viviendaBD.setTipoQuienAdjudicacion(vivienda
					.getTipoQuienAdjudicacion());
		} else if (type.equals(AppConstantes.ADJUDICACION)) {
			viviendaBD.setTipoAdjudicacion(vivienda.getTipoAdjudicacion());
		} else if (type.equals(AppConstantes.PROPIETARIOS)) {
			viviendaBD.setTipoPropietarios(vivienda.getTipoPropietarios());
		} else if (type.equals(AppConstantes.PROMOTOR)) {
			viviendaBD.setTipoPromotor(vivienda.getTipoPromotor());
		} else if (type.equals(AppConstantes.ACCESO)) {
			viviendaBD.setTipoAcceso(vivienda.getTipoAcceso());
		} else if (type.equals(AppConstantes.REGULACION)) {
			viviendaBD.setTipoRegulacion(vivienda.getTipoRegulacion());
		} else if (type.equals(AppConstantes.INICIATIVA)) {
			viviendaBD.setTipoIniciativa(vivienda.getTipoIniciativa());
		}
	}

	/**
	 * Finds a single row in the Vivienda table.
	 * 
	 * @param vivienda
	 *            Vivienda
	 * @return Vivienda
	 */
	@Override
@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','read')")
	public Vivienda find(Vivienda vivienda) {
		
		Vivienda viviendaBD = null;
		if (vivienda.getRowId()!=null && vivienda.getRowId().trim().length()>0){
			vivienda = this.viviendaDao.findByRowid(vivienda.getRowId());
		}
		viviendaBD = this.viviendaDao.find(vivienda);
		if (viviendaBD != null) {
			// Comprobamos si hay informacion del suelo
			viviendaBD.setExisteInfoSuelo(this.indInformacionSueloDao
					.findAllCount(new InformacionSuelo(TipoElemento.VIVIENDA,
							viviendaBD.getNumVivienda())) > 0);

			// Recuperamos los datos del Garaje
			viviendaBD.setGaraje(this.elementosDao
					.findByNumViviendaAndTipoElemento(
							viviendaBD.getNumVivienda(), TipoElemento.GARAJE));
			// Recuperamos los datos del Trastero
			viviendaBD
					.setTrastero(this.elementosDao
							.findByNumViviendaAndTipoElemento(
									viviendaBD.getNumVivienda(),
									TipoElemento.TRASTERO));
		}

		return viviendaBD;
	}

	/**
	 * Deletes a single row in the Vivienda table.
	 * 
	 * @param vivienda
	 *            Vivienda
	 */
	@Override
	@Transactional(rollbackFor = Throwable.class)
@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','delete')")
	public void remove(Vivienda vivienda) {
//		Vivienda viviendaBD;
		if (vivienda.getRowId()!=null && vivienda.getRowId().trim().length()>0){
		    //recupero numVivienda de la vista según rowid
			vivienda = this.viviendaDao.findByRowid(vivienda.getRowId());
			
			//comprobamos si tiene contratos asociados a una solicitud platea
			List<ContratoVivienda> contratosSolPlatea = contratoViviendaService.findAllSolPlatea(new ContratoVivienda(vivienda), null);
			if(Utilidades.isEmptyList(contratosSolPlatea)){
			    this.viviendaDao.remove(vivienda);
			}
			else{
			    throw new UFException(IberErrorsMsgConstants.VIVIENDA_CONTRATO_SOLPLATEA);
			}
		
			
//			viviendaBD = this.viviendaDao.find(vivienda);
//			this.viviendaDao.remove(viviendaBD);
		}
		else{
		    throw new UFException(IberErrorsMsgConstants.UNEXPECTED_MSG);
		}
	}

	/*
	 * OPERACIONES RUP_TABLE
	 */

	/**
	 * Funcion encargada de Filtra las viviendas para el mantenimiento de
	 * seleccion de viviendas
	 * 
	 * @param vivienda
	 *            Vivienda
	 * @param jqGridRequestDto
	 *            JQGridRequestDto
	 * @param startsWith
	 *            Booleanl
	 * @return List<Vivienda>
	 */
	@Override
@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','read')")
	public JQGridResponseDto<Vivienda> filterSeleccionViviendas(
			Vivienda filterVivienda, JQGridRequestDto jqGridRequestDto,
			Boolean startsWith) {
		List<Vivienda> listaVivienda = this.viviendaDao
				.filterSeleccionViviendas(filterVivienda, jqGridRequestDto,
						false);
		Long recordNum = this.viviendaDao
				.filterSeleccionViviendasCount(
						filterVivienda != null ? filterVivienda
								: new Vivienda(), false);
		return new JQGridResponseDto<Vivienda>(jqGridRequestDto, recordNum,
				listaVivienda);
	}

	/**
	 * Funcion encargada de Filtra las viviendas para el mantenimiento de
	 * seleccion de viviendas
	 * 
	 * @param vivienda
	 *            Vivienda
	 * @param jqGridRequestDto
	 *            JQGridRequestDto
	 * @param startsWith
	 *            Booleanl
	 * @return List<Vivienda>
	 */
	@Override
@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','read')")
	public JQGridResponseDto<ViviendaActMasiva> filterSeleccionViviendasForActMasiva(
			Vivienda filterVivienda, JQGridRequestDto jqGridRequestDto,
			Boolean startsWith) {
		List<ViviendaActMasiva> listaVivienda = this.viviendaDao
				.filterSeleccionViviendasForActMasiva(filterVivienda,
						jqGridRequestDto, false);
		// TODO el contador ahora mismo me da igual porque sera el mismo
		Long recordNum = this.viviendaDao
				.filterSeleccionViviendasCount(
						filterVivienda != null ? filterVivienda
								: new Vivienda(), false);
		return new JQGridResponseDto<ViviendaActMasiva>(jqGridRequestDto,
				recordNum, listaVivienda);
	}

	/**
	 * Realiza las validaciones necesarias antes de realizar el update de la
	 * vivienda
	 * 
	 * @param vivienda
	 *            Vivienda
	 */
	@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','write')")
	private void validateUpdate(Vivienda vivienda) {
		// Validamos que el Garaje no este en otra vivienda
		if (vivienda.getGaraje() != null
				&& vivienda.getGaraje().getIdeElemento() != null) {
			Elemento garaje = this.elementosDao.find(vivienda.getGaraje());
			if (garaje.getVivienda() != null
					&& garaje.getVivienda().getNumVivienda() != null
					&& !garaje.getVivienda().getNumVivienda()
							.equals(vivienda.getNumVivienda())) {
				List <Object> userFriendlyMessageParams = new ArrayList<Object>();
				userFriendlyMessageParams.add(garaje.getVivienda().getNumVivienda().toString());
				throw new UFException(
						IberErrorsMsgConstants.GARAJE_RELACIONADO_OTRA_VIVIENDA,userFriendlyMessageParams);
			}
		}

		// Validamos que el Trastero no este en otra vivienda
		if (vivienda.getTrastero() != null
				&& vivienda.getTrastero().getIdeElemento() != null) {
			Elemento trastero = this.elementosDao.find(vivienda.getTrastero());
			if (trastero.getVivienda() != null
					&& trastero.getVivienda().getNumVivienda() != null
					&& !trastero.getVivienda().getNumVivienda()
							.equals(vivienda.getNumVivienda())) {
				List <Object> userFriendlyMessageParams = new ArrayList<Object>();
				userFriendlyMessageParams.add(trastero.getVivienda().getNumVivienda().toString());
				throw new UFException(
						IberErrorsMsgConstants.TRASTERO_RELACIONADO_OTRA_VIVIENDA,userFriendlyMessageParams);
			}
		}
	}

	@Override
	@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','read')")
	public List<Vivienda> findAll(Vivienda filterVivienda, JQGridRequestDto jqGridRequestDto) {
		return (List<Vivienda>) this.viviendaDao.findAll(filterVivienda, jqGridRequestDto);
	}

	@Override
	@PreAuthorize("hasPermission('VIVIENDA_SERVICE','SecureService','read')")
	public List<Vivienda> findAllLike(Vivienda filterVivienda, JQGridRequestDto jqGridRequestDto, Boolean startsWith) {
		return (List<Vivienda>) this.viviendaDao.findAllLike(filterVivienda, jqGridRequestDto, startsWith);
	}

	@Override
	public Vivienda findForLupa(Vivienda vivienda) {
		Vivienda viviendaBD = this.viviendaDao.findForLupa(vivienda);
		if (viviendaBD != null) {
			// Comprobamos si hay informacion del suelo
			viviendaBD.setExisteInfoSuelo(this.indInformacionSueloDao
					.findAllCount(new InformacionSuelo(TipoElemento.VIVIENDA,
							viviendaBD.getNumVivienda())) > 0);

			// Recuperamos los datos del Garaje
			viviendaBD.setGaraje(this.elementosDao
					.findByNumViviendaAndTipoElemento(
							viviendaBD.getNumVivienda(), TipoElemento.GARAJE));
			// Recuperamos los datos del Trastero
			viviendaBD
					.setTrastero(this.elementosDao
							.findByNumViviendaAndTipoElemento(
									viviendaBD.getNumVivienda(),
									TipoElemento.TRASTERO));
		}
		return viviendaBD;
	}

}
