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.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.ContactoDao;
import com.ejie.y42b.model.Contacto;
import com.ejie.y42b.model.Entidad;
import com.ejie.y42b.model.Etiqueta;
import com.ejie.y42b.utils.Y42bUIDGenerator32;
import com.ejie.y42b.utils.Y42bUtils;

/**
 * * ContactoServiceImpl  
 * 
 *  
 */

@Service(value = "contactoService")
public class ContactoServiceImpl implements ContactoService {

	private static final Logger logger = LoggerFactory
			.getLogger(ContactoServiceImpl.class);
	@Autowired()
	private ContactoDao contactoDao;

	@Resource()
	private ReloadableResourceBundleMessageSource appMessageSource;

	/**
	 * Inserts a single row in the Contacto table.
	 * 
	 * @param pContacto
	 *            Contacto
	 * @exception Exception
	 *                Exception
	 * @return Contacto
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Contacto add(Contacto pContacto) throws Exception {

		Contacto contacto = pContacto;
		contacto.setContactoId(Y42bAgendaConstantes.PREFIJO_CONTACTO
				+ Y42bUIDGenerator32.getInstance().generateId());
		contacto.setNombre(Y42bUtils.filtroDB(contacto.getNombre()));
		Date fecultmod = new Date();
		contacto.setFecultmod(fecultmod);

		this.validarDatos(contacto);

		contacto = this.contactoDao.add(contacto);
		return this.contactoDao.addEntidadContacto(contacto);
	}

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

		Contacto contacto = pContacto;
		contacto.setNombre(Y42bUtils.filtroDB(contacto.getNombre()));
		Date fecultmod = new Date();
		contacto.setFecultmod(fecultmod);
		this.validarDatos(contacto);

		// eliminar todas sus etiquetas
		this.contactoDao.removeAllEtiquetasContacto(contacto);
		// añadir las que vengan
		this.contactoDao.addEtiquetaContacto(contacto);

		// eliminar todas sus entidades
		this.contactoDao.removeEntidadContacto(contacto);
		// añadir las que vengan
		this.contactoDao.addEntidadContacto(contacto);

		return this.contactoDao.update(contacto);
	}

	/**
	 * Finds a single row in the Contacto table.
	 * 
	 * @param contacto
	 *            Contacto
	 * @return Contacto
	 */
	public Contacto find(Contacto contacto) {
		return (Contacto) this.contactoDao.find(contacto);
	}

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

	/**
	 * Counts rows in the Contacto table.
	 * 
	 * @param contacto
	 *            Contacto
	 * @return Long
	 */
	public Long findAllCount(Contacto contacto) {
		return this.contactoDao.findAllCount(contacto);
	}

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

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

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

	/**
	 * Inserts a single row in the EntidadContacto table.
	 * 
	 * @param contacto
	 *            Contacto
	 * @return Contacto
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Contacto addEntidadContacto(Contacto contacto) {
		contacto.setContactoId(Y42bAgendaConstantes.PREFIJO_CONTACTO
				+ Y42bUIDGenerator32.getInstance().generateId());
		return this.contactoDao.addEntidadContacto(contacto);
	}

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

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

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

	/**
	 * Getter method for ContactoDao
	 * 
	 * @return ContactoDao
	 */
	public ContactoDao getContactoDao() {
		return this.contactoDao;
	}

	/**
	 * Setter method for ContactoDao.
	 * 
	 * @param contactoDao
	 *            ContactoDao
	 * @return
	 */
	public void setContactoDao(ContactoDao contactoDao) {
		ContactoServiceImpl.logger.info("Setting Dependency " + contactoDao);
		this.contactoDao = contactoDao;
	}

	/**
	 * @param contacto
	 *            Contacto
	 * @param entidades
	 *            List<Entidad>
	 * @param fechaDesde
	 *            Date
	 * @param fechaHasta
	 *            Date
	 * @param pagination
	 *            Paginacion
	 * @return List<Contacto>
	 */
	@Transactional(readOnly = true)
	public List<Contacto> advancedSearch(Contacto contacto,
			List<Entidad> entidades, List<Etiqueta> etiquetas, Date fechaDesde,
			Date fechaHasta, Pagination pagination) {

		return this.contactoDao.advancedSearch(contacto, entidades, etiquetas,
				fechaDesde, fechaHasta, pagination);
	}

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

		// Normalizar valores
		String paisId = Y42bUtils.normalizarCero(contacto.getNoraPaisId());
		String provinciaId = Y42bUtils.normalizarCero(contacto
				.getNoraProvinciaId());
		String municipioId = Y42bUtils.normalizarCero(contacto
				.getNoraMunicipioId());
		if (bNacional) {
			if ("0".equals(provinciaId)) {
				arrErrors.add(this.appMessageSource.getMessage(
						"required.provincia", null, locale));
			}
			if ("0".equals(municipioId)) {
				arrErrors.add(this.appMessageSource.getMessage(
						"required.municipio", null, locale));
			}
		} else {
			if ("0".equals(paisId)) {
				arrErrors.add(this.appMessageSource.getMessage("required.pais",
						null, locale));
			}
		}

		if (arrErrors.size() == 0) {
			ContactoServiceImpl.logger.debug("Contacto valido.");
		} else {
			ContactoServiceImpl.logger
					.debug("Se presentaron errores al validar el contacto.");
			throw new ResourceNotFoundException(
					"Se presentaron errores al validar el contacto.");
		}
	}

	/**
	 * Find a single row in the findEtiquetaContacto Many To Many relationship.
	 * 
	 * @param contacto
	 *            Contacto
	 * @param etiqueta
	 *            Etiqueta
	 * @param pagination
	 *            Pagination
	 * @return Contacto
	 */
	public Contacto findEtiquetaContacto(Contacto contacto, Etiqueta etiqueta,
			Pagination pagination) {
		return this.contactoDao.findEtiquetaContacto(contacto, etiqueta,
				pagination);
	}

	/**
	 * Counts rows in the EtiquetaContacto table.
	 * 
	 * @param contacto
	 *            Contacto
	 * @param etiqueta
	 *            Etiqueta
	 * @return List
	 */
	public Long findEtiquetaContactoCount(Contacto contacto, Etiqueta etiqueta) {
		return this.contactoDao.findEtiquetaContactoCount(contacto, etiqueta);
	}

	/**
	 * Inserts a single row in the EtiquetaContacto table.
	 * 
	 * @param contacto
	 *            Contacto
	 * @return Contacto
	 */
	@Transactional(rollbackFor = Throwable.class)
	public Contacto addEtiquetaContacto(Contacto contacto) {
		return this.contactoDao.addEtiquetaContacto(contacto);
	}

	/**
	 * Deletes a single row in the EtiquetaContacto table.
	 * 
	 * @param contacto
	 *            Contacto
	 */
	@Transactional(rollbackFor = Throwable.class)
	public void removeEtiquetaContacto(Contacto contacto) {
		this.contactoDao.removeEtiquetaContacto(contacto);
	}

}
