package com.ejie.y42b.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ejie.x38.control.exception.ResourceNotFoundException;
import com.ejie.x38.dto.Pagination;
import com.ejie.y42b.constantes.Y42bAgendaConstantes;
import com.ejie.y42b.dao.EntidadDao;
import com.ejie.y42b.model.Contacto;
import com.ejie.y42b.model.Entidad;
import com.ejie.y42b.model.Etiqueta;
import com.ejie.y42b.model.Grupo;
import com.ejie.y42b.model.Y42bGrupo;
import com.ejie.y42b.utils.Y42bUIDGenerator32;
import com.ejie.y42b.utils.Y42bUtils;
import com.ejie.y42b.utils.exception.Y42bUDAException;

/**
 * * EntidadServiceImpl  
 * 
 *  
 */

@Service(value = "entidadService")
public class EntidadServiceImpl implements EntidadService {

	private static final Logger logger = LoggerFactory
			.getLogger(EntidadServiceImpl.class);
	@Autowired()
	private EntidadDao entidadDao;

	@Resource()
	private ReloadableResourceBundleMessageSource appMessageSource;

	/**
	 * Inserts a single row in the Entidad table.
	 * 
	 * @param pEntidad
	 *            Entidad
	 * @return Entidad
	 * @exception Exception
	 *                Exception
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Entidad add(Entidad pEntidad) throws Exception {
		try {
			Entidad entidad = pEntidad;
			entidad.setFecultmod(new Date());

			entidad.setEntidadId(Y42bAgendaConstantes.PREFIJO_ENTIDAD
					+ Y42bUIDGenerator32.getInstance().generateId());
			entidad.setNombreEs(Y42bUtils.filtroDB(entidad.getNombreEs()));
			entidad.setNombreEu(Y42bUtils.filtroDB(entidad.getNombreEu()));
			// Miro si existe la descripcion en castellano y en euskera en BBDD.
			if (this.entidadDao.findByNombreCount(entidad) > 0) {
				// Si existe con ese nombre mando un error
				throw new Y42bUDAException("error.entidad.nombreYaExiste",
						true, null);
			}

			// String codOrg = "";
			// if(Y42bAgendaConstantes.SI.equals(entidad.getIsnacional())){
			// codOrg = this.obtenerCodigoOrganismo(entidad);
			// }
			// entidad.setCodOrg(codOrg);

			if (null == pEntidad.getActiva()
					|| ("null").equals(pEntidad.getActiva())
					|| "" == pEntidad.getActiva()) {
				entidad.setActiva(Y42bAgendaConstantes.SI);
			}
			/* Validar datos de negocio */
			this.validarDatos(entidad);

			entidad = this.entidadDao.add(entidad);

			// añadir las etiquetas que vengan
			this.entidadDao.addEtiquetaEntidad(entidad);

