package com.ejie.ab39a.control;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.ejie.ab39a.constantes.Constantes;
import com.ejie.ab39a.exceptions.ErrorField;
import com.ejie.ab39a.exceptions.ErrorGenericoException;
import com.ejie.ab39a.model.ElementoCombo;
import com.ejie.ab39a.model.Entidades;
import com.ejie.ab39a.model.TecnicosEntidad;
import com.ejie.ab39a.seguridad.UsuarioConectado;
import com.ejie.ab39a.seguridad.UtilSeguridad;
import com.ejie.ab39a.service.EntidadesService;
import com.ejie.ab39a.service.TecnicosEntidadService;
import com.ejie.ab39a.validations.EntidadesValidator;
import com.ejie.x38.control.bind.annotation.RequestJsonBody;
import com.ejie.x38.dto.JQGridRequestDto;
import com.ejie.x38.dto.JQGridResponseDto;
import com.fasterxml.jackson.core.JsonProcessingException;

/**
 * EntidadesController.
 * 
 *  
 */

@Controller
@RequestMapping(value = "/entidades")
public class EntidadesController {

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

    @Autowired
    private EntidadesService entidadesService;

    @Autowired
    private EntidadesValidator entidadesValidation;

    @Autowired
    private TecnicosEntidadService tecnicoEntidadService;

    /*
     * OPERACIONES CRUD (Create, Read, Update, Delete)
     * 
     */

    /**
     * Operacion CRUD Read. Devuelve el bean correspondiente al identificador indicado.
     * 
     * @param codentidad
     *            Integer codigo entidad
     * @return Entidades Objeto correspondiente al identificador indicado.
     */
    @RequestMapping(value = { "/{codentidad}", "/get/{codentidad}" }, method = RequestMethod.GET)
    public @ResponseBody Entidades get(@PathVariable Integer codentidad) {
        Entidades entidades = new Entidades();
        entidades.setCodentidad(codentidad);
        entidades = this.entidadesService.find(entidades);
        EntidadesController.logger.info("[GET - findBy_PK] : Obtener Entidades por PK");
        return entidades;
    }

    /**
     * Devuelve una lista de beans correspondientes a los valores de filtrados indicados en el
     * objeto pasado como parametro.
     *
     * @param filterEntidades
     *            Entidades Objeto que contiene los parametros de filtrado utilizados en la
     *            busqueda.
     * @return List<Entidades> Lista de objetos correspondientes a la busqueda realizada.
     */
    @RequestMapping(method = RequestMethod.GET)
    public @ResponseBody List<Entidades> getAll(@ModelAttribute Entidades filterEntidades) {
        EntidadesController.logger.info("[GET - find_ALL] : Obtener Entidades por filtro");
        return this.entidadesService.findAll(filterEntidades, null);
    }

    /**
     * lista de tipos de situacion
     * 
     * @return List<TiposReceptores> Lista de objetos correspondientes a la busqueda realizada.
     */
    @RequestMapping(value = "getInformacion", method = RequestMethod.GET)
    public @ResponseBody List<ElementoCombo> getInformacion() {
        EntidadesController.logger.info("[GET - find_ALL] : Obtener Solicitar informacion por filtro");
        List<ElementoCombo> lista = new ArrayList<ElementoCombo>();
        lista.add(new ElementoCombo(Constantes.BILINGUECOD, Constantes.BILINGUE, Constantes.BILINGUE_EU));
        lista.add(new ElementoCombo(Constantes.EUSKERACOD, Constantes.EUSKERA, Constantes.EUSKERA_EU));
        return lista;
    }

