package es.uv.saic.web;

import java.io.IOException;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Year;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;

import static java.util.Comparator.comparing;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import jakarta.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.DeleteMapping;
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.ResponseBody;

import es.uv.saic.domain.Calendari;
import es.uv.saic.domain.DummyDataTransfer;
import es.uv.saic.domain.Email;
import es.uv.saic.domain.EvidenciaIndicadorEnquesta;
import es.uv.saic.domain.InstanciaTasca;
import es.uv.saic.domain.Organ;
import es.uv.saic.domain.Plantilla;
import es.uv.saic.domain.Proces;
import es.uv.saic.domain.Rol;
import es.uv.saic.domain.Tipus;
import es.uv.saic.domain.Usuari;
import es.uv.saic.dto.EvidenciaBuscadorDTO;
import es.uv.saic.feign.PlantillaClient;
import es.uv.saic.service.CalendariService;
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.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;



@Controller
public class AjaxController {
	
	@Autowired
	private OrganService os;
	@Autowired
	private UsuariService us;
	@Autowired
	private ProcesService ps;
	@Autowired
	private TascaService tas;
	@Autowired
	private TipusService tps;
	@Autowired
	private RolService rs;
	@Autowired
	private EvidenciaIndicadorEnquestaService eies;
	@Autowired
	private CalendariService cs;
	@Autowired
	private InstanciaService is;
	@Autowired
	private InstanciaTascaService its;
	@Autowired
	private EmailService es;
	@Autowired
	private PlantillaClient plc;
	
	@PostMapping("/ajax/active/centres")
	public String getActiveCentres(Model model, Authentication auth) throws IOException {	
		List<Organ> org_list = this.os.getActiveCentres();
		List<DummyDataTransfer> centres = new ArrayList<DummyDataTransfer>();
		for(Organ or : org_list) {
			DummyDataTransfer c = new DummyDataTransfer();
			c.setText(or.getNomCas());
			c.setText2(or.getNomVal());
			c.setValue(or.getId().getLugar());
			centres.add(c);
		}
		System.out.println(centres);
		model.addAttribute("sup_centers", centres);
		return "components/selector_centres";
	}
	
	@PostMapping("/ajax/active/titulacions")
	public String getActiveTitulationsByCenter(Model model, Authentication auth,
			@RequestParam("centre") Integer centre) throws IOException {	
		List<Organ> org_list = this.os.getTitulacionsByCentre(centre);
		List<DummyDataTransfer> titulacions = new ArrayList<DummyDataTransfer>();
		for(Organ or : org_list) {
			DummyDataTransfer c = new DummyDataTransfer();
			c.setText(or.getNomCas());
			c.setText2(or.getNomVal());
			c.setValue(or.getRuct());
			titulacions.add(c);
		}
		model.addAttribute("sup_orgs", titulacions);
		return "components/selector_titulacions";
	}
	
	// POST que buscar titulaciones que se encuentren asociadas a uno o varios centros
	@PostMapping("/ajax/search/titulations")
	public String getTitulationsByCenter(Model model, Authentication auth,
			@RequestParam(name="centers[]", required=false) List<Integer> centres) throws IOException {	
		if(centres == null) { centres = us.getSupervisableCentres((Usuari) auth.getPrincipal()); }
		List<Organ> org_list = this.os.findTitulacionsByCentre(centres);
		List<DummyDataTransfer> supervisable_cents = new ArrayList<DummyDataTransfer>();
		for(Organ or : org_list) {
			DummyDataTransfer c = new DummyDataTransfer();
			c.setText(or.getNomCas());
			c.setText2(or.getNomVal());
			c.setValue(or.getId().getLugar());
			supervisable_cents.add(c);
		}
		DummyDataTransfer o = new DummyDataTransfer();
		o = new DummyDataTransfer();
		Organ org = os.findByID("T", 1);
		o.setText(org.getNomCas());
		o.setText2(org.getNomVal());
		o.setValue(1);
		supervisable_cents.add(o);
		o = new DummyDataTransfer();
		org = os.findByID("T", 2);
		o.setText(org.getNomCas());
		o.setText2(org.getNomVal());
		o.setValue(2);
		supervisable_cents.add(o);
		o = new DummyDataTransfer();
		org = os.findByID("T", 0);
		o.setText(org.getNomCas());
		o.setText2(org.getNomVal());
		o.setValue(0);
		supervisable_cents.add(o);
		model.addAttribute("sup_orgs", supervisable_cents);
		return "components/selector_titulacions";
	}
	
