package es.uv.saic.web;

import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import es.uv.saic.domain.Acreditacio;
import es.uv.saic.domain.AcreditacioTransfer;
import es.uv.saic.domain.Email;
import es.uv.saic.domain.EvidenciaIndicadorEnquesta;
import es.uv.saic.domain.EvidenciaIndicadorEnquestaPK;
import es.uv.saic.domain.Instancia;
import es.uv.saic.domain.InstanciaTasca;
import es.uv.saic.domain.Organ;
import es.uv.saic.domain.Proces;
import es.uv.saic.domain.Rol;
import es.uv.saic.domain.Tasca;
import es.uv.saic.domain.Usuari;
import es.uv.saic.domain.UsuarisRol;
import es.uv.saic.service.AcreditacioService;
import es.uv.saic.service.EmailService;
import es.uv.saic.service.EvidenciaIndicadorEnquestaService;
import es.uv.saic.service.InstanciaService;
import es.uv.saic.service.InstanciaTascaService;
import es.uv.saic.service.InstanciaTascaVerService;
import es.uv.saic.service.OrganService;
import es.uv.saic.service.ProcesService;
import es.uv.saic.service.RolService;
import es.uv.saic.service.TascaService;
import es.uv.saic.service.TipusService;
import es.uv.saic.service.UsuariService;
import es.uv.saic.service.UsuarisRolService;

@RestController
public class AdminController {

	@Autowired
	private OrganService os;
	@Autowired
	private ProcesService ps;
	@Autowired
	private InstanciaService is;
	@Autowired
	private InstanciaTascaService its;
	@Autowired
	private InstanciaTascaVerService itsver;
	@Autowired
	private UsuariService us;
	@Autowired
	private RolService rs;
	@Autowired
	private UsuarisRolService urs;
	@Autowired
	private TascaService ts;
	@Autowired
	private TipusService tps;
	@Autowired
	private EmailService es;
	@Autowired
	private EvidenciaIndicadorEnquestaService eies;
	@Autowired
	private AcreditacioService as;
	@Value("${saic.data.filePath}")
	private String filePath;
	@Value("${saic.data.templates.filePath}")
	private String templatePath;

	public static final String DDMMYYYY = "dd/MM/yyyy";