    /**
     * Operacion CRUD Edit. Modificacion del bean indicado.
     *
     * @param entidades
     *            Entidades Bean que contiene la informacion a modificar.
     * @return Entidades Bean resultante de la modificacion.
     */
    @RequestMapping(method = RequestMethod.PUT)
    public @ResponseBody Entidades edit(@RequestBody Entidades entidades) {

        UsuarioConectado usuarioConectado = UtilSeguridad.getUsuarioConectado();
        List<ErrorField> errores = new ArrayList<ErrorField>();
        // Validate
        if (usuarioConectado.isTecnicoEntidad()) {
            errores = this.entidadesValidation.validateTodo(entidades);
            if (!errores.isEmpty()) {
                throw new ErrorGenericoException(errores);
            }
        } else {
            errores = this.entidadesValidation.validate(entidades);
            if (!errores.isEmpty()) {
                throw new ErrorGenericoException(errores);
            }
        }

        if (entidades != null && entidades.getTecnicosEntidad() != null
                && entidades.getTecnicosEntidad().getCodtecnico() == 0) {
            entidades.getTecnicosEntidad().setCodtecnico(null);
        }

        Entidades entidadesAux = this.entidadesService.update(entidades);

        if (usuarioConectado.isTecnicoEntidad()) {

            TecnicosEntidad tecnicosEntidad = new TecnicosEntidad();
            tecnicosEntidad.setCodtecnico(usuarioConectado.getTecnicosEntidad().getCodtecnico());
            Entidades entidades2 = new Entidades();
            entidades2.setTecnicosEntidad(tecnicosEntidad);

            List<Entidades> listaEntidadesDelTecnico = this.entidadesService.findAllLike(entidades2, null, true);
            usuarioConectado.getTecnicosEntidad().setEntidadeses(listaEntidadesDelTecnico);
            try {
                if (usuarioConectado.isEsVerificarRdr()) {
                    usuarioConectado.verificarEntidadesTrabaja();
                }
            } catch (Exception e) {
                errores.add(new ErrorField("error.aplicacion"));
                throw new ErrorGenericoException(errores);
            }
            listaEntidadesDelTecnico = UtilSeguridad
                    .listaEntidadesDatosNoInformados(usuarioConectado.getTecnicosEntidad().getEntidadeses());

            if (listaEntidadesDelTecnico == null || listaEntidadesDelTecnico.isEmpty()) {
                usuarioConectado.setRellenarDatosIncompletos(false);
                entidadesAux.setDatosCompletos(true);
            }
        }

        EntidadesController.logger.info("[PUT] : Entidades actualizado correctamente");
        return entidadesAux;
    }

    /**
     * Operacion CRUD Create. Creacion de un nuevo registro a partir del bean indicado.
     *
     * @param entidades
     *            Entidades Bean que contiene la informacion con la que se va a crear el nuevo
     *            registro.
     * @return Entidades Bean resultante del proceso de creacion.7
     */
    @RequestMapping(method = RequestMethod.POST)
    public @ResponseBody Entidades add(@RequestBody Entidades entidades) {
        // Validate
        List<ErrorField> errores = this.entidadesValidation.validate(entidades);
        if (!errores.isEmpty()) {
            throw new ErrorGenericoException(errores);
        }
        Entidades entidadesAux = this.entidadesService.add(entidades);
        EntidadesController.logger.info("[POST] : Entidades insertado correctamente");
        return entidadesAux;
    }

    /**
     * Operacion CRUD Delete. Borrado del registro correspondiente al identificador especificado.
     *
     * @param entidades
     *            Entidades Identificador del objeto que se desea eliminar.
     * @return Entidades Bean eliminado.
     */
    @RequestMapping(value = "/remove", method = RequestMethod.POST)
    @ResponseStatus(value = HttpStatus.OK)
    public @ResponseBody Entidades remove(@RequestBody Entidades entidades) {
        // Entidades entidades = new Entidades();
        // entidades.setCodentidad(codentidad);
        this.entidadesService.remove(entidades);
        EntidadesController.logger.info("[DELETE] : Entidades borrado correctamente");
        return entidades;
    }

    /**
     * asociar tecnicos
     * 
     * @param model
     *            Model model
     * @return String String
     * @throws JsonProcessingException
     *             exception e
     */
    @RequestMapping(value = "/asociarTecnico/{entidad}", method = RequestMethod.GET)
    public String asociarTecnico(Model model, @PathVariable Integer entidad) throws JsonProcessingException {
        EntidadesController.logger.info("[GET - View] : asociarTecnico");

        model.addAttribute("entidad", entidad);
        return "asociarTecnico";
    }