	// POST que se utiliza para conseguir los cursos a partir de la titulación
	@PostMapping("/ajax/search/years")
	public String getYearsByCenterTitulation(Model model, Authentication auth, 
			@RequestParam(name="centers[]", required=false) List<Integer> centres,
			@RequestParam("titulations[]") List<Integer> titulacions) throws IOException {		
			List<DummyDataTransfer> supervisable_years = new ArrayList<DummyDataTransfer>();
			if(centres == null) { centres = us.getSupervisableCentres((Usuari) auth.getPrincipal()); }
			for(Integer c : ps.getSupervisableCursos(centres, titulacions)) {
				DummyDataTransfer d = new DummyDataTransfer();
				d.setValue(c);
				d.setText(Integer.toString(c-1) + " - " + Integer.toString(c));
				supervisable_years.add(d);
			}
			model.addAttribute("sup_years", supervisable_years);
		return "components/selector_cursos";
	}
	
	// POST que se utiliza para conseguir los procedimiento que se han llevado a cabo por cursos y por titulación
	@PostMapping("/ajax/search/procedures")
	public String getProceduresByCenterTitulationYear(Model model, Authentication auth,
			@RequestParam(name="centers[]", required=false) List<Integer> centres,
			@RequestParam("years[]") List<Integer> cursos,
			@RequestParam("titulations[]") List<Integer> titulacions) throws IOException {	
		List<DummyDataTransfer> supervisable_procedures = new ArrayList<DummyDataTransfer>();
		if(centres == null) { centres = us.getSupervisableCentres((Usuari) auth.getPrincipal()); }
		for(Integer p_id : ps.getSupervisableProcedures((Usuari) auth.getPrincipal(), cursos, centres, titulacions)) {
			DummyDataTransfer d = new DummyDataTransfer();
			Proces p = ps.findByID(p_id);
			d.setText(p.getNomProces());
			d.setText2(p.getNomProces() + " " + p.getTitolCas());
			d.setText3(p.getNomProces() + " " + p.getTitolVal());
			supervisable_procedures.add(d);
		}
		
		Set<String> set = new HashSet<>(supervisable_procedures.size());
		supervisable_procedures.removeIf(p -> !set.add(p.getText()));
		Collections.sort(supervisable_procedures, comparing(DummyDataTransfer::getText));
		model.addAttribute("sup_procs", supervisable_procedures);
		
		return "components/selector_processos";
	}

	// POST para buscar pas evidencias a partir del año, centro y titulación
	@PostMapping("/ajax/search/evidences")
	public String getEvidencesByCenterTitulationYear(Model model, Authentication auth,
			@RequestParam(name="centers[]", required=false) List<Integer> centres,
			@RequestParam("years[]") List<Integer> cursos,
			@RequestParam("titulations[]") List<Integer> titulacions) throws IOException {	
		List<DummyDataTransfer> supervisable_evs = new ArrayList<DummyDataTransfer>();
		List<EvidenciaBuscadorDTO> evs_list = tas.getEvidenciesByCentreTitulacioCurs(centres, titulacions, cursos);		
		for(EvidenciaBuscadorDTO e : evs_list) {
			DummyDataTransfer c = new DummyDataTransfer();
			c.setText(e.getCodiEvidencia());
			c.setText2(e.getNomEvidenciaCas());
			c.setText3(e.getNomEvidenciaVal());
			supervisable_evs.add(c);
		}
		model.addAttribute("sup_evs", supervisable_evs);
		return "components/selector_evidencies";
	}
	
