package com.ejie.y42b.control;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import com.ejie.x38.control.exception.ControlException;
import com.ejie.x38.control.exception.MethodFailureException;
import com.ejie.x38.control.exception.ResourceNotFoundException;
import com.ejie.y42b.UserPreferences;
import com.ejie.y42b.constantes.Y42bAgendaConstantes;
import com.ejie.y42b.dao.Y42bGruposDao;
import com.ejie.y42b.model.Entidad;
import com.ejie.y42b.model.Y42bFormGrupo;
import com.ejie.y42b.model.Y42bGrupo;
import com.ejie.y42b.service.EntidadService;
import com.ejie.y42b.service.Y42bGruposService;
import com.ejie.y42b.utils.Y42bUtils;

/**
 * ConsultasServiceImpl  
 * 
 *  
 */

@Controller()
@RequestMapping(value = "/grupos")
@SessionAttributes(value = { "grupoForm" })
public class Y42bGruposController {

	private static final Logger logger = LoggerFactory
			.getLogger(Y42bGruposController.class);

	@Autowired()
	private Y42bGruposService gruposService;

	@Autowired()
	private EntidadService entidadService;

	@Autowired()
	private Properties appConfiguration;

	@Autowired()
	private Y42bGruposDao gruposDao;

	/**
	 * /** Method 'getById'.
	 * 
	 * @param nodeId
	 *            String
	 * @param model
	 *            Model
	 * @param session
	 *            HttpSession
	 * @return String
	 */
	@RequestMapping(value = "mant", method = RequestMethod.GET)
	public ModelAndView getById(
			@RequestParam(value = "nodeId", required = false) String nodeId,
			HttpSession session, Model model) {

		Y42bGruposController.logger.debug("/grupos/mant GET");

		model.addAttribute("defaultLanguage",
				this.appConfiguration.get("y42bVistaWar.default.language"));
		model.addAttribute("defaultLayout",
				this.appConfiguration.get("y42bVistaWar.default.layout"));

		Locale locale = LocaleContextHolder.getLocale();
		String grupoId = this.getGrupoId(nodeId, session);

		Y42bGrupo grupo = new Y42bGrupo();
		grupo.setGrupoId(grupoId);
		grupo = this.gruposService.find(grupo);

		Y42bFormGrupo formGrupo = this.getY42bFormGrupo(grupo, locale);

		model.addAttribute("grupoForm", formGrupo);

		return new ModelAndView("mantenimientos_grupos", "model", model);
	}

	/**
	 * Method 'getCreateForm'.
	 * 
	 * @param model
	 *            Model
	 * @return String
	 */
	@RequestMapping(value = "maintModal", method = RequestMethod.GET)
	public ModelAndView getCreateFormModal(Model model) {
		model.addAttribute("defaultLanguage",
				appConfiguration.get("y42bVistaWar.default.language"));
		model.addAttribute("defaultLayout",
				appConfiguration.get("y42bVistaWar.default.layout"));
		return new ModelAndView("gruposPadreModal", "model", model);
	}

	/**
	 * /** Method 'showGrupoNuevo'.
	 * 
	 * @param session
	 *            HttpSession
	 * @param model
	 *            Model
	 * @return String
	 */
	@RequestMapping(value = "mant_nuevo", method = RequestMethod.GET)
	public ModelAndView showGrupoNuevo(HttpSession session, Model model) {

		Y42bGruposController.logger.debug("/grupos/mant_nuevo GET");

		model.addAttribute("defaultLanguage",
				this.appConfiguration.get("y42bVistaWar.default.language"));
		model.addAttribute("defaultLayout",
				this.appConfiguration.get("y42bVistaWar.default.layout"));

		Y42bFormGrupo formGrupo = new Y42bFormGrupo();
		formGrupo.setGrupoId("0");
		formGrupo.setNombreEs("");
		formGrupo.setNombreEu("");
		formGrupo.setNumEntidadesActivas(0);
		formGrupo.setUsuarioActualizacion("");
		formGrupo.setFechaActualizacion("");
		formGrupo.setPadreId("0");
		formGrupo.setCbopadre("0");

		model.addAttribute("grupoForm", formGrupo);

		return new ModelAndView("mantenimientos_grupos", "model", model);
	}