    /*
     * METODOS COMPONENTE RUP_TABLE
     * 
     */

    /**
     * Metodo de presentacion del RUP_TABLE.
     * 
     * @param model
     *            Model model
     * 
     * @return String carga inicial
     */
    @RequestMapping(value = "/maint", method = RequestMethod.GET)
    public String getFormEdit(Model model/* Locale locale */) {
        EntidadesController.logger.info("[GET - View] : entidades");

        model.addAttribute("isTecnicoEntidad", Boolean.valueOf(UtilSeguridad.getUsuarioConectado().isTecnicoEntidad()));

        return "entidades";
    }

    /**
     * Metodo de presentacion del RUP_TABLE.
     * 
     * @param model
     *            Model model
     * @param codtecnico
     *            Integer codtecnico
     * @return String carga inicial
     */
    @RequestMapping(value = "/maintDetalle/{codtecnico}", method = RequestMethod.GET)
    public String getFormDetalle(Model model, @PathVariable Integer codtecnico) {
        EntidadesController.logger.info("[GET - View] : entidades");

        model.addAttribute("isTecnicoEntidad", Boolean.valueOf(UtilSeguridad.getUsuarioConectado().isTecnicoEntidad()));
        model.addAttribute("idEntidad", codtecnico);
        model.addAttribute("prefijoId", "");
        model.addAttribute("beanNameContenedor", "");

        UsuarioConectado usuario = UtilSeguridad.getUsuarioConectado();
        List<Entidades> entidades = new ArrayList<Entidades>();
        if (usuario != null && usuario.getListaEntidadesNoCompletas() != null
                && !usuario.getListaEntidadesNoCompletas().isEmpty()) {
            entidades = usuario.getListaEntidadesNoCompletas();
        } else {
            TecnicosEntidad tecnicosEntidad = new TecnicosEntidad();
            tecnicosEntidad.setCodtecnico(codtecnico);
            Entidades entidad = new Entidades();
            entidad.setTecnicosEntidad(tecnicosEntidad);
            entidades = this.entidadesService.findAllLike(entidad, null, true);
        }
        if (entidades != null && !entidades.isEmpty()) {
            model.addAttribute("datosEntidad", (Entidades) entidades.get(0));
        } else {
            model.addAttribute("datosEntidad", "");
        }
        return "entidadesDetalle";
    }

    /**
     * Metodo de presentacion del RUP_TABLE.
     * 
     * @param model
     *            Model model
     * @param codtecnico
     *            Integer codtecnico
     * @return String carga inicial
     */
    @RequestMapping(value = "/dialog/{codtecnico}", method = RequestMethod.GET)
    public String getFormEditDialog(Model model/* Locale locale */, @PathVariable Integer codtecnico) {
        EntidadesController.logger.info("[GET - View] : entidades");
        return "entidadesDialog";
    }