	// POST que recoge toda las titulaciones que contiene un centro para el manager
	@PostMapping("/ajax/search/managers/titulations")
	public String getCenterTitulations(Model model, Authentication auth, 
			@RequestParam("center") Integer centre,
			HttpSession session) {
		List<Organ> sup_titulacions;
		sup_titulacions = this.os.getTitulacionsByCentre(centre);
		model.addAttribute("resp_titulacions", sup_titulacions);
		
		return "components/selector_titulacions_managers";
	}
	
	@PostMapping("/ajax/find/titulations2")
	public String getTitulationsByCenters(Model model, Authentication auth,
			@RequestParam("centers[]") List<Integer> centres, @RequestParam("procedure") Integer idProces) throws IOException {	
		List<DummyDataTransfer> titulations = new ArrayList<DummyDataTransfer>();
		DummyDataTransfer o = new DummyDataTransfer();
		
		if(idProces > 0) {
			Proces p = ps.findByID(idProces);
			if(p.getAmbit().equals("U")) {
				o = new DummyDataTransfer();
				Organ org = os.findByID("T", 0);
				o.setText(org.getNomCas());
				o.setText2(org.getNomVal());
				titulations.add(o);
			}
			else if(p.getAmbit().equals("C")) {
				o = new DummyDataTransfer();
				Organ org = os.findByID("T", 1);
				o.setText(org.getNomCas());
				o.setText2(org.getNomVal());
				o.setValue(1);
				titulations.add(o);
				o = new DummyDataTransfer();
				org = os.findByID("T", 2);
				o.setText(org.getNomCas());
				o.setText2(org.getNomVal());
				o.setValue(2);
				titulations.add(o);
				o = new DummyDataTransfer();
				org = os.findByID("T", 0);
				o.setText(org.getNomCas());
				o.setText2(org.getNomVal());
				o.setValue(0);
				titulations.add(o);
			}
			else if(p.getAmbit().equals("T")) {
				for(Integer centre : centres) {
					List<Organ> org_list = this.os.getTitulacionsByCentre(centre);
					for(Organ or : org_list) {
						DummyDataTransfer c = new DummyDataTransfer();
						c.setText(or.getNomCas());
						c.setText2(or.getNomVal());
						c.setValue(or.getId().getLugar());
						titulations.add(c);
					}
				}	
				Collections.sort(titulations, 
	                    (o1, o2) -> Integer.valueOf(o1.getValue()).compareTo(Integer.valueOf(o2.getValue())));
			}
		}
		else {
			for(Integer centre : centres) {
				List<Organ> org_list = this.os.getTitulacionsByCentre(centre);
				for(Organ or : org_list) {
					DummyDataTransfer c = new DummyDataTransfer();
					c.setText(or.getNomCas());
					c.setText2(or.getNomVal());
					c.setValue(or.getId().getLugar());
					titulations.add(c);
				}
			}	
			Collections.sort(titulations, 
                    (o1, o2) -> Integer.valueOf(o1.getValue()).compareTo(Integer.valueOf(o2.getValue())));
		}
		
		model.addAttribute("sup_orgs", titulations);
		return "components/selector_titulacions";
	}
	