	@PostMapping("/admin/instances")
	public HashMap<String, Object> instantiate(@RequestParam("procedure") Integer idProces,
			@RequestParam("center") Integer idCentre,
			@RequestParam("titulation") Integer idTitulacio) {
		HashMap<String, Object> map = new HashMap<>();
		Proces p = ps.findByID(idProces);
		List<String> errorCas = new ArrayList<String>();
		List<String> errorVal = new ArrayList<String>();
		List<String> successCas = new ArrayList<String>();
		List<String> successVal = new ArrayList<String>();

		if (p.getAmbit().equals("U")) { // Type U procedure
			Organ centre = os.findByID("C", idCentre);
			BigInteger idInstancia = is.instantiateU(idProces, idTitulacio);
			if (!idInstancia.equals(BigInteger.valueOf(0))) {
				InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
				for (Usuari u : us.getInstanceAsignedUsers(idInstancia)) {
					Email email = new Email();
					email.setUsusari(u);
					email.setInstanciaTasca(activa);
					es.addEmail(email);
				}
				successCas.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomCas());
				successVal.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomVal());
				map.put("success", true);
			} else {
				errorCas.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomCas());
				errorVal.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomVal());
				map.put("error", true);
			}
		} else if (idTitulacio > 2 && p.getAmbit().equals("T")) { // Type T procedure for one place
			Organ o = os.findByID("T", idTitulacio);
			BigInteger idInstancia = is.instantiateT(idProces, idTitulacio);
			if (!idInstancia.equals(BigInteger.valueOf(0))) {
				InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
				for (Usuari u : us.getInstanceAsignedUsers(idInstancia)) {
					Email email = new Email();
					email.setUsusari(u);
					email.setInstanciaTasca(activa);
					es.addEmail(email);
				}
				successCas.add("Procediment: " + p.getNomProces() + ", Centre: " + o.getOrgan().getNomCas()
						+ ", Titulació: " + o.getNomCas());
				successVal.add("Procediment: " + p.getNomProces() + ", Centre: " + o.getOrgan().getNomVal()
						+ ", Titulació: " + o.getNomVal());
				map.put("success", true);
			} else {
				errorCas.add("Procediment: " + p.getNomProces() + ", Centre: " + o.getOrgan().getNomCas()
						+ ", Titulació: " + o.getNomCas());
				errorVal.add("Procediment: " + p.getNomProces() + ", Centre: " + o.getOrgan().getNomVal()
						+ ", Titulació: " + o.getNomVal());
				map.put("error", true);
			}
		} else if (idTitulacio <= 2 && p.getAmbit().equals("T")) {
			List<Organ> titulacions;
			if (idTitulacio == 0) { // Type T procedure for all active places
				titulacions = os.getTitulacionsByCentre(idCentre);
			} else { // Type T procedure for one whole category place (masters/grados)
				titulacions = os.getTitulacionsByTypeCentre(idCentre, idTitulacio);
			}
			for (Organ o : titulacions) {
				BigInteger idInstancia = is.instantiateT(idProces, o.getId().getLugar());
				if (!idInstancia.equals(BigInteger.valueOf(0))) {
					InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
					for (Usuari u : us.getInstanceAsignedUsers(idInstancia)) {
						Email email = new Email();
						email.setUsusari(u);
						email.setInstanciaTasca(activa);
						es.addEmail(email);
					}
					successCas.add("Procediment: " + p.getNomProces() + ", Centre: " + o.getOrgan().getNomCas()
							+ ", Titulació: " + o.getNomCas());
					successVal.add("Procediment: " + p.getNomProces() + ", Centre: " + o.getOrgan().getNomVal()
							+ ", Titulació: " + o.getNomVal());
				} else {
					errorCas.add("Procediment: " + p.getNomProces() + ", Centre: " + o.getOrgan().getNomCas()
							+ ", Titulació: " + o.getNomCas());
					errorVal.add("Procediment: " + p.getNomProces() + ", Centre: " + o.getOrgan().getNomVal()
							+ ", Titulació: " + o.getNomVal());
				}
			}
		} else if (p.getAmbit().equals("C")) {
			if (idCentre == 0) { // Type C procedure for all active places
				for (Organ centre : os.getActiveCentres()) {
					Organ titulacio = os.findByID("T", idTitulacio);
					BigInteger idInstancia = is.instantiateC(idProces, centre.getId().getLugar(), idTitulacio);
					if (!idInstancia.equals(BigInteger.valueOf(0))) {
						InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
						for (Usuari u : us.getInstanceAsignedUsers(idInstancia)) {
							Email email = new Email();
							email.setUsusari(u);
							email.setInstanciaTasca(activa);
							es.addEmail(email);
						}
						successCas.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomCas()
								+ ", Titulació: " + titulacio.getNomCas());
						successVal.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomVal()
								+ ", Titulació: " + titulacio.getNomVal());
						map.put("success", true);
					} else {
						errorCas.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomCas()
								+ ", Titulació: " + titulacio.getNomCas());
						errorVal.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomVal()
								+ ", Titulació: " + titulacio.getNomVal());
						map.put("error", true);
					}
				}
			} else if (idCentre > 0) { // Type C procedure for one place
				Organ titulacio = os.findByID("T", idTitulacio);
				Organ centre = os.findByID("C", idCentre);
				BigInteger idInstancia = is.instantiateC(idProces, idCentre, idTitulacio);
				if (!idInstancia.equals(BigInteger.valueOf(0))) {
					InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
					for (Usuari u : us.getInstanceAsignedUsers(idInstancia)) {
						Email email = new Email();
						email.setUsusari(u);
						email.setInstanciaTasca(activa);
						es.addEmail(email);
					}
					successCas.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomCas()
							+ ", Titulació: " + titulacio.getNomCas());
					successVal.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomVal()
							+ ", Titulació: " + titulacio.getNomVal());
					map.put("success", true);
				} else {
					errorCas.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomCas()
							+ ", Titulació: " + titulacio.getNomCas());
					errorVal.add("Procediment: " + p.getNomProces() + ", Centre: " + centre.getNomVal()
							+ ", Titulació: " + titulacio.getNomVal());
					map.put("error", true);
				}
			}
		}

		map.put("successCas", successCas);
		map.put("successVal", successVal);
		map.put("errorCas", errorCas);
		map.put("errorVal", errorVal);
		if (errorCas.isEmpty()) {
			map.put("error", true);
		}
		if (successCas.isEmpty()) {
			map.put("success", true);
		}

		return map;
	}

	// POST que elimina una instancia concreta
	@PostMapping("/admin/instance/delete")
	public void deleteInstance(@RequestParam BigInteger idInstancia) throws IOException {

		Instancia instancia = is.findByID(idInstancia);
		List<InstanciaTasca> instanciaTasques = its.findByInstancia(instancia.getIdInstancia());
		for (InstanciaTasca instanciaTasca : instanciaTasques) {
			Files.deleteIfExists(Paths.get(this.filePath + instanciaTasca.getEvidencia()));
		}
		is.deleteInstance(instancia);
	}

	// POST que reinicia una instancia por completo
	@PostMapping("/admin/instance/clear")
	public String clearInstance(@RequestParam BigInteger idInstancia) throws IOException {

		Instancia instancia = is.findByID(idInstancia);
		List<InstanciaTasca> instanciaTasques = its.findByInstancia(instancia.getIdInstancia());
		for (InstanciaTasca instanciaTasca : instanciaTasques) {
			Files.deleteIfExists(Paths.get(this.filePath + instanciaTasca.getEvidencia()));
		}
		is.clearInstance(instancia);
		instancia.setEstat("A");
		is.save(instancia);

		this.itsver.deleteByIdInstancia(idInstancia);

		InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
		if (activa.getTasca().getRol().getNomRol().equals("sys")) {
			activa = this.its.system(activa);
		}

		for (Usuari u : us.getInstanceAsignedUsers(idInstancia)) {
			Email email = new Email();
			email.setUsusari(u);
			email.setInstanciaTasca(activa);
			es.addEmail(email);
		}

		return instancia.getIdInstancia().toString();
	}

	// POST que establece que una instancia ha sido cerrada, cambiandole su estado
	@PostMapping("/admin/instance/close")
	public String closeInstance(@RequestParam BigInteger idInstancia) throws IOException {

		Instancia instancia = is.findByID(idInstancia);
		instancia.setEstat("C");
		InstanciaTasca instanciaTasca = its.findActiveByInstancia(instancia.getIdInstancia());
		instanciaTasca.setEstat(null);
		its.save(instanciaTasca);
		is.save(instancia);

		return instancia.getIdInstancia().toString();
	}

	// POST que se encarga de eliminar una tarea concreta de una instancia
	@PostMapping("/admin/instance/task/remove")
	public String removeTask(@RequestParam BigInteger idInstanciaTasca) throws IOException {

		InstanciaTasca instanciaTasca = its.findById(idInstanciaTasca);
		Files.deleteIfExists(Paths.get(this.filePath + instanciaTasca.getEvidencia()));
		its.remove(instanciaTasca.getIdInstanciaTasca());
		return instanciaTasca.getInstancia().getIdInstancia().toString();
	}

	// POST que se encarga de reiniciar por completo una tarea de una instancia
	@PostMapping("/admin/instance/task/clear")
	public String clearTask(@RequestParam BigInteger idInstanciaTasca) throws IOException {

		InstanciaTasca instanciaTasca = its.findById(idInstanciaTasca);
		Files.deleteIfExists(Paths.get(this.filePath + instanciaTasca.getEvidencia()));
		instanciaTasca.setDataFet(null);
		instanciaTasca.setEvidencia(null);
		instanciaTasca.setUsuari(null);
		instanciaTasca.setEstat(null);
		instanciaTasca.setText(null);
		if (instanciaTasca.getTasca().getRol().getNomRol().equals("sys")) {
			instanciaTasca = this.its.system(instanciaTasca);
		}
		its.save(instanciaTasca);

		return instanciaTasca.getInstancia().getIdInstancia().toString();
	}

	// POST que reinicia una tarea del procedimiento, eliminando datos anteriores y
	// creando una nueva vesión de esta
	@PostMapping("/admin/instance/task/reload")
	public String reloadTask(@RequestParam BigInteger idInstanciaTasca) throws IOException {

		InstanciaTasca instanciaTasca = its.findById(idInstanciaTasca);
		Files.deleteIfExists(Paths.get(this.filePath + instanciaTasca.getEvidencia()));
		InstanciaTasca instanciaTascaNew = new InstanciaTasca();
		instanciaTascaNew.setDataFet(null);
		instanciaTascaNew.setEstat("A");
		instanciaTascaNew.setEvidencia(null);
		instanciaTascaNew.setInstancia(instanciaTasca.getInstancia());
		instanciaTascaNew.setTasca(instanciaTasca.getTasca());
		instanciaTascaNew.setUsuari(null);
		instanciaTascaNew.setText(null);
		instanciaTascaNew.setVersion(0);
		instanciaTascaNew.setIdInstanciaTasca(instanciaTasca.getInstancia().getIdInstancia()
				.multiply(BigInteger.valueOf(10000))
				.add(BigInteger.valueOf(instanciaTasca.getTasca().getIdTascap()))
				.multiply(BigInteger.valueOf(100)));

		/* Editable online revisión - inyectar de quien corresponda */
		if (instanciaTasca.getTasca().getTipus().getTipus() == 15) {
			InstanciaTasca itdone = its.findByInstanciaTascap(instanciaTasca.getInstancia().getIdInstancia(),
					Integer.parseInt(instanciaTasca.getTasca().getOpcions()));
			instanciaTascaNew.setText(itdone.getText());
		}

		its.deactivateAll(instanciaTasca.getInstancia().getIdInstancia());
		its.removeAllVersions(instanciaTasca.getInstancia().getIdInstancia(), instanciaTasca.getTasca().getIdTasca());

		if (instanciaTascaNew.getTasca().getRol().getNomRol().equals("sys")) {
			instanciaTascaNew = this.its.system(instanciaTascaNew);
		}
		its.save(instanciaTascaNew);

		if (!instanciaTasca.getInstancia().getEstat().equals("A")) {
			instanciaTasca.getInstancia().setEstat("A");
			is.save(instanciaTasca.getInstancia());
		}

		for (Usuari u : us.getInstanceAsignedUsers(instanciaTascaNew.getInstancia().getIdInstancia())) {
			Email email = new Email();
			email.setUsusari(u);
			email.setInstanciaTasca(instanciaTascaNew);
			es.addEmail(email);
		}

		return instanciaTasca.getInstancia().getIdInstancia().toString();
	}

	// POST que tiene como objetivo reactivar una tarea
	@PostMapping("/admin/instance/task/reactivate")
	public String activateTask(@RequestParam BigInteger idInstanciaTasca) throws IOException {

		InstanciaTasca instanciaTasca = its.findById(idInstanciaTasca);
		InstanciaTasca instanciaTascaNew = new InstanciaTasca();
		instanciaTascaNew.setDataFet(null);
		instanciaTascaNew.setEstat("A");
		instanciaTascaNew.setEvidencia(null);
		instanciaTascaNew.setInstancia(instanciaTasca.getInstancia());
		instanciaTascaNew.setTasca(instanciaTasca.getTasca());
		instanciaTascaNew.setUsuari(null);
		instanciaTascaNew.setVersion(instanciaTasca.getVersion() + 1);
		instanciaTascaNew.setIdInstanciaTasca(instanciaTasca.getIdInstanciaTasca().add(BigInteger.valueOf(1)));

		its.deactivateAll(instanciaTasca.getInstancia().getIdInstancia());

		/* Editable online revisión - inyectar de quien corresponda */
		if (instanciaTasca.getTasca().getTipus().getTipus() == 15) {
			instanciaTascaNew.setText(instanciaTasca.getText());
		}

		its.save(instanciaTascaNew);

		if (!instanciaTasca.getInstancia().getEstat().equals("A")) {
			instanciaTasca.getInstancia().setEstat("A");
			is.save(instanciaTasca.getInstancia());
		}

		for (Usuari u : us.getInstanceAsignedUsers(instanciaTascaNew.getInstancia().getIdInstancia())) {
			Email email = new Email();
			email.setUsusari(u);
			email.setInstanciaTasca(instanciaTascaNew);
			es.addEmail(email);
		}

		return instanciaTasca.getInstancia().getIdInstancia().toString();
	}

	// POST que edita la información de una tarea ya existente
	@PostMapping("/admin/instance/task/edit")
	public String editTask(@RequestParam BigInteger idInstanciaTasca) throws IOException {

		InstanciaTasca instanciaTasca = its.findById(idInstanciaTasca);
		InstanciaTasca instanciaTascaNew = new InstanciaTasca();
		instanciaTascaNew.setDataFet(null);
		instanciaTascaNew.setEstat("A");
		instanciaTascaNew.setEvidencia(null);
		instanciaTascaNew.setInstancia(instanciaTasca.getInstancia());
		instanciaTascaNew.setTasca(instanciaTasca.getTasca());
		instanciaTascaNew.setUsuari(null);
		instanciaTascaNew.setVersion(instanciaTasca.getVersion() + 1);
		instanciaTascaNew.setIdInstanciaTasca(instanciaTasca.getIdInstanciaTasca().add(BigInteger.valueOf(1)));
		instanciaTascaNew.setText(instanciaTasca.getText());

		its.deactivateAll(instanciaTasca.getInstancia().getIdInstancia());
		its.save(instanciaTascaNew);

		if (!instanciaTasca.getInstancia().getEstat().equals("A")) {
			instanciaTasca.getInstancia().setEstat("A");
			is.save(instanciaTasca.getInstancia());
		}

		for (Usuari u : us.getInstanceAsignedUsers(instanciaTascaNew.getInstancia().getIdInstancia())) {
			Email email = new Email();
			email.setUsusari(u);
			email.setInstanciaTasca(instanciaTascaNew);
			es.addEmail(email);
		}

		return instanciaTasca.getInstancia().getIdInstancia().toString();
	}

	@PostMapping("/admin/mailing")
	public void sendMails(@RequestParam Integer idRol, @RequestParam("centres[]") List<Integer> centres,
			@RequestParam String subject, @RequestParam String body) {
		List<Usuari> usuaris = us.findByRolCentre(idRol, centres);
		for (Usuari usuari : usuaris) {
			Email email = new Email();
			email.setUsusari(usuari);
			email.setBody(body);
			email.setSubject(subject);
			es.addEmail(email);
		}
	}

	// POST para la creación de un procedimiento nuevo
	@PostMapping("/admin/procedures/new")
	public void newProcedure(@RequestParam Map<String, String> params,
			@RequestParam(name = "idTascap[]", required = false) List<String> idTascap,
			@RequestParam(name = "dataLimit[]", required = false) List<String> dataLimit,
			@RequestParam(name = "tipus[]", required = false) List<String> tipus,
			@RequestParam(name = "codiEvidencia[]", required = false) List<String> codiEvidencia,
			@RequestParam(name = "idTascaSeg[]", required = false) List<String> idTascaSeg,
			@RequestParam(name = "idTascaSeg2[]", required = false) List<String> idTascaSeg2,
			@RequestParam(name = "opcions[]", required = false) List<String> opcions,
			@RequestParam(name = "idRol[]", required = false) List<String> idRol,
			@RequestParam(name = "titolCas[]", required = false) List<String> titolCas,
			@RequestParam(name = "titolVal[]", required = false) List<String> titolVal,
			@RequestParam(name = "descripcioCas[]", required = false) List<String> descripcioCas,
			@RequestParam(name = "descripcioVal[]", required = false) List<String> descripcioVal,
			@RequestParam(name = "nomEvidenciaCas[]", required = false) List<String> nomEvidenciaCas,
			@RequestParam(name = "nomEvidenciaVal[]", required = false) List<String> nomEvidenciaVal,
			@RequestParam(name = "idPlantilla[]", required = false) List<String> idPlantilla,
			@RequestParam(name = "informe[]", required = false) List<Boolean> informe)
			throws NumberFormatException, ParseException {

		Proces p = new Proces();
		p.setIdProces(Integer.parseInt(params.get("idProces")));
		p.setNomProces(params.get("nomProces"));
		p.setVersio(params.get("versio"));
		p.setComentaris(params.get("comentaris"));
		p.setSubTitol(params.get("subTitol"));
		p.setAmbit(params.get("ambit"));
		p.setTitolCas(params.get("titolCas").equals(".") ? "" : params.get("titolCas"));
		p.setTitolVal(params.get("titolVal").equals(".") ? "" : params.get("titolVal"));
		p.setDescripcioCas(params.get("descripcioCas").equals(".") ? "" : params.get("descripcioCas"));
		p.setDescripcioVal(params.get("descripcioVal").equals(".") ? "" : params.get("descripcioVal"));
		p.setCursActivacio(Integer.parseInt(params.get("cursActivacio")));
		p.setCursAvaluat(Integer.parseInt(params.get("cursAvaluat")));

		ps.save(p);

		if (idTascaSeg != null) {
			for (Integer i = 0; i < idTascap.size(); i++) {
				Tasca t = new Tasca();
				t.setIdTasca((p.getIdProces() * 10000) + Integer.parseInt(idTascap.get(i)));
				t.setProces(p);
				t.setIdTascap(Integer.parseInt(idTascap.get(i)));
				t.setIdTascaSeg(Integer.parseInt(idTascaSeg.get(i)));
				t.setIdTascaSeg2(idTascaSeg2.get(i).equals(".") ? null : Integer.parseInt(idTascaSeg2.get(i)));
				t.setOpcions(opcions.get(i));
				t.setTitolCas(titolCas.get(i).equals(".") ? "" : titolCas.get(i).replace("[comma]", ","));
				t.setDescripcioCas(
						descripcioCas.get(i).equals(".") ? "" : descripcioCas.get(i).replace("[comma]", ","));
				t.setTitolVal(titolVal.get(i).equals(".") ? "" : titolVal.get(i).replace("[comma]", ","));
				t.setDescripcioVal(
						descripcioVal.get(i).equals(".") ? "" : descripcioVal.get(i).replace("[comma]", ","));
				t.setNomEvidenciaCas(
						nomEvidenciaCas.get(i).equals(".") ? "" : nomEvidenciaCas.get(i).replace("[comma]", ","));
				t.setNomEvidenciaVal(
						nomEvidenciaVal.get(i).equals(".") ? "" : nomEvidenciaVal.get(i).replace("[comma]", ","));
				t.setDataLim(new SimpleDateFormat(DDMMYYYY).parse(dataLimit.get(i)));
				t.setTipus(tps.findOne(Integer.parseInt(tipus.get(i))));
				if (t.getTipus().getTipus() == 11 || t.getTipus().getTipus() == 15) {
					t.setCodiEvidencia(idPlantilla.get(i));
				} else {
					t.setCodiEvidencia(
							codiEvidencia.get(i).equals(".") ? "" : codiEvidencia.get(i).replace("[comma]", ","));
				}

				t.setRol(rs.findOne(Integer.parseInt(idRol.get(i))));
				t.setInforme(informe.get(i));

				ts.save(t);
			}
		}
	}

	// POST para editar un procedimiento ya existente
	@PostMapping("/admin/procedures/edit")
	public void editProcedure(@RequestParam Map<String, String> params,
			@RequestParam(name = "idTascap[]", required = false) List<String> idTascap,
			@RequestParam(name = "dataLimit[]", required = false) List<String> dataLimit,
			@RequestParam(name = "tipus[]", required = false) List<String> tipus,
			@RequestParam(name = "codiEvidencia[]", required = false) List<String> codiEvidencia,
			@RequestParam(name = "idTascaSeg[]", required = false) List<String> idTascaSeg,
			@RequestParam(name = "idTascaSeg2[]", required = false) List<String> idTascaSeg2,
			@RequestParam(name = "opcions[]", required = false) List<String> opcions,
			@RequestParam(name = "idRol[]", required = false) List<String> idRol,
			@RequestParam(name = "titolCas[]", required = false) List<String> titolCas,
			@RequestParam(name = "titolVal[]", required = false) List<String> titolVal,
			@RequestParam(name = "descripcioCas[]", required = false) List<String> descripcioCas,
			@RequestParam(name = "descripcioVal[]", required = false) List<String> descripcioVal,
			@RequestParam(name = "nomEvidenciaCas[]", required = false) List<String> nomEvidenciaCas,
			@RequestParam(name = "nomEvidenciaVal[]", required = false) List<String> nomEvidenciaVal,
			@RequestParam(name = "idPlantilla[]", required = false) List<String> idPlantilla,
			@RequestParam(name = "informe[]", required = false) List<Boolean> informe)
			throws NumberFormatException, ParseException {

		Proces p = ps.findByID(Integer.parseInt(params.get("idProces")));
		p.setNomProces(params.get("nomProces"));
		p.setVersio(params.get("versio"));
		p.setComentaris(params.get("comentaris"));
		p.setSubTitol(params.get("subTitol"));
		p.setAmbit(params.get("ambit"));
		p.setTitolCas(params.get("titolCas").equals(".") ? "" : params.get("titolCas"));
		p.setTitolVal(params.get("titolVal").equals(".") ? "" : params.get("titolVal"));
		p.setDescripcioCas(params.get("descripcioCas").equals(".") ? "" : params.get("descripcioCas"));
		p.setDescripcioVal(params.get("descripcioVal").equals(".") ? "" : params.get("descripcioVal"));
		p.setCursActivacio(Integer.parseInt(params.get("cursActivacio")));
		p.setCursAvaluat(Integer.parseInt(params.get("cursAvaluat")));

		ps.save(p);

		if (idTascaSeg != null) {
			for (Tasca t : ts.findByProces(p.getIdProces())) {
				if (!idTascap.contains(Integer.toString(t.getIdTascap()))) {
					ts.delete(t);
				}
			}

			for (Integer i = 0; i < idTascap.size(); i++) {
				Tasca t;
				try {
					t = ts.getByID((p.getIdProces() * 10000) + Integer.parseInt(idTascap.get(i)));
					if (t == null) {
						t = new Tasca();
						t.setIdTasca((p.getIdProces() * 10000) + Integer.parseInt(idTascap.get(i)));
						t.setProces(p);
						t.setIdTascap(Integer.parseInt(idTascap.get(i)));
					}
				} catch (Exception e) {
					t = new Tasca();
					t.setIdTasca((p.getIdProces() * 10000) + Integer.parseInt(idTascap.get(i)));
					t.setProces(p);
					t.setIdTascap(Integer.parseInt(idTascap.get(i)));
				}

				t.setIdTascaSeg(Integer.parseInt(idTascaSeg.get(i)));
				t.setIdTascaSeg2(idTascaSeg2.get(i).equals(".") ? null : Integer.parseInt(idTascaSeg2.get(i)));
				t.setOpcions(opcions.get(i));
				t.setTitolCas(titolCas.get(i).equals(".") ? "" : titolCas.get(i).replace("[comma]", ","));
				t.setDescripcioCas(
						descripcioCas.get(i).equals(".") ? "" : descripcioCas.get(i).replace("[comma]", ","));
				t.setTitolVal(titolVal.get(i).equals(".") ? "" : titolVal.get(i).replace("[comma]", ","));
				t.setDescripcioVal(
						descripcioVal.get(i).equals(".") ? "" : descripcioVal.get(i).replace("[comma]", ","));
				t.setNomEvidenciaCas(
						nomEvidenciaCas.get(i).equals(".") ? "" : nomEvidenciaCas.get(i).replace("[comma]", ","));
				t.setNomEvidenciaVal(
						nomEvidenciaVal.get(i).equals(".") ? "" : nomEvidenciaVal.get(i).replace("[comma]", ","));
				t.setDataLim(new SimpleDateFormat(DDMMYYYY).parse(dataLimit.get(i)));
				t.setTipus(tps.findOne(Integer.parseInt(tipus.get(i))));
				if (t.getTipus().getTipus() == 11 || t.getTipus().getTipus() == 15) {
					t.setCodiEvidencia(idPlantilla.get(i));
				} else {
					t.setCodiEvidencia(
							codiEvidencia.get(i).equals(".") ? "" : codiEvidencia.get(i).replace("[comma]", ","));
				}
				t.setRol(rs.findOne(Integer.parseInt(idRol.get(i))));
				t.setInforme(informe.get(i));
				ts.save(t);
			}
		}
	}

	// POST que elimina un procedimiento
	@PostMapping("/admin/procedures/remove")
	public void removeProcedure(@RequestParam("idProces") Integer idProces) {
		Proces p = ps.findByID(idProces);
		for (Tasca t : ts.findByProces(p.getIdProces())) {
			ts.delete(t);
		}
		ps.delete(p);
	}

	// POST que le eliminar un usuario concreto del sitema
	@PostMapping("/admin/userrole/remove")
	public HashMap<String, Object> removeUserrole(@RequestParam("idRol") Integer idRol,
			@RequestParam("usuari") String usuari,
			@RequestParam("lugar") Integer lugar, @RequestParam("tlugar") String tlugar) throws IOException {
		HashMap<String, Object> map = new HashMap<>();

		UsuarisRol u = urs.findActive(idRol, usuari, lugar, tlugar);
		if (u != null) {
			u.setVigent(false);
			u.setFin(Calendar.getInstance().getTime());
			urs.save(u);
		}

		List<Integer> respCentres = new ArrayList<Integer>();
		List<Integer> respTitulacions = new ArrayList<Integer>();
		if (tlugar.equals("C")) {
			respCentres.add(lugar);
			map.put("respCentres", respCentres);
			map.put("respTitulacions", respTitulacions);
		} else {
			Organ titulacio = os.findByID(tlugar, lugar);
			respCentres.add(titulacio.getOrgan().getId().getLugar());
			respTitulacions.add(titulacio.getId().getLugar());
			map.put("respCentres", respCentres);
			map.put("respTitulacions", respTitulacions);
		}

		return map;
	}

	// POST para añadir un nuevo usuario al sistema
	@PostMapping("/admin/userrole/new")
	public HashMap<String, Object> newUserrole(@RequestParam("idRol") Integer idRol,
			@RequestParam(name = "usuari", required = false) String usuari, @RequestParam("centre") Integer idCentre,
			@RequestParam(name = "titulacio", required = false) Integer idTitulacio,
			@RequestParam Map<String, String> params) throws IOException {
		HashMap<String, Object> map = new HashMap<>();

		if (usuari == null && params.get("username") != null) {
			Usuari x = new Usuari();
			x.setCognoms(params.get("lastname"));
			x.setNom(params.get("firstname"));
			x.setUsuari(params.get("username"));
			x.setEmail(params.get("email"));
			x.setLdap(true);
			this.us.save(x);
			usuari = x.getUsuari();
		}

		Rol rol = rs.findOne(idRol);
		Integer lugar = null;
		String tlugar = null;
		boolean exists = false;
		if (rol.getAmbit().equals("C")) {
			lugar = idCentre;
			tlugar = "C";
			UsuarisRol u = urs.findLast(idRol, usuari, lugar, tlugar);
			Integer num = urs.findLastNum(idRol, lugar, tlugar);
			num = num == null ? 0 : num;
			if (u != null) {
				if (!u.getVigent()) {
					UsuarisRol r = new UsuarisRol();
					r.setFin(null);
					r.setInici(Calendar.getInstance().getTime());
					r.setUsuari(u.getUsuari());
					r.setOrgan(u.getOrgan());
					r.setRol(u.getRol());
					r.setVigent(true);
					r.setSupervisor(null);
					r.setNum(num + 1);
					r.setIdUsuariRol(Integer.parseInt(Integer.toString(lugar) + (idRol < 10 ? "0" : "")
							+ Integer.toString(idRol) + (num + 1 < 10 ? "0" : "") + Integer.toString(num + 1)));
					urs.save(r);
				} else {
					exists = true;
				}
			} else {
				UsuarisRol r = new UsuarisRol();
				r.setFin(null);
				r.setInici(Calendar.getInstance().getTime());
				r.setUsuari(us.findByUsername(usuari));
				r.setOrgan(os.findByID(tlugar, lugar));
				r.setRol(rs.findOne(idRol));
				r.setVigent(true);
				r.setSupervisor(null);
				r.setNum(num + 1);
				r.setIdUsuariRol(Integer.parseInt(Integer.toString(lugar) + (idRol < 10 ? "0" : "")
						+ Integer.toString(idRol) + (num + 1 < 10 ? "0" : "") + Integer.toString(num + 1)));
				urs.save(r);
			}
		} else {
			tlugar = "T";
			UsuarisRol u = urs.findLast(idRol, usuari, idTitulacio, tlugar);
			Integer num = urs.findLastNum(idRol, idTitulacio, tlugar);
			num = num == null ? 0 : num;
			if (u != null) {
				if (!u.getVigent()) {
					UsuarisRol r = new UsuarisRol();
					r.setFin(null);
					r.setInici(Calendar.getInstance().getTime());
					r.setUsuari(u.getUsuari());
					r.setOrgan(u.getOrgan());
					r.setRol(u.getRol());
					r.setVigent(true);
					r.setSupervisor(null);
					r.setNum(num + 1);
					r.setIdUsuariRol(Integer.parseInt(Integer.toString(idTitulacio) + (idRol < 10 ? "0" : "")
							+ Integer.toString(idRol) + (num + 1 < 10 ? "0" : "") + Integer.toString(num + 1)));
					urs.save(r);
				} else {
					exists = true;
				}
			} else {
				UsuarisRol r = new UsuarisRol();
				r.setFin(null);
				r.setInici(Calendar.getInstance().getTime());
				r.setUsuari(us.findByUsername(usuari));
				r.setOrgan(os.findByID(tlugar, idTitulacio));
				r.setRol(rs.findOne(idRol));
				r.setVigent(true);
				r.setSupervisor(null);
				r.setNum(num + 1);
				r.setIdUsuariRol(Integer.parseInt(Integer.toString(idTitulacio) + (idRol < 10 ? "0" : "")
						+ Integer.toString(idRol) + (num + 1 < 10 ? "0" : "") + Integer.toString(num + 1)));
				urs.save(r);
			}
		}

		List<Integer> respCentres = new ArrayList<Integer>();
		respCentres.add(idCentre);
		map.put("respCentres", respCentres);
		List<Integer> respTitulacions = new ArrayList<Integer>();
		if (idTitulacio != null) {
			respTitulacions.add(idTitulacio);
		}
		map.put("respTitulacions", respTitulacions);

		if (exists) {
			map.put("roleExists", true);
		} else {
			map.put("roleExists", null);
		}

		return map;
	}

	// GET que recoge todas las plantillas actuales del sistema
	@GetMapping("/admin/templates")
	public List<String> getTemplates2() {

		File[] files = Stream.concat(Arrays.stream(new File(this.templatePath).listFiles()),
				Arrays.stream(new File(this.templatePath + "/T1/").listFiles()))
				.toArray(File[]::new);
		files = Stream.concat(Arrays.stream(files),
				Arrays.stream(new File(this.templatePath + "/T2/").listFiles()))
				.distinct()
				.toArray(File[]::new);

		List<String> evs = new ArrayList<String>();
		for (File f : files) {

			String e = f.getName().replace(".docx", "");
			if (f.getPath().contains("/T1/")) {
				e = e + " (G)";
			} else if (f.getPath().contains("/T2/")) {
				e = e + " (M)";
			}

			if (!e.endsWith("_") && !e.contains(".old")) {
				evs.add(e.replace("_", "."));
			}

		}

		return evs;
	}

	// POST que redefine que indicadores están asociados a una evidencia dentro de
	// un proceso
	@PostMapping("/admin/templates/inds/update")
	public void updateTemplateInds(@RequestParam(name = "indicador[]", required = true) List<String> indicador,
			@RequestParam(name = "enquesta[]", required = true) List<String> enquesta,
			@RequestParam(name = "media[]", required = true) List<String> media,
			@RequestParam(name = "evidencia", required = true) String evidencia,
			@RequestParam(name = "proces", required = true) String proces) {

		eies.removeByProcesEvidencia(proces, evidencia);

		for (Integer i = 0; i < indicador.size(); i++) {
			EvidenciaIndicadorEnquesta e = new EvidenciaIndicadorEnquesta();
			EvidenciaIndicadorEnquestaPK eid = new EvidenciaIndicadorEnquestaPK();
			eid.setEnquesta(enquesta.get(i));
			eid.setEvidencia(evidencia);
			eid.setIndicador(indicador.get(i));
			eid.setProces(proces);
			e.setId(eid);
			e.setMedia(media.get(i));
			eies.save(e);
		}
	}

	@GetMapping("/admin/acredita/{curs}/{grup}/{tambit}")
	public List<AcreditacioTransfer> acreditacionsByCurs(@PathVariable Integer curs, @PathVariable Integer grup,
			@PathVariable String tambit) {

		List<AcreditacioTransfer> alist = new ArrayList<AcreditacioTransfer>();

		if (grup == 0) {
			for (Acreditacio a : this.as.getByCurs(curs)) {
				Organ o = os.findByID(a.getTlugar(), a.getLugar());
				alist.add(new AcreditacioTransfer(a, o));
			}
			return alist;
		} else {
			if (tambit.equals("A")) {
				for (Acreditacio a : this.as.getByCursGrup(curs, grup)) {
					Organ o = os.findByID(a.getTlugar(), a.getLugar());
					alist.add(new AcreditacioTransfer(a, o));
				}
			} else {
				for (Acreditacio a : this.as.getByCursGrupTambit(curs, grup, tambit)) {
					Organ o = os.findByID(a.getTlugar(), a.getLugar());
					alist.add(new AcreditacioTransfer(a, o));
				}
			}
			return alist;
		}
	}

	@PostMapping("/admin/acredita")
	public Acreditacio UpdateAcreditacio(@RequestParam String tlugar, @RequestParam Integer lugar,
			@RequestParam Integer grupCurs, @RequestParam Integer grupNum, @RequestParam Integer cursImpla,
			@RequestParam String dataAcred, @RequestParam String dataRenov, @RequestParam String dataSegui,
			@RequestParam String dataVerif, @RequestParam Boolean recom, @RequestParam Boolean segui)
			throws ParseException {

		Acreditacio a = this.as.getById(tlugar, lugar);
		a.setGrupCurs(grupCurs);
		a.setGrupNum(grupNum);
		a.setDataAcred(new SimpleDateFormat(DDMMYYYY).parse(dataAcred));
		a.setDataRenov(new SimpleDateFormat(DDMMYYYY).parse(dataRenov));
		a.setDataSegui(new SimpleDateFormat(DDMMYYYY).parse(dataSegui));
		a.setDataVerif(new SimpleDateFormat(DDMMYYYY).parse(dataVerif));
		a.setCursImpla(cursImpla);
		a.setRecom(recom);
		a.setSegui(segui);
		a = as.save(a);

		return a;
	}

}