    /**
     * guarda los datos de las entidades
     * 
     * @param codEntidad
     *            Integer codEntidad
     * @param email
     *            String email
     * @param numTrab
     *            Integer numTrab
     * @param numTrabH
     *            Integer numTrabH
     * @param numTrabM
     *            Integer numTrabM
     * @param tlfno
     *            String tlfno
     * @return String String
     * @throws ParseException
     *             e e
     */
    @RequestMapping(value = { "/guardarDatos" }, method = RequestMethod.POST)
    public @ResponseBody String guardarDatos(@RequestJsonBody(param = "codEntidad") Integer codEntidad,
            @RequestJsonBody(param = "email") String email, @RequestJsonBody(param = "numTrab") Integer numTrab,
            @RequestJsonBody(param = "numTrabH") Integer numTrabH, @RequestJsonBody(param = "tlfno") String tlfno,
            @RequestJsonBody(param = "numTrabM") Integer numTrabM) throws ParseException {

        Entidades entidad = new Entidades();
        entidad.setCodentidad(codEntidad);
        entidad.setEmail(email);
        entidad.setNumTrabajadores(numTrab);
        entidad.setNumTrabHombre(numTrabH);
        entidad.setNumTrabMujer(numTrabM);
        entidad.setTfno(tlfno);
        List<ErrorField> errores = this.entidadesValidation.validateEntidad(entidad);
        if (!errores.isEmpty()) {
            throw new ErrorGenericoException(errores);
        }

        this.entidadesService.updateEntidad(entidad);

        String retorno = "OK";
        UsuarioConectado usuarioConectado = UtilSeguridad.getUsuarioConectado();
        if (usuarioConectado.isTecnicoEntidad()) {

            TecnicosEntidad tecnicosEntidad = new TecnicosEntidad();
            tecnicosEntidad.setCodtecnico(usuarioConectado.getTecnicosEntidad().getCodtecnico());
            Entidades entidades2 = new Entidades();
            entidades2.setTecnicosEntidad(tecnicosEntidad);

            List<Entidades> listaEntidadesDelTecnico = this.entidadesService.findAllLike(entidades2, null, true);
            usuarioConectado.getTecnicosEntidad().setEntidadeses(listaEntidadesDelTecnico);
            try {
                if (usuarioConectado.isEsVerificarRdr()) {
                    usuarioConectado.verificarEntidadesTrabaja();
                }
            } catch (Exception e) {
                errores.add(new ErrorField("error.aplicacion"));
                throw new ErrorGenericoException(errores);
            }

            listaEntidadesDelTecnico = UtilSeguridad
                    .listaEntidadesDatosNoInformados(usuarioConectado.getTecnicosEntidad().getEntidadeses());

            if (listaEntidadesDelTecnico == null || listaEntidadesDelTecnico.isEmpty()) {
                usuarioConectado.setRellenarDatosIncompletos(false);
                retorno = "OKCOMPLETO";
            }
        }
        EntidadesController.logger.info("[guardarDatos] : datos entidad guardados correctamente:".concat(retorno));
        return retorno;
    }

    /**
     * Operacion de filtrado del componente RUP_TABLE.
     * 
     * @param filterEntidades
     *            Entidades Bean que contiene los parametros de filtrado a emplear.
     * @param jqGridRequestDto
     *            Dto que contiene los parametros de configuracion propios del RUP_TABLE a aplicar
     *            en el filtrado.
     * @param codtecnico
     *            Integer codtecnico
     * @return JQGridResponseDto<Entidades> Dto que contiene el resultado del filtrado realizado por
     *         el componente RUP_TABLE.
     */

    @RequestMapping(value = "/dialog/{codtecnico}/filter", method = RequestMethod.POST)
    public @ResponseBody JQGridResponseDto<Entidades> filterBusq(
            @RequestJsonBody(param = "filter") Entidades filterEntidades,
            @RequestJsonBody JQGridRequestDto jqGridRequestDto, @PathVariable Integer codtecnico) {
        EntidadesController.logger.info("[POST - filter] : Obtener Entidadess");

        TecnicosEntidad tecnicosEntidad = new TecnicosEntidad();
        tecnicosEntidad.setCodtecnico(codtecnico);
        filterEntidades.setTecnicosEntidad(tecnicosEntidad);
        tecnicosEntidad = new TecnicosEntidad();
        tecnicosEntidad.setEntidadesesNoAsociadas(this.entidadesService.findAllLike(filterEntidades, null, true));
        filterEntidades.setTecnicosEntidad(tecnicosEntidad);
        return this.entidadesService.filter(filterEntidades, jqGridRequestDto, false);
    }