	@PostMapping("/ajax/find/titulations")
	public String getTitulationsByCenter(Model model, Authentication auth,
			@RequestParam("center") Integer centre, @RequestParam("procedure") Integer idProces) throws IOException {	
		Proces p = ps.findByID(idProces);
		List<DummyDataTransfer> titulations = new ArrayList<DummyDataTransfer>();
		DummyDataTransfer o = new DummyDataTransfer();
		
		if(p.getAmbit().equals("U")) {
			o = new DummyDataTransfer();
			Organ org = os.findByID("T", 0);
			o.setText(org.getNomCas());
			o.setText2(org.getNomVal());
			titulations.add(o);
		}
		else if(p.getAmbit().equals("C")) {
			o = new DummyDataTransfer();
			Organ org = os.findByID("T", 1);
			o.setText(org.getNomCas());
			o.setText2(org.getNomVal());
			o.setValue(1);
			titulations.add(o);
			o = new DummyDataTransfer();
			org = os.findByID("T", 2);
			o.setText(org.getNomCas());
			o.setText2(org.getNomVal());
			o.setValue(2);
			titulations.add(o);
			o = new DummyDataTransfer();
			org = os.findByID("T", 0);
			o.setText(org.getNomCas());
			o.setText2(org.getNomVal());
			o.setValue(0);
			titulations.add(o);
		}
		else if(p.getAmbit().equals("T")) {
			o = new DummyDataTransfer();
			o.setText("Todos los grados");
			o.setText2("Tots els graus");
			o.setValue(1);
			titulations.add(o);
			o = new DummyDataTransfer();
			o.setText("Todos los másters");
			o.setText2("Tots els màsters");
			o.setValue(2);
			titulations.add(o);
			o = new DummyDataTransfer();
			o.setText("Todas las titulaciones");
			o.setText2("Totes les titulacions");
			o.setValue(0);
			titulations.add(o);
			List<Organ> org_list = this.os.getTitulacionsByCentre(centre);
			for(Organ or : org_list) {
				DummyDataTransfer c = new DummyDataTransfer();
				c.setText(or.getNomCas());
				c.setText2(or.getNomVal());
				c.setValue(or.getId().getLugar());
				titulations.add(c);
			}
		}
		model.addAttribute("sup_orgs", titulations);
		return "components/selector_titulacions";
	}
	
	@PostMapping("/ajax/get/titulations")
	public String getAllTitulationsByCenter(Model model, Authentication auth, @RequestParam("center") Integer centre) throws IOException {	
		List<DummyDataTransfer> titulations = new ArrayList<DummyDataTransfer>();
		DummyDataTransfer o = new DummyDataTransfer();
		
		o = new DummyDataTransfer();
		o.setText("Todos los grados");
		o.setText2("Tots els graus");
		o.setValue(1);
		titulations.add(o);
		o = new DummyDataTransfer();
		o.setText("Todos los másters");
		o.setText2("Tots els màsters");
		o.setValue(2);
		titulations.add(o);
		o = new DummyDataTransfer();
		o.setText("Todas las titulaciones");
		o.setText2("Totes les titulacions");
		o.setValue(0);
		titulations.add(o);
		List<Organ> org_list = this.os.getTitulacionsByCentre(centre);
		for(Organ or : org_list) {
			DummyDataTransfer c = new DummyDataTransfer();
			c.setText(or.getNomCas());
			c.setText2(or.getNomVal());
			c.setValue(or.getId().getLugar());
			titulations.add(c);
		}
		model.addAttribute("sup_orgs", titulations);
		return "components/selector_titulacions";
	}
	
	// POST para encontrar el centro a partir de los procedimientos
	@PostMapping("/ajax/find/centers")
	public String getAllCentresByAmbit(Model model, Authentication auth, @RequestParam("procedure") Integer idProces) throws IOException {	
		List<DummyDataTransfer> centres = new ArrayList<DummyDataTransfer>();
		if(idProces > 0) {
			Proces p = ps.findByID(idProces);
			if(p.getAmbit().equals("C")) {
				DummyDataTransfer o = new DummyDataTransfer();
				o.setText("Todos los centros");
				o.setText2("Tots els centres");
				o.setValue(0);
				centres.add(o);
			}
		}
		List<Organ> org_list = this.os.getActiveCentres();
		for(Organ or : org_list) {
			DummyDataTransfer c = new DummyDataTransfer();
			c.setText(or.getNomCas());
			c.setText2(or.getNomVal());
			c.setValue(or.getId().getLugar());
			centres.add(c);
		}
		model.addAttribute("sup_centers", centres);
		return "components/selector_centres";
	}
	