	/**
	 * Method 'submitGrupo'.
	 * 
	 * @param grupoId
	 *            grupoId
	 * @param padreId
	 *            padreId
	 * @param nombreEs
	 *            nombreEs
	 * @param nombreEu
	 *            nombreEs
	 * @param session
	 *            HttpSession
	 * @param response
	 *            HttpServletResponse
	 * @return String
	 */
	@ResponseBody()
	@RequestMapping(value = "guardar", method = RequestMethod.POST)
	public Y42bFormGrupo submitGrupoValid(
			@RequestParam(value = "grupoId", required = false) String grupoId,
			@RequestParam(value = "padreId", required = false) String padreId,
			@RequestParam(value = "nombreEs", required = false) String nombreEs,
			@RequestParam(value = "nombreEu", required = false) String nombreEu,
			HttpSession session, HttpServletResponse response) {

		Y42bGruposController.logger.debug("controler   /app/mant/grupos");

		UserPreferences userPreferences = (UserPreferences) session
				.getAttribute(Y42bAgendaConstantes.SESSIONBEAN_NODE);
		String usuario = userPreferences.getUserId();

		Locale locale = LocaleContextHolder.getLocale();

		Y42bGrupo grupo = new Y42bGrupo();
		grupo.setGrupoId(grupoId);
		grupo.setNombreEs(Y42bUtils.unescapeHTML(nombreEs, 0));
		grupo.setNombreEu(Y42bUtils.unescapeHTML(nombreEu, 0));
		grupo.setActiva(Y42bAgendaConstantes.SI);
		grupo.setPadreId(padreId);
		grupo.setUsuultmod(usuario);
		grupo.setNivel(new BigDecimal(1));// A ver para que demonios sirve

		try {

			if ("0".equals(grupo.getGrupoId())) {
				grupo = this.gruposService.add(grupo);
			} else {
				grupo = this.gruposService.update(grupo);
			}
			userPreferences.setNodeActive("G_" + grupo.getGrupoId());
			session.setAttribute(Y42bAgendaConstantes.SESSIONBEAN_NODE,
					userPreferences);
			response.setStatus(HttpServletResponse.SC_OK);

		} catch (ResourceNotFoundException er) {
			response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
			throw new ResourceNotFoundException(er.getMessage());

		} catch (Exception e) {
			e.printStackTrace();
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			throw new MethodFailureException("Method failed");

		}

		return this.getY42bFormGrupo(grupo, locale);
	}

	/**
	 * Method 'submitGrupo'.
	 * 
	 * @param id
	 *            String
	 * @param response
	 *            response
	 * @param session
	 *            session
	 * @throws MethodFailureException
	 *             Exception
	 */
	@ResponseBody()
	@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
	public void remove(@PathVariable() String id, HttpServletResponse response,
			HttpSession session) throws MethodFailureException {
		response.setContentType("text/javascript;charset=utf-8");
		response.setHeader("Pragma", "cache");
		response.setHeader("Expires", "0");
		response.setHeader("Cache-Control", "private");

		UserPreferences userPreferences = (UserPreferences) session
				.getAttribute(Y42bAgendaConstantes.SESSIONBEAN_NODE);
		String usuario = userPreferences.getUserId();

		Y42bGrupo grupo = new Y42bGrupo();
		grupo.setGrupoId(id);
		grupo = this.gruposService.findGrupo(grupo);
		grupo.setUsuultmod(usuario);

		try {
			if (this.gruposService.countGruposHijo(grupo) == 0) { // sin grupos
																	// hijo

				Entidad entidadKey = new Entidad();
				entidadKey.setActiva(null);

				// recuperar lista entidades del grupo
				grupo = this.gruposDao
						.findGrupoEntidad(grupo, entidadKey, null);

				List<Entidad> listaEntidades = grupo.getEntidads();

				// eliminar las relaciones de ese grupo con sus entidades
				this.gruposService.removeGrupoEntidad(grupo);
				// eliminar grupo
				this.gruposService.remove(grupo);

				// asociar las entidades de la lista que no esten relacionadas
				// con algun grupo mas con el raiz

				Y42bGrupo grupoAux = new Y42bGrupo();
				grupoAux.setGrupoId(Y42bAgendaConstantes.GRUPO_RAIZ_ID);

				for (Entidad entidadLoop : listaEntidades) {
					String idEntidad = entidadLoop.getEntidadId();

					long contGruposRelacionados = this.gruposService
							.countByEntidadId(idEntidad);
					if (contGruposRelacionados <= 0) {

						// recuperar entidad
						Entidad entidad = new Entidad();
						entidad.setEntidadId(idEntidad);
						entidad = this.entidadService.find(entidad);

						// agregarla a la lista del raiz
						grupoAux.getEntidads().add(entidad);

					}
				}
				this.gruposService.addGrupoEntidad(grupoAux);

				// this.gruposService.remove(grupo);
				userPreferences.setNodeActive(Y42bAgendaConstantes.NODO_RAIZ);
				session.setAttribute(Y42bAgendaConstantes.SESSIONBEAN_NODE,
						userPreferences);
				response.setStatus(HttpServletResponse.SC_OK);
			} else { // con grupos hijo
				Y42bGruposController.logger
						.error("Unable to delete porque tiene hijos" + id);
				response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
				throw new ResourceNotFoundException("hijos");
			}
		} catch (MethodFailureException e) {
			Y42bGruposController.logger.error("Unable to delete " + id);
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
		}

	}