    /**
     * Operacion de filtrado del componente RUP_TABLE.
     * 
     * @param filterEntidades
     *            Entidades Bean que contiene los parametros de filtrado a emplear.
     * @param jqGridRequestDto
     *            Dto que contiene los parametros de configuracion propios del RUP_TABLE a aplicar
     *            en el filtrado.
     * @return JQGridResponseDto<Entidades> Dto que contiene el resultado del filtrado realizado por
     *         el componente RUP_TABLE.
     */
    @RequestMapping(value = "/filter", method = RequestMethod.POST)
    public @ResponseBody JQGridResponseDto<Entidades> filter(
            @RequestJsonBody(param = "filter") Entidades filterEntidades,
            @RequestJsonBody JQGridRequestDto jqGridRequestDto) {
        EntidadesController.logger.info("[POST - filter] : Obtener Entidadess");
        UsuarioConectado usuarioConectado = UtilSeguridad.getUsuarioConectado();
        if (usuarioConectado.isTecnicoEntidad()) {
            TecnicosEntidad tecnicosEntidad = new TecnicosEntidad();
            tecnicosEntidad.setCodtecnico(usuarioConectado.getTecnicosEntidad().getCodtecnico());
            tecnicosEntidad.setEntidadeses(usuarioConectado.getTecnicosEntidad().getEntidadeses());
            filterEntidades.setTecnicosEntidad(tecnicosEntidad);
        }

        return this.entidadesService.filter(filterEntidades, jqGridRequestDto, false);
    }

    /**
     * Borrado multiple de registros
     * 
     * @param filterEntidades
     *            Entidades Bean que contiene los parametros de filtrado a emplear.
     * @param jqGridRequestDto
     *            Dto que contiene los parametros de configuracion propios del RUP_TABLE a aplicar
     *            en la busqueda.
     * @return List<String> Lista de los identificadores de los registros eliminados.
     * 
     */
    @RequestMapping(value = "/deleteAll", method = RequestMethod.POST)
    @ResponseStatus(value = HttpStatus.OK)
    public @ResponseBody List<String> removeMultiple(@RequestJsonBody(param = "filter") Entidades filterEntidades,
            @RequestJsonBody JQGridRequestDto jqGridRequestDto) {
        EntidadesController.logger.info("[POST - search] : [POST - removeMultiple] : Eliminar multiples Entidadess");
        this.entidadesService.removeMultiple(filterEntidades, jqGridRequestDto, false);
        EntidadesController.logger.info("All entities correctly deleted!");

        return jqGridRequestDto.getMultiselection().getSelectedIds();
    }

    /**
     * metodo de filtrar
     * 
     * @param filterTecnicosEntidad
     *            TecnicosEntidad filterTecnicosEntidad
     * @param jqGridRequestDto
     *            JQGridRequestDto jqGridRequestDto
     * @param codentidad
     *            Integer codentidad
     * @return JQGridResponseDto<TecnicosEntidad> TecnicosEntidad
     */
    @RequestMapping(value = "/tecnicosEntidad/{codentidad}/filter", method = RequestMethod.POST)
    public @ResponseBody JQGridResponseDto<TecnicosEntidad> filter(
            @RequestJsonBody(param = "filter") TecnicosEntidad filterTecnicosEntidad,
            @RequestJsonBody JQGridRequestDto jqGridRequestDto, @PathVariable Integer codentidad) {
        EntidadesController.logger.info("[POST - filter] : Obtener Tecnicos entidad de Entidades");
        // Entidades entidad = new Entidades();
        // entidad.setCodentidad(codentidad);
        // filterTecnicosEntidad.getEntidadeses().add(entidad);
        filterTecnicosEntidad.setCodentidad(codentidad);
        return this.tecnicoEntidadService.filter(filterTecnicosEntidad, jqGridRequestDto, false);
    }