	// POST para encontrar un procedimiento concreto
	@PostMapping("/ajax/find/procedure")
	public String findProcedure(Model model, Authentication auth, @RequestParam("procedure") Integer idProces, 
			@RequestParam("action") String action) throws IOException {	
		
		Proces p = new Proces();
		model.addAttribute("action", action);
		List<Tipus> tipus = tps.findAll();
		List<Plantilla> templates = plc.findAll();
		model.addAttribute("tipus", tipus);
		model.addAttribute("templates", templates);
		
		
		if(idProces != 0 && (action.equals("duplicate") || action.equals("edit"))) {
			p = ps.findByID(idProces);
			if(action.equals("duplicate")) {
				p.setVersio(Integer.toString(Integer.parseInt(p.getVersio())+1));
				p.setIdProces(p.getIdProces()+1);
				p.setCursActivacio(Year.now().getValue());
				p.setCursAvaluat(null);
			}
			model.addAttribute("tasks", this.tas.findByProces(idProces));
			model.addAttribute("procedure", p);
			List<Rol> roles = rs.findAssignables();
			model.addAttribute("roles", roles);
			return "components/form_procedure";
		}
		else if(idProces != 0 && action.equals("remove")) {
			p = ps.findByID(idProces);
			model.addAttribute("procedure", p);
			return "components/form_procedure_remove_confirm";
		}
		else {
			model.addAttribute("procedure", p);
			List<Rol> roles = rs.findAssignables();
			model.addAttribute("roles", roles);
			return "components/form_procedure";
		}	
	}	
	
	// POST para encontar las plantillas concretas para cierta titulación, centro o procedimiento
	@PostMapping("/ajax/find/templates")
	public String findTemplates(Model model, Authentication auth, @RequestParam("procedure") Integer idProces, 
			@RequestParam("center") String idCentre, @RequestParam("titulation") String idTitulacio) throws IOException {	
		model.addAttribute("evs", this.tas.getEvidencesByProcedure(idProces));
		model.addAttribute("idCentre", idCentre);
		model.addAttribute("idTitulacio", idTitulacio);
		model.addAttribute("idProces", idProces);
		return "components/templates";
	}
	
	@PostMapping("/ajax/find/template/inds")
	public String findTemplatesInds(Model model, Authentication auth, @RequestParam("procedure") Integer idProces, 
			@RequestParam("center") String idCentre, @RequestParam("titulation") String idTitulacio,
			@RequestParam("ev") String evidencia) throws IOException {	
		
		Proces p = this.ps.findByID(idProces);
		List<EvidenciaIndicadorEnquesta> inds = this.eies.getByProcesEvidencia(p.getNomProces(), evidencia);
		model.addAttribute("inds", inds);
		model.addAttribute("proces", p.getNomProces());
		model.addAttribute("idCentre", idCentre);
		model.addAttribute("idTitulacio", idTitulacio);
		model.addAttribute("evidencia", evidencia);
		
		return "components/form_templates_indicators";
	}
	
	// GET para renderizar el formulario de cración de nueva tarea
	@GetMapping("/ajax/newTask/{i}")
	public String newTaskForm(Model model, Authentication auth, @PathVariable Integer i) throws IOException {	
		List<Rol> roles = rs.findAssignables();
		List<Tipus> tipus = tps.findAll();
		List<Plantilla> templates = plc.findAll();
		model.addAttribute("tipus", tipus);
		model.addAttribute("roles", roles);
		model.addAttribute("i", i);
		model.addAttribute("templates", templates);
		return "components/form_procedure_task";
	}
	
