package com.ejie.u74a.control;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.ejie.u74a.exception.AjaxTimeoutException;
import com.ejie.u74a.model.FormaEnvio;
import com.ejie.u74a.model.Idioma;
import com.ejie.u74a.model.TipoMaterial;
import com.ejie.u74a.model.UsuarioDetalles;
import com.ejie.u74a.service.FormaEnvioService;
import com.ejie.u74a.service.IdiomaService;
import com.ejie.u74a.service.TipoMaterialService;
import com.ejie.u74a.util.Utilidades;

/**
 * Controlador principal
 * 
 *  
 */
@Controller()
public class MainController {

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

	@Autowired()
	private TipoMaterialService tipoMaterialService;

	@Autowired()
	private IdiomaService idiomaService;

	@Autowired()
	private FormaEnvioService formaEnvioService;

	/**
	 * Página de inicio.
	 * 
	 * @param model Modelo
	 * @param usuario Detalles del usuario autenticado
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String index(Map<String, Object> model, @AuthenticationPrincipal() UsuarioDetalles usuario) {
		logger.debug("Usuario: {}", Utilidades.getDetallesUsuario());

		logger.debug("Usuario por parámetro: {}", usuario);

		return "welcome";
	}

	/**
	 * Página de solicitud de folletos
	 * 
	 * @param model Modelo
	 * @param locale Locale actual
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/usuario/solicitudFolletos", method = RequestMethod.GET)
	public String solicitudFolletosPage(ModelMap model, Locale locale) {
		logger.debug("solicitudFolletosPage");
		logger.debug("Usuario: {}", Utilidades.getDetallesUsuario());

		// Opción seleccionada en el menú
		model.addAttribute("solicitud", true);

		// Carga de combos del formulario

		// Carga de los Tipos de Material
		List<TipoMaterial> tiposMaterial = this.tipoMaterialService.findAll();
		LinkedHashMap<Integer, String> tiposMaterialSelect = new LinkedHashMap<Integer, String>();

		for (TipoMaterial tipoMaterial : tiposMaterial) {
			tiposMaterialSelect.put(Integer.valueOf(tipoMaterial.getCodigo()), tipoMaterial.getAbreviatura(locale)
					+ " - " + tipoMaterial.getNombre(locale));
		}

		model.addAttribute("tipoMaterial", "");
		model.addAttribute("tiposMaterial", tiposMaterialSelect);

		// Carga de los Idiomas
		List<Idioma> idiomas = this.idiomaService.findAll();
		LinkedHashMap<String, String> idiomasSelect = new LinkedHashMap<String, String>();

		for (Idioma idioma : idiomas) {
			idiomasSelect.put(idioma.getCodigo(), idioma.getNombre(locale));
		}

		model.addAttribute("idioma", "");
		model.addAttribute("idiomas", idiomasSelect);

		// Carga de las formas de envío
		List<FormaEnvio> formasEnvioLst = this.formaEnvioService.findAll();
		LinkedHashMap<Integer, String> formasEnvioSelect = new LinkedHashMap<Integer, String>();

		for (FormaEnvio formaEnvio : formasEnvioLst) {
			formasEnvioSelect.put(Integer.valueOf(formaEnvio.getCodigoFormaEnvio()), formaEnvio.getNombre(locale));
		}
		model.addAttribute("formaEnvio", "");
		model.addAttribute("formasEnvio", formasEnvioSelect);

		return "solicitudFolletos";
	}

	/**
	 * Página de gestión del catálogo general.
	 * 
	 * @param model Modelo
	 * @param locale Locale actual
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/gestion/catalogoGeneral", method = RequestMethod.GET)
	public String catalogoGeneralPage(ModelMap model, Locale locale) {
		logger.debug("catalogoGeneralPage");
		logger.debug("Usuario: {}", Utilidades.getDetallesUsuario());

		model.addAttribute("user", Utilidades.getDetallesUsuario());

		// Opción seleccionada en el menú
		model.addAttribute("catalogo", true);

		// Carga de combos del formulario

		// Carga de los Tipos de Material
		List<TipoMaterial> tiposMaterial = this.tipoMaterialService.findAll();
		LinkedHashMap<Integer, String> tiposMaterialSelect = new LinkedHashMap<Integer, String>();

		for (TipoMaterial tipoMaterial : tiposMaterial) {
			tiposMaterialSelect.put(Integer.valueOf(tipoMaterial.getCodigo()), tipoMaterial.getAbreviatura(locale)
					+ " - " + tipoMaterial.getNombre(locale));
		}

		model.addAttribute("tipoMaterial", "");
		model.addAttribute("tiposMaterial", tiposMaterialSelect);

		// Carga de los Idiomas
		List<Idioma> idiomas = this.idiomaService.findAll();
		LinkedHashMap<String, String> idiomasSelect = new LinkedHashMap<String, String>();

		for (Idioma idioma : idiomas) {
			idiomasSelect.put(idioma.getCodigo(), idioma.getNombre(locale));
		}

		model.addAttribute("idioma", "");
		model.addAttribute("idiomas", idiomasSelect);

		// Carga de las formas de envío
		List<FormaEnvio> formasEnvioLst = this.formaEnvioService.findAll();
		LinkedHashMap<Integer, String> formasEnvioSelect = new LinkedHashMap<Integer, String>();

		for (FormaEnvio formaEnvio : formasEnvioLst) {
			formasEnvioSelect.put(Integer.valueOf(formaEnvio.getCodigoFormaEnvio()), formaEnvio.getNombre(locale));
		}
		model.addAttribute("formaEnvio", "");
		model.addAttribute("formasEnvio", formasEnvioSelect);

		return "catalogoGeneral";
	}

	/**
	 * Página de gestión de solicitudes recibidas.
	 * 
	 * @param model Modelo
	 * @param locale Locale actual
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/gestion/solicitudesRecibidas", method = RequestMethod.GET)
	public String solicitudesRecibidasPage(ModelMap model, Locale locale) {
		logger.debug("solicitudesRecibidasPage");
		logger.debug("Usuario: {}", Utilidades.getDetallesUsuario());

		model.addAttribute("user", Utilidades.getDetallesUsuario());

		// Opción seleccionada en el menú
		model.addAttribute("solicitudes", true);

		// Carga de combos del formulario

		// Carga de los Tipos de Material
		List<TipoMaterial> tiposMaterial = this.tipoMaterialService.findAll();
		Map<Integer, String> tiposMaterialSelect = new HashMap<Integer, String>();

		for (TipoMaterial tipoMaterial : tiposMaterial) {
			tiposMaterialSelect.put(Integer.valueOf(tipoMaterial.getCodigo()), tipoMaterial.getAbreviatura(locale)
					+ " - " + tipoMaterial.getNombre(locale));
		}

		model.addAttribute("tipoMaterial", "");
		model.addAttribute("tiposMaterial", tiposMaterialSelect);

		// Carga de los Idiomas
		List<Idioma> idiomas = this.idiomaService.findAll();
		LinkedHashMap<String, String> idiomasSelect = new LinkedHashMap<String, String>();

		for (Idioma idioma : idiomas) {
			idiomasSelect.put(idioma.getCodigo(), idioma.getNombre(locale));
		}

		model.addAttribute("idioma", "");
		model.addAttribute("idiomas", idiomasSelect);

		return "solicitudesRecibidas";
	}

	/**
	 * Página de gestión de stock.
	 * 
	 * @param model Modelo
	 * @param locale Locale actual
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/gestion/gestionStock", method = RequestMethod.GET)
	public String gestionStockPage(ModelMap model, Locale locale) {
		logger.debug("gestionStockPage");
		logger.debug("Usuario: {}", Utilidades.getDetallesUsuario());

		model.addAttribute("user", Utilidades.getDetallesUsuario());

		// Opción seleccionada en el menú
		model.addAttribute("gestion", true);

		// Carga de combos del formulario

		// Carga de los Tipos de Material
		List<TipoMaterial> tiposMaterial = this.tipoMaterialService.findAll();
		Map<Integer, String> tiposMaterialSelect = new HashMap<Integer, String>();

		for (TipoMaterial tipoMaterial : tiposMaterial) {
			tiposMaterialSelect.put(Integer.valueOf(tipoMaterial.getCodigo()), tipoMaterial.getAbreviatura(locale)
					+ " - " + tipoMaterial.getNombre(locale));
		}

		model.addAttribute("tipoMaterial", "");
		model.addAttribute("tiposMaterial", tiposMaterialSelect);

		// Carga de las formas de envío
		List<FormaEnvio> formasEnvioLst = this.formaEnvioService.findAll();
		LinkedHashMap<Integer, String> formasEnvioSelect = new LinkedHashMap<Integer, String>();

		for (FormaEnvio formaEnvio : formasEnvioLst) {
			formasEnvioSelect.put(Integer.valueOf(formaEnvio.getCodigoFormaEnvio()), formaEnvio.getNombre(locale));
		}
		model.addAttribute("formaEnvio", "");
		model.addAttribute("formasEnvio", formasEnvioSelect);

		return "gestionStock";
	}

	/**
	 * Página de consulta de Mis Solicitudes.
	 * 
	 * @param model Modelo
	 * @param locale Locale actual
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/usuario/misSolicitudes", method = RequestMethod.GET)
	public String misSolicitudesPage(ModelMap model, Locale locale) {
		logger.debug("misSolicitudesPage");
		logger.debug("Usuario: {}", Utilidades.getDetallesUsuario());

		model.addAttribute("user", Utilidades.getDetallesUsuario());

		// Opción seleccionada en el menú
		model.addAttribute("misSolicitudes", true);

		// Carga de combos del formulario

		// Carga de los Tipos de Material
		List<TipoMaterial> tiposMaterial = this.tipoMaterialService.findAll();
		Map<Integer, String> tiposMaterialSelect = new HashMap<Integer, String>();

		for (TipoMaterial tipoMaterial : tiposMaterial) {
			tiposMaterialSelect.put(Integer.valueOf(tipoMaterial.getCodigo()), tipoMaterial.getAbreviatura(locale)
					+ " - " + tipoMaterial.getNombre(locale));
		}

		model.addAttribute("tipoMaterial", "");
		model.addAttribute("tiposMaterial", tiposMaterialSelect);

		// Carga de los Idiomas
		List<Idioma> idiomas = this.idiomaService.findAll();
		LinkedHashMap<String, String> idiomasSelect = new LinkedHashMap<String, String>();

		for (Idioma idioma : idiomas) {
			idiomasSelect.put(idioma.getCodigo(), idioma.getNombre(locale));
		}

		model.addAttribute("idioma", "");
		model.addAttribute("idiomas", idiomasSelect);

		return "misSolicitudes";
	}

	/**
	 * Página de mantenimiento de puntos de recepción
	 * 
	 * @param model Modelo
	 * @param locale Locale actual
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/usuario/puntosRecepcion", method = RequestMethod.GET)
	public String puntosRecepcion(ModelMap model, Locale locale) {
		logger.debug("PuntosRecepcionPage");
		logger.debug("Usuario: {}", Utilidades.getDetallesUsuario());

		model.addAttribute("user", Utilidades.getDetallesUsuario());

		return "puntosRecepcion";
	}

	/**
	 * Página de accesso denegado.
	 * 
	 * @param model Modelo
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/accessDenied", method = RequestMethod.GET)
	public String accessDeniedPage(ModelMap model) {
		logger.debug("Usuario: {}", Utilidades.getDetallesUsuario());

		model.addAttribute("user", Utilidades.getDetallesUsuario());
		return "accessDenied";
	}

	/**
	 * Página de login.
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String loginPage() {
		return "login";
	}

	/**
	 * Página de logout.
	 * 
	 * @param request request
	 * @param response response
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/logout", method = RequestMethod.GET)
	public String logoutPage(HttpServletRequest request, HttpServletResponse response) {
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		if (auth != null) {
			new SecurityContextLogoutHandler().logout(request, response, auth);
		}
		return "redirect:/login?logout";
	}

	/**
	 * Página de timeout.
	 * 
	 * @param request request
	 * @param response response
	 * 
	 * @return vista
	 */
	@RequestMapping(value = "/timeout", method = RequestMethod.GET)
	public String timeoutPage(HttpServletRequest request, HttpServletResponse response) {
		logger.debug("Usuario: {}", Utilidades.getDetallesUsuario());

		String ajaxHeader = request.getHeader("X-Requested-With");

		if ("XMLHttpRequest".equals(ajaxHeader)) {
			logger.info("Llamada Ajax detectada, se lanza AjaxTimeoutException");

			Authentication auth = SecurityContextHolder.getContext().getAuthentication();
			if (auth != null) {
				new SecurityContextLogoutHandler().logout(request, response, auth);
			}

			throw new AjaxTimeoutException();
		}

		return "redirect:/login?timeout";
	}

}