	/**
	 * Method 'unBind' GrupoEntidad
	 * 
	 * @param grupoId
	 *            String
	 * @param entidadEntidadId
	 *            String
	 * @return
	 */
	@RequestMapping(value = "/unbindGrupoEntidad", method = RequestMethod.POST)
	public void unBindGrupoEntidad(
			@RequestParam(value = "grupoId", required = false) String grupoId,
			@RequestParam(value = "entidadId", required = false) String entidadEntidadId) {
		Entidad entidad = new Entidad();
		Y42bGrupo grupo = new Y42bGrupo();
		if (grupoId != null) {
			grupo.setGrupoId(grupoId);
		}
		if (entidadEntidadId != null) {
			entidad.setEntidadId(entidadEntidadId);
		}
		grupo.getEntidads().add(entidad);
		this.gruposService.removeGrupoEntidad(grupo);
		// Comprueba si esta entidad dispone de algún grupo, si no es así lo
		// asigna a grupo raiz (Sin grupo definido) y además lo inactiva
		grupo.setGrupoId(null);
		long grupos_cnt = this.entidadService.findGrupoEntidadCount(entidad,
				grupo);
		if (grupos_cnt == 0) {
			try {
				entidad = this.entidadService.find(entidad);
				entidad.setActiva(Y42bAgendaConstantes.NO);
				this.entidadService.update(entidad);
			} catch (Exception e) {
				throw new MethodFailureException("Method failed");
			}
			grupo.setGrupoId(Y42bAgendaConstantes.GRUPO_RAIZ_ID);
			this.gruposService.addGrupoEntidad(grupo);
		}

	}

	/**
	 * Method 'bind' GrupoEntidad
	 * 
	 * @param grupoId
	 *            String
	 * @param entidadEntidadId
	 *            String
	 */
	@RequestMapping(value = "/bindGrupoEntidad", method = RequestMethod.POST)
	public void bindGrupoEntidad(
			@RequestParam(value = "grupoId", required = false) String grupoId,
			@RequestParam(value = "entidadId", required = false) String entidadEntidadId) {
		Entidad entidad = new Entidad();
		Y42bGrupo grupo = new Y42bGrupo();

		if (grupoId != null) {
			grupo.setGrupoId(grupoId);
		}
		if (entidadEntidadId != null) {
			entidad.setEntidadId(entidadEntidadId);
		}

		grupo.getEntidads().add(entidad);
		this.gruposService.addGrupoEntidad(grupo);
		// Comprueba si esta entidad esta asignada a grupo raiz (Sin grupo
		// definido), y lo elimina
		grupo.setGrupoId(Y42bAgendaConstantes.GRUPO_RAIZ_ID);
		long grupos_cnt = this.gruposService.findGrupoEntidadCount(grupo,
				entidad);
		if (grupos_cnt > 0) {
			try {
				entidad = this.entidadService.find(entidad);
				entidad.setActiva(Y42bAgendaConstantes.SI);
				this.entidadService.update(entidad);
			} catch (Exception e) {
				throw new MethodFailureException("Method failed");
			}

			this.gruposService.removeGrupoEntidad(grupo);
		}
	}