	@GetMapping("/ajax/newUserrole")
	public String newUserRoleForm(Model model, Authentication auth) throws IOException {	
		List<Usuari> users = us.findAll();
		List<Rol> roles = rs.findAll();
		model.addAttribute("users", users);
		model.addAttribute("roles", roles);
		return "components/form_new_manager";
	}
	
	@ResponseBody
	@PostMapping("/ajax/find/template")
	public String findTemplate(Model model, Authentication auth, @RequestParam("id") Integer idPlantilla) throws IOException {	
		Plantilla p = plc.findByID(idPlantilla);
		return p.getText();
	}
	
	// GET para comprobar si una plantilla esta siendo usada
	@ResponseBody
	@GetMapping("/ajax/template/used/{idPlantilla}")
	public int isTemplateUsed(Model model, Authentication auth, @PathVariable("idPlantilla") Integer idPlantilla) throws IOException {	
		Boolean u = plc.isUsed(idPlantilla);
		return u ? 1 : 0;
	}
	
	// POST para crear el form de creación de plantilla
	@PostMapping("/ajax/template/form")
	public String formTemplate(Model model, Authentication auth, @RequestParam("id") Integer idPlantilla,
			@RequestParam("action") String action) throws IOException {	
		if(action.equals("new")) {
			Plantilla p = new Plantilla();
			model.addAttribute("editable", true);
			model.addAttribute("template", p);
			return "components/form_template";
		}
		else if(action.equals("edit")) {
			Plantilla p = plc.findByID(idPlantilla);
			model.addAttribute("editable", false);
			model.addAttribute("template", p);
			return "components/form_template";
		}
		else if(action.equals("duplicate")) {
			Plantilla p = plc.findByID(idPlantilla);
			p.setVersio(p.getVersio()+1);
			model.addAttribute("editable", true);
			model.addAttribute("template", p);
			return "components/form_template";
		}
		
		return "";
	}
	
	// DELETE para eliminar una plantilla concreta
	@DeleteMapping("/ajax/template/form")
	@ResponseBody
	public String formTemplateRemove(Model model, Authentication auth, @RequestParam("id") Integer idPlantilla) throws IOException {	
		if(plc.isUsed(idPlantilla)){
			return "0";
		}
		else {
			Plantilla p = plc.findByID(idPlantilla);
			plc.delete(p);
			return "1";
		}
	
	}
	
	// POST para guadar una de las plantillas
	@ResponseBody
	@PostMapping("/ajax/template/save")
	public String templateSave(Model model, Authentication auth, @RequestParam("id") Integer idPlantilla, @RequestParam("action") String action,
			@RequestParam("text") String text, @RequestParam("codi") String codi, @RequestParam("versio") Integer versio,
			@RequestParam("nomCas") String nomCas, @RequestParam("nomVal") String nomVal, @RequestParam("ambit") String ambit) throws IOException {	
		
		if(action.equals("edit")) {
			Plantilla p = plc.findByID(idPlantilla);
			p.setNomCas(nomCas);
			p.setNomVal(nomVal);
			p.setText(text);
			p.setAmbit(ambit);
			plc.save(p);
			return "1";
		}
		else if(action.equals("duplicate") || action.equals("new")) {
			Plantilla p = new Plantilla();
			Plantilla p2 = plc.findByVersioCodiAmbit(versio, codi, ambit);
			if(p2 != null) {
				return "0";
			}
			p.setCodi(codi);
			p.setVersio(versio);
			p.setNomCas(nomCas);
			p.setNomVal(nomVal);
			p.setText(text);
			p.setAmbit(ambit);
			plc.save(p);
			return "1";
		}
		return "0";
	}
	
	@ResponseBody
	@PostMapping("/ajax/draft/save/{id}")
	public String saveTemplate(Model model, Authentication auth, @PathVariable("id") Integer idPlantilla, 
			@RequestParam("text") String text) throws IOException {	
		Plantilla p = plc.findByID(idPlantilla);
		p.setText(text);
		plc.save(p);
		return "1";
	}
	