    /**
     * metodo de filtrar
     * 
     * @param filterTecnicosEntidad
     *            TecnicosEntidad filterTecnicosEntidad
     * @param jqGridRequestDto
     *            JQGridRequestDto jqGridRequestDto
     * @param codentidad
     *            Integer codentidad
     * @return JQGridResponseDto<TecnicosEntidad> TecnicosEntidad
     */
    @RequestMapping(value = "/tecnicosEntidad/{codplane}/{entidad}/{asoc}/filter", method = RequestMethod.POST)
    public @ResponseBody JQGridResponseDto<TecnicosEntidad> filterTecnicos(
            @RequestJsonBody(param = "filter") TecnicosEntidad filterTecnicosEntidad,
            @RequestJsonBody JQGridRequestDto jqGridRequestDto, @PathVariable Integer entidad,
            @PathVariable Integer asoc, @PathVariable Integer codplane) {
        EntidadesController.logger.info("[POST - filter] : Obtener Tecnicos entidad de Entidades");

        filterTecnicosEntidad.setCodentidad(entidad);
        filterTecnicosEntidad.setCodPlane(codplane);
        filterTecnicosEntidad.setAsoc(asoc);
        filterTecnicosEntidad.setBaja(Constantes.NUM_CERO);
        return this.tecnicoEntidadService.filter(filterTecnicosEntidad, jqGridRequestDto, false);
    }

    /**
     * Asociar tecnico al plan estrategico
     * 
     * @param codplane
     *            Integer codplane
     * @param tecnico
     *            Integer tecnico
     * @return String String
     */
    @RequestMapping(value = { "/asociarTecnico" }, method = RequestMethod.POST)
    public @ResponseBody String asociarTecnico(@RequestJsonBody(param = "codplane") Integer codplane,
            @RequestJsonBody(param = "tecnico") Integer tecnico) {

        TecnicosEntidad tecnicoEnt = new TecnicosEntidad();
        tecnicoEnt.setCodPlane(codplane);
        tecnicoEnt.setCodtecnico(tecnico);

        this.tecnicoEntidadService.asociarTecnico(tecnicoEnt);

        EntidadesController.logger.info("[PUT] : asociarTecnico correctamente");
        return "OK";
    }

    /**
     * Desasociar tecnico al plan estrategico
     * 
     * @param codplane
     *            Integer codplane
     * @param tecnico
     *            Integer tecnico
     * @return String String
     */
    @RequestMapping(value = { "/desasociarTecnico" }, method = RequestMethod.POST)
    public @ResponseBody String desasociarTecnico(@RequestJsonBody(param = "codplane") Integer codplane,
            @RequestJsonBody(param = "tecnico") Integer tecnico) {

        TecnicosEntidad tecnicoEnt = new TecnicosEntidad();
        tecnicoEnt.setCodPlane(codplane);
        tecnicoEnt.setCodtecnico(tecnico);

        this.tecnicoEntidadService.desasociarTecnico(tecnicoEnt);

        EntidadesController.logger.info("[PUT] : desasociarTecnico correctamente");
        return "OK";
    }

    /**
     * Establece la entidad principal
     * 
     * @param codentidad
     *            String codentidad
     * @param request
     *            HttpServletRequest request
     * @return String String
     */
    @RequestMapping(value = { "/establecerEntidadPrincipal" }, method = RequestMethod.POST)
    public @ResponseBody String establecerEntidadPrincipal(@RequestBody String codentidad, HttpServletRequest request,
            HttpSession sesion) {

        EntidadesController.logger.info("[POST - establecerEntidadPrincipal] : Inicio Establecer Entidad Principal");

        Entidades entidadPrincipal = new Entidades();
        UsuarioConectado usuarioConectado = UtilSeguridad.getUsuarioConectado();
        for (Entidades entidad : usuarioConectado.getTecnicosEntidad().getEntidadeses()) {
            if (String.valueOf(entidad.getCodentidad()).equals(codentidad)) {
                entidadPrincipal = entidad;
                break;
            }
        }

        request.getSession().setAttribute(Constantes.SESSION_ENTIDAD_PRINCIPAL, entidadPrincipal);

        UtilSeguridad.getUsuarioConectado().setEntidadPrincipal(entidadPrincipal);
        // usuarioConectado.getTecnicosEntidad().setEntidadPrincipal(entidadPrincipal);

        EntidadesController.logger.info("[POST - establecerEntidadPrincipal] : Fin Establecer Entidad Principal");
        return "";
    }

}