			return this.entidadDao.addGrupoEntidad(entidad);
		} catch (DuplicateKeyException e) {
			String causa = e.getCause().toString();
			int i = causa.indexOf("Y42B.UK_Y42B01T00_03");
			int j = causa.indexOf("Y42B.UK_Y42B01T00_04");
			if (i != -1) { // Cod_org
				throw new Y42bUDAException("error.entidad.organismoYaExiste",
						true, e);
			} else if (j != -1) {// Usuario
				throw new Y42bUDAException("error.entidad.usuarioYaExiste",
						true, e);
			} else {// generico
				throw new Y42bUDAException("error.entidad.errorGenerico", true,
						e);
			}
		}
	}

	/**
	 * Obtiene el numero de organismo en base a provincia y tipo de organismo
	 * 
	 * @param entidad
	 *            Entidad
	 * @return String
	 */
	public String obtenerCodigoOrganismo(Entidad entidad) {
		Entidad entidadAux = new Entidad();
		StringBuffer codigoOrganismo = new StringBuffer();
		if (entidad.getNoraProvinciaId() != null)
			codigoOrganismo.append(entidad.getNoraProvinciaId());
		else if (entidad.getNoraPaisId() != null) {
			codigoOrganismo.append(entidad.getNoraPaisId());
		}
		codigoOrganismo.append(entidad.getTipoOrganismo());

		entidadAux.setCodOrg(codigoOrganismo.toString());

		entidadAux = this.entidadDao.findSiguienteCodigoOrganismo(entidadAux);

		return entidadAux.getCodOrg();
	}

	/**
	 * Updates a single row in the Entidad table.
	 * 
	 * @param pEntidad
	 *            Entidad
	 * @return Entidad
	 * @exception Exception
	 *                Exception
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Entidad update(Entidad pEntidad) throws Exception {

		try {
			Entidad entidad = pEntidad;
			entidad.setFecultmod(new Date());

			/* Validar datos de negocio */
			this.validarDatos(entidad);

			this.entidadDao.update(entidad);

			// eliminar todos sus grupos
			this.entidadDao.removeAllGruposEntidad(entidad);
			// añadir los buenos
			this.entidadDao.addGrupoEntidad(entidad);

			// eliminar todas sus etiquetas
			this.entidadDao.removeAllEtiquetasEntidad(entidad);
			// añadir las que vengan
			this.entidadDao.addEtiquetaEntidad(entidad);

			// Miro si existe la descripcion en castellano y en euskera en BBDD.
			if (this.entidadDao.findByNombreCount(entidad) > 1) {
				// Si existe con ese nombre mando un error
				throw new Y42bUDAException("error.entidad.nombreYaExiste",
						true, null);
			}

			return entidad;

		} catch (DuplicateKeyException e) {
			String causa = e.getCause().toString();
			int i = causa.indexOf("Y42B.UK_Y42B01T00_03");
			int j = causa.indexOf("Y42B.UK_Y42B01T00_04");
			if (i != -1) { // Cod_org
				throw new Y42bUDAException("error.entidad.organismoYaExiste",
						true, e);
			} else if (j != -1) {// Usuario
				throw new Y42bUDAException("error.entidad.usuarioYaExiste",
						true, e);
			} else {// generico
				throw new Y42bUDAException("error.entidad.errorGenerico", true,
						e);
			}
		}
	}

	/**
	 * Updates a single row in the Entidad table.
	 * 
	 * @param pEntidad
	 *            Entidad
	 * @return Entidad
	 * @exception Exception
	 *                Exception
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Entidad updateEntidad(Entidad pEntidad) throws Exception {

		try {
			Entidad entidad = pEntidad;
			entidad.setFecultmod(new Date());

			/* Validar datos de negocio */
			this.validarDatos(entidad);

			this.entidadDao.update(entidad);

			return entidad;

		} catch (DuplicateKeyException e) {
			String causa = e.getCause().toString();
			int i = causa.indexOf("Y42B.UK_Y42B01T00_03");
			int j = causa.indexOf("Y42B.UK_Y42B01T00_04");
			if (i != -1) { // Cod_org
				throw new Y42bUDAException("error.entidad.organismoYaExiste",
						true, e);
			} else if (j != -1) {// Usuario
				throw new Y42bUDAException("error.entidad.usuarioYaExiste",
						true, e);
			} else {// generico
				throw new Y42bUDAException("error.entidad.errorGenerico", true,
						e);
			}
		}
	}

	/**
	 * Updates a single row in the Entidad table. Sin validacion. para los
	 * masivos
	 * 
	 * @param pEntidad
	 *            Entidad
	 * @return Entidad
	 * @exception Exception
	 *                Exception
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Entidad updateEntidadSinValidacion(Entidad pEntidad)
			throws Exception {

		try {
			Entidad entidad = pEntidad;
			entidad.setFecultmod(new Date());

			this.entidadDao.update(entidad);

			return entidad;

		} catch (DuplicateKeyException e) {
			String causa = e.getCause().toString();
			int i = causa.indexOf("Y42B.UK_Y42B01T00_03");
			int j = causa.indexOf("Y42B.UK_Y42B01T00_04");
			if (i != -1) { // Cod_org
				throw new Y42bUDAException("error.entidad.organismoYaExiste",
						true, e);
			} else if (j != -1) {// Usuario
				throw new Y42bUDAException("error.entidad.usuarioYaExiste",
						true, e);
			} else {// generico
				throw new Y42bUDAException("error.entidad.errorGenerico", true,
						e);
			}
		}
	}

	/**
	 * Finds a single row in the Entidad table.
	 * 
	 * @param entidad
	 *            Entidad
	 * @return Entidad
	 */
	public Entidad find(Entidad entidad) {
		return (Entidad) this.entidadDao.find(entidad);
	}

	/**
	 * Finds a List of rows in the Entidad table.
	 * 
	 * @param entidad
	 *            Entidad
	 * @param pagination
	 *            Pagination
	 * @return List
	 */
	public List<Entidad> findAll(Entidad entidad, Pagination pagination) {
		return (List<Entidad>) this.entidadDao.findAll(entidad, pagination);
	}

	/**
	 * Counts rows in the Entidad table.
	 * 
	 * @param entidad
	 *            Entidad
	 * @return Long
	 */
	public Long findAllCount(Entidad entidad) {
		return this.entidadDao.findAllCount(entidad);
	}

	/**
	 * Finds rows in the Entidad table using like.
	 * 
	 * @param entidad
	 *            Entidad
	 * @param pagination
	 *            Pagination
	 * @param startsWith
	 *            Boolean
	 * @return List
	 */
	public List<Entidad> findAllLike(Entidad entidad, Pagination pagination,
			Boolean startsWith) {
		return (List<Entidad>) this.entidadDao.findAllLike(entidad, pagination,
				startsWith);
	}

	/**
	 * Deletes a single row in the Entidad table.
	 * 
	 * @param entidad
	 *            Entidad
	 * @return
	 */
	@Transactional(rollbackFor = Throwable.class)
	public void remove(Entidad entidad) {
		this.entidadDao.remove(entidad);
	}

	/**
	 * Deletes multiple rows in the Entidad table.
	 * 
	 * @param entidadList
	 *            ArrayList
	 * @return
	 */
	@Transactional(rollbackFor = Throwable.class)
	public void removeMultiple(ArrayList<Entidad> entidadList) {
		for (Entidad entidadAux : entidadList) {
			this.entidadDao.remove(entidadAux);
		}
	}

	/**
	 * Inserts a single row in the EtiquetaEntidad table.
	 * 
	 * @param entidad
	 *            Entidad
	 * @return Entidad
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Entidad addEtiquetaEntidad(Entidad entidad) {
		return this.entidadDao.addEtiquetaEntidad(entidad);
	}

	/**
	 * Deletes a single row in the EtiquetaEntidad table.
	 * 
	 * @param entidad
	 *            Entidad
	 */
	@Transactional(rollbackFor = Throwable.class)
	public void removeEtiquetaEntidad(Entidad entidad) {
		this.entidadDao.removeEtiquetaEntidad(entidad);
	}

	/**
	 * Find a single row in the findEtiquetaEntidad Many To Many relationship.
	 * 
	 * @param entidad
	 *            Entidad
	 * @param etiqueta
	 *            Etiqueta
	 * @param pagination
	 *            Pagination
	 * @return Entidad
	 */
	public Entidad findEtiquetaEntidad(Entidad entidad, Etiqueta etiqueta,
			Pagination pagination) {

		return this.entidadDao.findEtiquetaEntidad(entidad, etiqueta,
				pagination);
	}

	/**
	 * Counts rows in the EtiquetaEntidad table.
	 * 
	 * @param entidad
	 *            Entidad
	 * @param etiqueta
	 *            Etiqueta
	 * @return List
	 */
	public Long findEtiquetaEntidadCount(Entidad entidad, Etiqueta etiqueta) {
		return this.entidadDao.findEtiquetaEntidadCount(entidad, etiqueta);
	}

	/**
	 * Inserts a single row in the GrupoEntidad table.
	 * 
	 * @param entidad
	 *            Entidad
	 * @return Entidad
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Entidad addGrupoEntidad(Entidad entidad) {
		return this.entidadDao.addGrupoEntidad(entidad);
	}

	/**
	 * Deletes a single row in the GrupoEntidad table.
	 * 
	 * @param entidad
	 *            Entidad
	 */
	@Transactional(rollbackFor = Throwable.class)
	public void removeGrupoEntidad(Entidad entidad) {
		this.entidadDao.removeGrupoEntidad(entidad);
	}

	/**
	 * Find a single row in the findGrupoEntidad Many To Many relationship.
	 * 
	 * @param entidad
	 *            Entidad
	 * @param pGrupo
	 *            Grupo
	 * @param pagination
	 *            Pagination
	 * @return Entidad Entidad
	 */
	public Entidad findGrupoEntidad(Entidad entidad, Y42bGrupo pGrupo,
			Pagination pagination) {
		Grupo grupo = new Grupo();
		grupo.setActiva(pGrupo.getActiva());
		grupo.setGrupoId(pGrupo.getGrupoId());

		return this.entidadDao.findGrupoEntidad(entidad, grupo, pagination);
	}

	/**
	 * Counts rows in the GrupoEntidad table.
	 * 
	 * @param entidad
	 *            Entidad
	 * @param pGrupo
	 *            Grupo
	 * @return List
	 */
	public Long findGrupoEntidadCount(Entidad entidad, Y42bGrupo pGrupo) {
		Grupo grupo = new Grupo();
		grupo.setActiva(pGrupo.getActiva());
		grupo.setGrupoId(pGrupo.getGrupoId());

		return this.entidadDao.findGrupoEntidadCount(entidad, grupo);
	}

	/**
	 * Inserts a single row in the EntidadContacto table.
	 * 
	 * @param entidad
	 *            Entidad
	 * @return Entidad
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Entidad addEntidadContacto(Entidad entidad) {
		return this.entidadDao.addEntidadContacto(entidad);
	}

	/**
	 * Deletes a single row in the EntidadContacto table.
	 * 
	 * @param entidad
	 *            Entidad
	 */
	@Transactional(rollbackFor = Throwable.class)
	public void removeEntidadContacto(Entidad entidad) {
		this.entidadDao.removeEntidadContacto(entidad);
	}

	/**
	 * Find a single row in the findEntidadContacto Many To Many relationship.
	 * 
	 * @param entidad
	 *            Entidad
	 * @param contacto
	 *            Contacto
	 * @param pagination
	 *            Pagination
	 * @return Entidad
	 */
	public Entidad findEntidadContacto(Entidad entidad, Contacto contacto,
			Pagination pagination) {
		return this.entidadDao.findEntidadContacto(entidad, contacto,
				pagination);
	}

	/**
	 * Counts rows in the EntidadContacto table.
	 * 
	 * @param entidad
	 *            Entidad
	 * @param contacto
	 *            Contacto
	 * @return List
	 */
	public Long findEntidadContactoCount(Entidad entidad, Contacto contacto) {
		return this.entidadDao.findEntidadContactoCount(entidad, contacto);
	}

	/**
	 * Getter method for EntidadDao
	 * 
	 * @return EntidadDao
	 */
	public EntidadDao getEntidadDao() {
		return this.entidadDao;
	}

	/**
	 * Setter method for EntidadDao.
	 * 
	 * @param entidadDao
	 *            EntidadDao
	 * @return
	 */
	public void setEntidadDao(EntidadDao entidadDao) {
		EntidadServiceImpl.logger.info("Setting Dependency " + entidadDao);
		this.entidadDao = entidadDao;
	}

	/**
	 * Validar datos de pantalla
	 * 
	 * @param entidad
	 *            Entidad
	 * @throws Exception
	 *             Exception
	 */
	private void validarDatos(Entidad entidad) throws Exception {
		List<String> arrErrors = new ArrayList<String>();
		Locale locale = LocaleContextHolder.getLocale();
		boolean bNacional = ((Y42bAgendaConstantes.SI.equals(entidad
				.getIsnacional()) ? true : false));

		// Normalizar valores
		String paisId = Y42bUtils.normalizarCero(entidad.getNoraPaisId());
		String provinciaId = Y42bUtils.normalizarCero(entidad
				.getNoraProvinciaId());
		String municipioId = Y42bUtils.normalizarCero(entidad
				.getNoraMunicipioId());
		// String localidadId = Y42bUtils.normalizarCero(entidad
		// .getNoraLocalidadId());
		/*
		 * String localidadInt = Y42bUtils.normalizarVacio(entidad
		 * .getNombreLocalidad());
		 */
		if (bNacional) {
			if ("0".equals(provinciaId)) {
				// errNegocio.append("<li>");
				arrErrors.add(this.appMessageSource.getMessage(
						"required.provincia", null, locale));
				// errNegocio.append("</li>");
			}
			if ("0".equals(municipioId)) {
				// errNegocio.append("<li>");
				arrErrors.add(this.appMessageSource.getMessage(
						"required.municipio", null, locale));
				// errNegocio.append("</li>");
			}
			// if ("0".equals(localidadId)) {
			// //errNegocio.append("<li>");
			// arrErrors.add(this.appMessageSource.getMessage(
			// "required.localidad", null, locale));
			// //errNegocio.append("</li>");
			// }
		} else {
			if ("0".equals(paisId)) {
				// errNegocio.append("<li>");
				arrErrors.add(this.appMessageSource.getMessage("required.pais",
						null, locale));
				// errNegocio.append("</li>");
			}
			/*
			 * if ("".equals(localidadInt)) { //errNegocio.append("<li>");
			 * arrErrors.add(this.appMessageSource.getMessage(
			 * "required.localidad", null, locale));
			 * //errNegocio.append("</li>"); }
			 */
		}

		if (arrErrors.size() == 0) {
			EntidadServiceImpl.logger.debug("Entidad valida.");
		} else {
			EntidadServiceImpl.logger
					.debug("Se presentaron errores al validar la entidad.");

			throw new ResourceNotFoundException(
					"Se presentaron errores al validar la entidad");

		}

		// throw new Exception("esto es una prueba");

	}

	@Override()
	public List<Entidad> advancedSearchAll(Entidad entidad, List<Grupo> grupos,
			List<Etiqueta> etiquetas, Date fechaDesde, Date fechaHasta,
			Pagination pagination, String tiporb) {
		return this.entidadDao.advancedSearchAll(entidad, grupos, etiquetas,
				fechaDesde, fechaHasta, pagination, tiporb);
	}

}