	// POST para añadir un evento al calendario
	@ResponseBody
	@PostMapping("/ajax/calendar")
	public Calendari calendarAddEvent(Model model, Authentication auth, @RequestParam("idProces") Integer idProces, 
			@RequestParam("titulacions") List<String> titulacions, @RequestParam("centres") List<String> centres, 
			@RequestParam("data") String data, @RequestParam("instancia") Optional<Integer> instancia) throws IOException, ParseException {	
		
		Date d = new SimpleDateFormat("dd/MM/yyyy").parse(data);
		String dstr = new SimpleDateFormat("yyyy-MM-dd").format(d);
		Proces p = this.ps.findByID(idProces);
		Calendari c = new Calendari();
		c.setIdProces(p.getIdProces());
		c.setData(d);
		c.setDataStr(dstr);
		c.setTitolCas(p.getNomProces() + " " + p.getTitolCas());
		c.setTitolVal(p.getNomProces() + " " + p.getTitolVal());
		c.setAmbit(p.getAmbit());
		c.setTipus(1);
		c.setColor(p.getAmbit().equals("C")  ? "aquamarine" : "dodgerblue");
		c.setStatus("P");
		if(instancia.isPresent()) {
			Calendari cold = cs.findById(instancia.get());
			c.setCentres(cold.getCentres());
			c.setTitulacions(cold.getTitulacions());
		}
		else {
			c.setCentres(centres.toString());
			c.setTitulacions(titulacions.toString());
		}
		
		c = cs.save(c);
		
		return c;
	}
	
	// POST que actualiza el evento ddel calendario
	@ResponseBody
	@PostMapping("/ajax/calendar/{id}")
	public Calendari calendarAddEvent(Model model, Authentication auth, @PathVariable("id") Integer id, 
			@RequestParam("idProces") Integer idProces, @RequestParam("titulacions") List<String> titulacions, 
			@RequestParam("centres") List<String> centres, @RequestParam("data") String data) throws IOException, ParseException {	
		
		Calendari c = cs.findById(id);
		Date d = new SimpleDateFormat("dd/MM/yyyy").parse(data);
		String dstr = new SimpleDateFormat("yyyy-MM-dd").format(d);
		Proces p = this.ps.findByID(idProces);
		c.setIdProces(p.getIdProces());
		c.setData(d);
		c.setDataStr(dstr);
		c.setCentres(centres.toString());
		c.setTitulacions(titulacions.toString());
		c.setTitolCas(p.getNomProces() + " " + p.getTitolCas());
		c.setTitolVal(p.getNomProces() + " " + p.getTitolVal());
		c.setAmbit(p.getAmbit());
		c.setColor(p.getAmbit().equals("C") ? "aquamarine" : "dodgerblue");
		c.setStatus("P");
		
		c = cs.save(c);
		
		return c;
	}
	
	// GET que recoge todos los eventos del calendario
	@ResponseBody
	@GetMapping("/ajax/calendar")
	public List<Calendari> calendarGetEvents(Model model, Authentication auth) throws IOException, ParseException {	
		return cs.getAll();
	}
	
	// DELETE que elimina un evento del calendario
	@ResponseBody
	@DeleteMapping("/ajax/calendar")
	public Integer calendarDeleteEvent(Model model, Authentication auth, @RequestParam("id") Integer id) throws IOException, ParseException {	
		Calendari c = this.cs.findById(id);
		this.cs.delete(c);
		return id;
	}
	