	/**
	 * /** Method 'getPadres'.
	 * 
	 * @param grupoid
	 *            grupoid
	 * @return 'lista de Padres'
	 */
	@RequestMapping(value = "mant/combo/padre", method = RequestMethod.GET)
	public @ResponseBody()
	List<HashMap<String, String>> getPadres(
			@RequestParam(value = "grupoid", required = false) String grupoid) {
		HashMap<String, String> aMap = null;

		List<HashMap<String, String>> lst = new ArrayList<HashMap<String, String>>();

		// Idioma
		Locale locale = LocaleContextHolder.getLocale();
		Y42bGrupo grupo = new Y42bGrupo();
		grupo.setGrupoId(grupoid);

		List<Y42bGrupo> lstGrupos = this.gruposService
				.findGruposPadreAll(grupo);

		for (Y42bGrupo gr : lstGrupos) {
			aMap = new HashMap<String, String>();// NOPMD

			if (Y42bAgendaConstantes.EUSKERA.equals(locale.getLanguage())) {
				aMap.put("label", gr.getNombreEu());
			} else {
				aMap.put("label", gr.getNombreEs());
			}

			aMap.put("value", gr.getGrupoId());
			lst.add(aMap);
		}

		return lst;// this.consultaService.findAll(null, null);

	}

	/**
	 * Method 'handle'.
	 * 
	 * @param e
	 *            ControlException
	 * @return String
	 * 
	 */
	@ExceptionHandler()
	public @ResponseBody()
	String handle(ControlException e) {
		Y42bGruposController.logger.warn(e.getMessage());
		return e.getMessage();
	}

	/**
	 * Method 'getAppConfiguration'.
	 * 
	 * @return appConfiguration
	 * 
	 */
	public Properties getAppConfiguration() {
		return this.appConfiguration;
	}

	/**
	 * Method 'setAppConfiguration'.
	 * 
	 * @param appConfiguration
	 *            Properties
	 * 
	 */
	public void setAppConfiguration(Properties appConfiguration) {
		this.appConfiguration = appConfiguration;
	}

	// METODOS PRIVADOS //

	/**
	 * Obtiene la Id del grupo
	 * 
	 * @param nodeId
	 *            String
	 * @param session
	 *            HttpSession
	 * @return String
	 */
	private String getGrupoId(String nodeId, HttpSession session) {
		// Esquema de nodo G_03#E_02#C_005
		UserPreferences userPreferences = (UserPreferences) session
				.getAttribute(Y42bAgendaConstantes.SESSIONBEAN_NODE);
		String nodos = userPreferences.getNodeActive();
		String grupoId = "";
		if ("".equals(nodeId)) {
			grupoId = (nodos.split("#")[0]).substring(2);
		} else {
			grupoId = (nodeId.split("#")[0]).substring(2);
		}
		return grupoId;
	}

	/**
	 * 
	 * @param grupoBean
	 *            Y42bGrupo
	 * @param locale
	 *            Locale
	 * @return Y42bFormGrupo
	 */
	private Y42bFormGrupo getY42bFormGrupo(Y42bGrupo grupoBean, Locale locale) {
		Y42bFormGrupo formGrupo = new Y42bFormGrupo();

		grupoBean.setActiva(Y42bAgendaConstantes.SI);
		int numEntActivas = this.gruposService.findEntidadesActivas(grupoBean);
		int numEntTotal = this.gruposService
				.findEntidadesHijasTotales(grupoBean);

		formGrupo.setGrupoId(grupoBean.getGrupoId());
		formGrupo.setNombreEs(Y42bUtils.encodeHtmlTag(grupoBean.getNombreEs()));
		formGrupo.setNombreEu(Y42bUtils.encodeHtmlTag(grupoBean.getNombreEu()));
		formGrupo.setNumEntidadesActivas(numEntActivas);
		formGrupo.setNumEntidadesTotal(numEntTotal);
		formGrupo.setFechaActualizacion(Y42bUtils.parseDateToString(
				grupoBean.getFecultmod(), locale.getLanguage()));
		formGrupo.setUsuarioActualizacion(grupoBean.getUsuultmod());
		formGrupo.setPadreId(grupoBean.getPadreId());
		return formGrupo;
	}

	/**
	 * Method 'getByIdGrupo'.
	 * 
	 * @param grupoId
	 *            String
	 * @return Grupo
	 */
	@RequestMapping(value = "/byGrupoId/{grupoId}", method = RequestMethod.GET)
	public @ResponseBody
	Y42bGrupo getByIdGrupo(@PathVariable String grupoId) {
		try {
			Y42bGrupo grupo = new Y42bGrupo();
			grupo.setGrupoId(grupoId);
			grupo = this.gruposService.findGrupo(grupo);
			if (grupo == null) {
				throw new Exception(grupoId.toString());
			}

			return grupo;
		} catch (Exception e) {
			throw new ResourceNotFoundException(grupoId.toString());
		}
	}