	// POST para instanciar un proceso desde el calendario
	@ResponseBody
	@PostMapping("/ajax/instantiate")
	public List<String> instantiate(Model model, Authentication auth, @RequestParam("id") Integer id,
			@RequestParam("idProces") Integer idProces, @RequestParam("centres") List<Integer> centres,
			@RequestParam("titulacions") List<Integer> titulacions) throws IOException, ParseException {	
		if(!((Usuari)auth.getPrincipal()).isAdmin()) {
			return null;
		}
		
		Calendari cal = cs.findById(id);
		if(!cal.getIdProces().equals(idProces) || !cal.getCentres().equals(centres.toString()) 
				|| !cal.getTitulacions().equals(titulacions.toString())) {
			cal.setCentres(centres.toString());
			cal.setTitulacions(titulacions.toString());
			cal.setIdProces(idProces);
			cs.save(cal);
		}
		
		List<String> log = new ArrayList<String>();
		boolean hasErrors = false;
		
		Proces pr = ps.findByID(idProces);
		
		if(pr.getAmbit().equals("U")) {  // ambit == universitat (U)
			for(Integer idTitulacio : titulacions) {
				BigInteger idInstancia = is.instantiateU(idProces, idTitulacio);
				if(!idInstancia.equals(new BigInteger("0"))) {
					log.add("[OK] "+idInstancia.toString()+" - "+groupedTitToText(idTitulacio));
					InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
					for(Usuari u : us.getInstanceAsignedUsers(idInstancia)) {
						Email email = new Email();
						email.setUsusari(u);
						email.setInstanciaTasca(activa);
						es.addEmail(email);
					}
				}
				else {
					log.add("[ERROR] "+groupedTitToText(idTitulacio));
					hasErrors = true;
				}		
			}
		}
		else if(pr.getAmbit().equals("C")) { // ambit == centre (C)
			for(Integer idCentre : centres) {
				Organ c = os.findByID("C", idCentre);
				for(Integer idTitulacio : titulacions) {
					BigInteger idInstancia = is.instantiateC(idProces, c.getId().getLugar(), idTitulacio);
					if(!idInstancia.equals(new BigInteger("0"))) {
						log.add("[OK] "+idInstancia.toString()+" - "+c.getNomCas() + " -> " + groupedTitToText(idTitulacio));
						InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
						for(Usuari u : us.getInstanceAsignedUsers(idInstancia)) {
							Email email = new Email();
							email.setUsusari(u);
							email.setInstanciaTasca(activa);
							es.addEmail(email);
						}
					}
					else {
						hasErrors = true;
						log.add("[ERROR] "+c.getNomCas() + " -> " + groupedTitToText(idTitulacio));
					}
				}
			}
		}
		else if(pr.getAmbit().equals("T")) { // ambit == titulacio (T)
			for(Integer idTitulacio : titulacions) {
				Organ t = os.findByID("T", idTitulacio);
				BigInteger idInstancia = is.instantiateT(idProces, t.getId().getLugar());
				if(!idInstancia.equals(new BigInteger("0"))) {
					log.add("[OK] "+idInstancia.toString()+" - "+t.getNomCas());
					InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
					for(Usuari u : us.getInstanceAsignedUsers(idInstancia)) {
						Email email = new Email();
						email.setUsusari(u);
						email.setInstanciaTasca(activa);
						es.addEmail(email);
					}
				}
				else {
					hasErrors = true;
					log.add("[ERROR] "+idInstancia.toString()+" - "+t.getNomCas());
				}
			}
		}
		
		if(hasErrors) {
			cal.setStatus("E");
			cal.setColor("indianred");
			cal.setData(new Date(System.currentTimeMillis()));
			cs.save(cal);
		}
		else {
			cal.setStatus("F");
			cal.setColor("lightgreen");
			cal.setData(new Date(System.currentTimeMillis()));
			cs.save(cal);
		}
		
		return log;
	}
	
	private String groupedTitToText(Integer t) {
		if(t == 1) {
			return "Grados";
		}
		else if(t == 2) {
			return "Masters";
		}
		else if(t == 3) {
			return "Doctorados";
		}
		else {
			return "Todas Titulaciones";
		}
	}
	
}