	/**
	 * Method 'loadArbolGrupos'.
	 * 
	 * @param envioId
	 *            String
	 * @param model
	 *            Model
	 * @return String
	 */
	@RequestMapping(value = "loadArbolGrupos/{grupoId}", method = RequestMethod.GET)
	public ModelAndView loadArbolGrupos(@PathVariable() String grupoId,
			Model model) {
		Y42bGruposController.logger
				.debug("/loadArbolGrupos GET JUDIT SANTANDER");

		model.addAttribute("defaultLanguage",
				this.appConfiguration.get("y42bVistaWar.default.language"));
		model.addAttribute("defaultLayout",
				this.appConfiguration.get("y42bVistaWar.default.layout"));

		// Y42bFormAccionesMasivas formAccMasivas = new
		// Y42bFormAccionesMasivas();
		// formAccMasivas.setIdEnvio(grupoId);
		// model.addAttribute("accionesForm", formAccMasivas);
		model.addAttribute("idGrupoEliminar", grupoId);
		return new ModelAndView("y42bArbolGrupos", "model", model);
	}

	/**
	 * Method 'changeEntityStatus'.
	 * 
	 * @param envioId
	 *            envioId
	 * @param listaGrupos
	 *            String
	 * @param response
	 *            Response
	 */
	@RequestMapping(value = "/moveEntidadesAGrupo", method = RequestMethod.GET)
	public void changeAsociarEntidadesAGrupo(
			@RequestParam(value = "envioId", required = true) String grupoId,
			@RequestParam(value = "listaGrupos", required = false) String listaGrupos,
			HttpServletResponse response) {

		Y42bGrupo grupo = new Y42bGrupo();
		grupo.setGrupoId(grupoId);
		Entidad entidad = new Entidad();
		grupo = this.gruposService.findGrupoEntidad(grupo, entidad, null);

		if (listaGrupos.equalsIgnoreCase(Y42bAgendaConstantes.GRUPO_RAIZ_ID)) {
			List<Entidad> listaEntidades = grupo.getEntidads();
			Iterator<Entidad> entidadAux = listaEntidades.iterator();

			while (entidadAux.hasNext()) {
				Entidad miEntidad = (Entidad) entidadAux.next();
				long contador = this.gruposService.countByEntidadId(miEntidad
						.getEntidadId());

				Y42bGrupo grupoRoot = new Y42bGrupo();
				List<Entidad> listaEntidadActual = new ArrayList<Entidad>();
				listaEntidadActual.add(miEntidad);

				grupoRoot.setGrupoId(Y42bAgendaConstantes.GRUPO_RAIZ_ID);
				grupoRoot.setEntidads(listaEntidadActual);

				Y42bGrupo grupoPadre = new Y42bGrupo();
				grupoPadre.setGrupoId(grupoId);
				grupoPadre.setEntidads(listaEntidadActual);

				if (contador == 1) {
					this.gruposService.addGrupoEntidad(grupoRoot);
					this.gruposService.removeGrupoEntidad(grupoPadre);
				} else if (contador > 1) {
					this.gruposService.removeGrupoEntidad(grupoPadre);
				}
			}

		} else {
			List<String> lstGrupos = Arrays.asList(listaGrupos
					.split("\\s*,\\s*"));
			for (String idGrupo : lstGrupos) {
				Y42bGrupo grupoNuevo = new Y42bGrupo();
				grupoNuevo.setGrupoId(idGrupo);
				grupoNuevo.setEntidads(grupo.getEntidads());
				this.gruposService.removeGrupoEntidad(grupoNuevo);
				this.gruposService.addGrupoEntidad(grupoNuevo);
			}
		}

		this.gruposService.removeGrupoEntidad(grupo);
		this.gruposService.remove(grupo);
		response.setStatus(HttpServletResponse.SC_OK);
	}

	/**
	 * Method 'countChildren'.
	 * 
	 * @param grupoId
	 *            String
	 * @return long
	 */

	@RequestMapping(value = "/comprobarHijos/{grupoId}", method = RequestMethod.GET)
	public @ResponseBody()
	long countChildren(@PathVariable() String grupoId) {

		Y42bGrupo grupo = new Y42bGrupo();
		grupo.setGrupoId(grupoId);
		grupo = this.gruposService.findGrupo(grupo);

		return this.gruposService.countGruposHijo(grupo);
	}

}