package org.gcube.application.geoportal.common.model.legacy;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.gcube.application.geoportal.common.faults.InvalidRequestException;
import org.gcube.application.geoportal.common.model.legacy.report.Check;
import org.gcube.application.geoportal.common.model.legacy.report.ConstraintCheck;
import org.gcube.application.geoportal.common.model.legacy.report.ValidationReport;
import org.gcube.application.geoportal.common.model.legacy.report.ValidationReport.ValidationStatus;
import org.gcube.application.geoportal.common.utils.CollectionsUtils;

import javax.xml.bind.annotation.XmlRootElement;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Getter
@Setter
@ToString(callSuper=true)
@XmlRootElement
public class Concessione extends Record{

	
	//Introduzione (descrizione del progetto)
	private String introduzione;

	//Descrizione del contenuto
	private String descrizioneContenuto;
	
	//Autori	
	private List<String> authors;
	
	//Soggetto che materialmente invia i dati.	
	private String contributore;

	//Indicare il nome del titolare/i dei dati contenuti nel dataset e/o per sue specifiche parti.
	private List<String> titolari;
	
	private String responsabile;
	private String editore;
	
	
	private List<String> fontiFinanziamento;
	
	//Research Excavation; Archaeology  (valori di default)
	
	private List<String> soggetto;

	
	//Referenze bibliografiche, DOI (se esistenti) di risorse correlate all’indagine in oggetto	
	private List<String> risorseCorrelate;

	
	private LocalDateTime dataInizioProgetto;
	private LocalDateTime dataFineProgetto;
	
	private List<String> titolareLicenza;
	private List<String> titolareCopyright;
	
	
	
	private List<String> paroleChiaveLibere;
	
	private List<String> paroleChiaveICCD;
	
	
	private Double centroidLat;
	private Double centroidLong;
	
    private RelazioneScavo relazioneScavo;
	private AbstractRelazione abstractRelazione;

    private List<UploadedImage> immaginiRappresentative=new ArrayList<UploadedImage>();
	
    private LayerConcessione posizionamentoScavo;
	
    private List<LayerConcessione> pianteFineScavo=new ArrayList<>();
	
	private List<OtherContent> genericContent=new ArrayList<>();
	
	
	public Concessione() {
		super();
		setRecordType(RecordType.CONCESSIONE);
	}
		
	
	public static class Paths{
		public final static String RELAZIONE="relazione";
		public final static String POSIZIONAMENTO="posizionamentoScavo";
		public final static String PIANTE="piante";
		public final static String IMMAGINI="immagini";
		public final static String ABSTRACT_RELAZIONE="abstract_relazione";
		public static final String MONGO_ID="mongo_id";
		
		public final static String piantaByIndex(int index) {return makeByIndex(PIANTE,index);};
		public final static String imgByIndex(int index) {return makeByIndex(IMMAGINI,index);};
		
		public final static String piantaById(String id) {return makeByStringField(PIANTE, MONGO_ID, id);};
		public final static String imgById(String id) {return makeByStringField(IMMAGINI, MONGO_ID, id);};
		
		
		
		private static String makeByIndex(String base,int value) {return String.format("%1$s[%2$d]",base,value);}
		private static String makeByStringField(String base,String field,String value) 
			{return String.format("%1$s.%2$s:\"%3$s\"",base,field,value);}

		public static boolean validate(String path) throws InvalidRequestException {
			switch(path) {
				case Paths.RELAZIONE :
				case Paths.POSIZIONAMENTO :
				case Paths.ABSTRACT_RELAZIONE: return true;
			}
			if(path.matches("\\w+\\[\\d+\\]")) {
				// Array section
				return true;
			}
			if(path.matches("\\w+\\.\\w+\\s*\\:\\s*\\\"\\w+\\\"")) {
				// Map section
				return true;
			}
			throw new InvalidRequestException("Invalid Path "+path);
		}
	}
	
	@Override
	public AssociatedContent getContentByPath(String path) {
		switch(path) {
		case Paths.RELAZIONE : return getRelazioneScavo();
		case Paths.POSIZIONAMENTO : return getPosizionamentoScavo();
		case Paths.ABSTRACT_RELAZIONE: return getAbstractRelazione();
		}
		if(path.matches("\\w+\\[\\d+\\]")) {
			// Array section
			String field=path.substring(0,path.lastIndexOf("["));
			Integer index=Integer.parseInt(path.substring(path.lastIndexOf("[")+1,path.lastIndexOf("]")));
			List<? extends AssociatedContent> list=null; 
			switch (field) {
			case Paths.IMMAGINI : list = immaginiRappresentative; break;
			case Paths.PIANTE :  list = pianteFineScavo; break;
			}
			return getByIndex(list,index);
			
		}
		if(path.matches("\\w+\\.\\w+\\s*\\:\\s*\\\"\\w+\\\"")) {
			// Map section
			String field=path.substring(0,path.lastIndexOf("."));
			String subField=path.substring(path.indexOf(".")+1,path.lastIndexOf(":")).trim();
			String value=path.substring(path.indexOf("\"")+1,path.lastIndexOf("\""));
			List<? extends AssociatedContent> list=null; 
			switch (field) {
			case Paths.IMMAGINI : list = immaginiRappresentative; break;
			case Paths.PIANTE :  list = pianteFineScavo; break;
			}
			return getByFieldValue(list, subField, value);
		}
		return null;
	}
	
	private static AssociatedContent getByIndex(List<? extends AssociatedContent> list, int index) {		
		if(list == null )return null;
		return list.get(index);
	}
	
//	 NB only mongo_id is supported in this impl.  
	private static AssociatedContent getByFieldValue(List<? extends AssociatedContent> list, String field, Object value) {
		for(AssociatedContent c: list) {
			switch(field) {
			case Paths.MONGO_ID : {
				if(c.getMongo_id()!=null&&c.getMongo_id().equals(value))
					return c;				
			}
			}
		}
		return null;
	}
	
	
	@Override
	public void setAtPath(AssociatedContent toSet, String path) {
		switch(path) {
		case Paths.RELAZIONE : {
			setRelazioneScavo((RelazioneScavo) toSet);
			break;
		}
		case Paths.POSIZIONAMENTO : {
			setPosizionamentoScavo((LayerConcessione) toSet);
			break;
		}
		case Paths.ABSTRACT_RELAZIONE:{
			setAbstractRelazione((AbstractRelazione)toSet);
			break;
		}
		case Paths.PIANTE : {
			if(pianteFineScavo==null)pianteFineScavo=new ArrayList<LayerConcessione>();
			pianteFineScavo.add((LayerConcessione) toSet);
			break;
		}
		case Paths.IMMAGINI: {
			if(immaginiRappresentative==null)immaginiRappresentative=new ArrayList<UploadedImage>();
			pianteFineScavo.add((LayerConcessione) toSet);
			break;
		}
		
		//TODO MATCH if()case Paths.PIANTa : return 
		//TODO MATCH if()case Paths.Img : return
		}
		
	}
	
	@Override
	public ValidationReport validate() {		
		ValidationReport validator= super.validate();
		
		validator.setObjectName("Concessione");
		
	//	setPolicy(AccessPolicy.OPEN);
		
		
		
		validator.checkMandatory(authors, "Lista Autori");
		if(validator.checkMandatory(centroidLat, "Latitudine"))
			if(centroidLat>90||centroidLat<-90) validator.addMessage(ValidationStatus.ERROR, "Latitudine non valida : "+centroidLat);
		
		if(validator.checkMandatory(centroidLong, "Longitudine"))
			if(centroidLong>180||centroidLong<-180) validator.addMessage(ValidationStatus.ERROR, "Longitudine non valida : "+centroidLong);
		
		validator.checkMandatory(contributore, "Contributore");
		if(validator.checkMandatory(dataFineProgetto, "Data Fine Progetto") &&
				validator.checkMandatory(dataInizioProgetto, "Data Inizio Progetto"))
			if(dataFineProgetto.isBefore(dataInizioProgetto)) validator.addMessage(ValidationStatus.ERROR, "Data Fine Progetto non può esser prima di Data Inizio Progetto.");
		
		validator.checkMandatory(descrizioneContenuto, "Descrizione contenuto");
		validator.checkMandatory(editore, "Editore");
		validator.checkMandatory(fontiFinanziamento, "Fonti Finanaziamento");
		validator.checkMandatory(introduzione, "Introduzione");
		validator.checkMandatory(paroleChiaveICCD, "Parole chiave ICCD");
		validator.checkMandatory(paroleChiaveLibere, "Parole chiave libere");
		
		validator.checkMandatory(responsabile,"Responsabile");

		
		validator.checkMandatory(titolareCopyright, "Titolare Copyright");
		validator.checkMandatory(titolareLicenza,"Titolare licenza");
		validator.checkMandatory(titolari, "Titolari");
		
		
		
		if(validator.checkMandatory(relazioneScavo, "Relazione scavo")) {
			validator.addChild(relazioneScavo.validateForInsertion());
		}

		if(validator.checkMandatory(abstractRelazione,"Abstract Relazione")){
			validator.addChild(abstractRelazione.validateForInsertion());
		}

		if(validator.checkMandatory(posizionamentoScavo, "Posizionamento scavo")) {
			
			ValidationReport posReport=posizionamentoScavo.validateForInsertion();
			posReport.setObjectName("Posizionamento scavo");
			validator.addChild(posReport);
		}

		
		if(genericContent!=null)
			for(OtherContent content:genericContent)
				validator.addChild(content.validateForInsertion());
		
		if(pianteFineScavo!=null)
			for(LayerConcessione l:pianteFineScavo) {
				validator.addChild(l.validateForInsertion());
			}

		return validator;
	}
	
	
	@Override
	public void setDefaults() {		
		super.setDefaults();
		setSoggetto(ConstraintCheck.defaultFor(soggetto, Arrays.asList(new String[] {"Research Excavation","Archaeology"}))
				.addChecks(Check.collectionSizeMin(2)).evaluate());
		
		setDescrizioneContenuto(ConstraintCheck.defaultFor(getDescrizioneContenuto(), 
				"Relazione di fine scavo e relativo abstract; selezione di immagini rappresentative;"
				+ " posizionamento topografico dell'area indagata, pianta di fine scavo.").evaluate());
		
		
		setSoggetto(ConstraintCheck.defaultFor(soggetto, Arrays.asList(new String[] {"Research Excavation","Archaeology"}))
				.addChecks(Check.collectionSizeMin(2)).evaluate());
		
		setLicenzaID(ConstraintCheck.defaultFor(getLicenzaID(), "CC0-1.0").evaluate());
		
		
		if(relazioneScavo == null) relazioneScavo=new RelazioneScavo();

			relazioneScavo.setTitolo(ConstraintCheck.defaultFor(relazioneScavo.getTitolo(),getNome()+" relazione di scavo").evaluate());
			relazioneScavo.setSoggetto(ConstraintCheck.defaultFor(relazioneScavo.getSoggetto(),getSoggetto()).evaluate());
			relazioneScavo.setCreationTime(ConstraintCheck.defaultFor(relazioneScavo.getCreationTime(),getCreationTime()).evaluate());
			relazioneScavo.setLicenseID(ConstraintCheck.defaultFor(relazioneScavo.getLicenseID(), "CC-BY-4.0").evaluate());
			relazioneScavo.setPolicy(ConstraintCheck.defaultFor(relazioneScavo.getPolicy(),AccessPolicy.OPEN).evaluate());


		if(abstractRelazione == null) abstractRelazione = new AbstractRelazione();
			abstractRelazione.setTitolo(ConstraintCheck.defaultFor(abstractRelazione.getTitolo(),getNome()+" abstract relazione di scavo").evaluate());
			abstractRelazione.setCreationTime(ConstraintCheck.defaultFor(abstractRelazione.getCreationTime(),getCreationTime()).evaluate());
			abstractRelazione.setLicenseID(ConstraintCheck.defaultFor(abstractRelazione.getLicenseID(), "CC-BY-4.0").evaluate());
			abstractRelazione.setPolicy(ConstraintCheck.defaultFor(abstractRelazione.getPolicy(),AccessPolicy.OPEN).evaluate());


		if(immaginiRappresentative!=null)
			for(UploadedImage img : immaginiRappresentative) {
//				String evaluatedTitle="Empty img";
//				img.setTitolo(ConstraintCheck.defaultFor(img.getTitolo(),
//						getNome()+" abstract relazione di scavo").evaluate());
//
//				if(!img.getActualContent().isEmpty()){
//
//				}
				img.setSoggetto(ConstraintCheck.defaultFor(img.getSoggetto(),getSoggetto()).evaluate());
				img.setCreationTime(ConstraintCheck.defaultFor(img.getCreationTime(),getCreationTime()).evaluate());
				img.setPolicy(ConstraintCheck.defaultFor(img.getPolicy(),getPolicy()).evaluate());
				img.setLicenseID(ConstraintCheck.defaultFor(img.getLicenseID(),"CC-BY-4.0").evaluate());				
			}
		
		
		if(posizionamentoScavo!=null) {
			posizionamentoScavo.setTitolo(ConstraintCheck.defaultFor(posizionamentoScavo.getTitolo(), getNome()+" posizionamento scavo").evaluate());
			posizionamentoScavo.setAbstractSection(
					ConstraintCheck.defaultFor(posizionamentoScavo.getAbstractSection(),"Posizionamento topografico georeferenziato dell’area interessata dalle indagini").evaluate());
			
			posizionamentoScavo.setTopicCategory(ConstraintCheck.defaultFor(posizionamentoScavo.getTopicCategory(), "Society").evaluate());
			posizionamentoScavo.setSubTopic(ConstraintCheck.defaultFor(posizionamentoScavo.getSubTopic(), "Archeology").evaluate());

			posizionamentoScavo.setParoleChiaveLibere(ConstraintCheck.defaultFor(posizionamentoScavo.getParoleChiaveLibere(),getParoleChiaveLibere()).evaluate());
			posizionamentoScavo.setParoleChiaveICCD(ConstraintCheck.defaultFor(posizionamentoScavo.getParoleChiaveICCD(),getParoleChiaveICCD()).evaluate());
			
			//TODO Evaluate
			posizionamentoScavo.setBbox(ConstraintCheck.defaultFor(posizionamentoScavo.getBbox(), BBOX.WORLD_EXTENT).evaluate());
			
			posizionamentoScavo.setPolicy(ConstraintCheck.defaultFor(posizionamentoScavo.getPolicy(),getPolicy()).evaluate());;
			posizionamentoScavo.setLicenseID(ConstraintCheck.defaultFor(posizionamentoScavo.getLicenseID(), "CC-BY-4.0").evaluate());
			posizionamentoScavo.setResponsabile(getResponsabile());
			posizionamentoScavo.setCreationTime(ConstraintCheck.defaultFor(posizionamentoScavo.getCreationTime(), getCreationTime()).evaluate());
			
			
		}

		
		
		if(pianteFineScavo!=null)
			for(LayerConcessione l:pianteFineScavo) {
				
				l.setTitolo(ConstraintCheck.defaultFor(l.getTitolo(), getNome()+" pianta fine scavo").evaluate());
				l.setAbstractSection(
						ConstraintCheck.defaultFor(l.getAbstractSection(),"Planimetria georeferenziata dell'area indagata al termine delle attività").evaluate());
				
				l.setTopicCategory(ConstraintCheck.defaultFor(l.getTopicCategory(), "Society").evaluate());
				l.setSubTopic(ConstraintCheck.defaultFor(l.getSubTopic(), "Archeology").evaluate());

				l.setParoleChiaveLibere(ConstraintCheck.defaultFor(l.getParoleChiaveLibere(),getParoleChiaveLibere()).evaluate());
				l.setParoleChiaveICCD(ConstraintCheck.defaultFor(l.getParoleChiaveICCD(),getParoleChiaveICCD()).evaluate());
				

				l.setBbox(ConstraintCheck.defaultFor(l.getBbox(), BBOX.WORLD_EXTENT).evaluate());
				
				l.setPolicy(ConstraintCheck.defaultFor(l.getPolicy(),getPolicy()).evaluate());;
				l.setLicenseID(ConstraintCheck.defaultFor(l.getLicenseID(), "CC-BY-4.0").evaluate());
				l.setResponsabile(getResponsabile());
				l.setCreationTime(ConstraintCheck.defaultFor(l.getCreationTime(), getCreationTime()).evaluate());
			}
						
		
		
		
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
//		result = prime * result + ((authors == null) ? 0 : authors.hashCode());
		result = prime * result + CollectionsUtils.hashCode(authors);
//		result = prime * result + ((fontiFinanaziamento == null) ? 0 : fontiFinanaziamento.hashCode());
		result = prime * result + CollectionsUtils.hashCode(fontiFinanziamento);
//		result = prime * result + ((immaginiRappresentative == null) ? 0 : immaginiRappresentative.hashCode());
		result = prime * result + CollectionsUtils.hashCode(immaginiRappresentative);
//		result = prime * result + ((paroleChiaveICCD == null) ? 0 : paroleChiaveICCD.hashCode());
		result = prime * result + CollectionsUtils.hashCode(paroleChiaveICCD);
//		result = prime * result + ((paroleChiaveLibere == null) ? 0 : paroleChiaveLibere.hashCode());
		result = prime * result + CollectionsUtils.hashCode(paroleChiaveLibere);
//		result = prime * result + ((pianteFineScavo == null) ? 0 : pianteFineScavo.hashCode());
		result = prime * result + CollectionsUtils.hashCode(pianteFineScavo);
//		result = prime * result + ((risorseCorrelate == null) ? 0 : risorseCorrelate.hashCode());
		result = prime * result + CollectionsUtils.hashCode(risorseCorrelate);
//		result = prime * result + ((soggetto == null) ? 0 : soggetto.hashCode());
		result = prime * result + CollectionsUtils.hashCode(soggetto);		
//		result = prime * result + ((titolari == null) ? 0 : titolari.hashCode());
		result = prime * result + CollectionsUtils.hashCode(titolari);
		
		result = prime * result + ((centroidLat == null) ? 0 : centroidLat.hashCode());
		result = prime * result + ((centroidLong == null) ? 0 : centroidLong.hashCode());
		result = prime * result + ((contributore == null) ? 0 : contributore.hashCode());
		result = prime * result + ((dataFineProgetto == null) ? 0 : dataFineProgetto.hashCode());
		result = prime * result + ((dataInizioProgetto == null) ? 0 : dataInizioProgetto.hashCode());
		result = prime * result + ((descrizioneContenuto == null) ? 0 : descrizioneContenuto.hashCode());
		result = prime * result + ((editore == null) ? 0 : editore.hashCode());
		result = prime * result + ((genericContent == null) ? 0 : genericContent.hashCode());
		result = prime * result + ((introduzione == null) ? 0 : introduzione.hashCode());
		
		result = prime * result + ((posizionamentoScavo == null) ? 0 : posizionamentoScavo.hashCode());
		result = prime * result + ((relazioneScavo == null) ? 0 : relazioneScavo.hashCode());
		result = prime * result + ((responsabile == null) ? 0 : responsabile.hashCode());
		result = prime * result + ((titolareCopyright == null) ? 0 : titolareCopyright.hashCode());
		result = prime * result + ((titolareLicenza == null) ? 0 : titolareLicenza.hashCode());
		return result;
	}


	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Concessione other = (Concessione) obj;

		if(!CollectionsUtils.equalsCollections(authors, other.authors)) return false;
	if (!CollectionsUtils.equalsCollections(fontiFinanziamento, other.fontiFinanziamento)) return false;
	if (!CollectionsUtils.equalsCollections(immaginiRappresentative, other.immaginiRappresentative)) return false;
	if (!CollectionsUtils.equalsCollections(paroleChiaveICCD, other.paroleChiaveICCD)) return false;
	if (!CollectionsUtils.equalsCollections(paroleChiaveLibere, other.paroleChiaveLibere)) return false;
	if (!CollectionsUtils.equalsCollections(pianteFineScavo, other.pianteFineScavo)) return false;
	if (!CollectionsUtils.equalsCollections(risorseCorrelate, other.risorseCorrelate)) return false;
	if (!CollectionsUtils.equalsCollections(soggetto, other.soggetto)) return false;
	if (!CollectionsUtils.equalsCollections(titolari, other.titolari)) return false;

		if (centroidLat == null) {
			if (other.centroidLat != null)
				return false;
		} else if (!centroidLat.equals(other.centroidLat))
			return false;
		if (centroidLong == null) {
			if (other.centroidLong != null)
				return false;
		} else if (!centroidLong.equals(other.centroidLong))
			return false;
		if (contributore == null) {
			if (other.contributore != null)
				return false;
		} else if (!contributore.equals(other.contributore))
			return false;
		if (dataFineProgetto == null) {
			if (other.dataFineProgetto != null)
				return false;
		} else if (!dataFineProgetto.equals(other.dataFineProgetto))
			return false;
		if (dataInizioProgetto == null) {
			if (other.dataInizioProgetto != null)
				return false;
		} else if (!dataInizioProgetto.equals(other.dataInizioProgetto))
			return false;
		if (descrizioneContenuto == null) {
			if (other.descrizioneContenuto != null)
				return false;
		} else if (!descrizioneContenuto.equals(other.descrizioneContenuto))
			return false;
		if (editore == null) {
			if (other.editore != null)
				return false;
		} else if (!editore.equals(other.editore))
			return false;
		if (genericContent == null) {
			if (other.genericContent != null)
				return false;
		} else if (!genericContent.equals(other.genericContent))
			return false;
		if (introduzione == null) {
			if (other.introduzione != null)
				return false;
		} else if (!introduzione.equals(other.introduzione))
			return false;
		
		if (posizionamentoScavo == null) {
			if (other.posizionamentoScavo != null)
				return false;
		} else if (!posizionamentoScavo.equals(other.posizionamentoScavo))
			return false;
		if (relazioneScavo == null) {
			if (other.relazioneScavo != null)
				return false;
		} else if (!relazioneScavo.equals(other.relazioneScavo))
			return false;
		if (responsabile == null) {
			if (other.responsabile != null)
				return false;
		} else if (!responsabile.equals(other.responsabile))
			return false;
		if (titolareCopyright == null) {
			if (other.titolareCopyright != null)
				return false;
		} else if (!titolareCopyright.equals(other.titolareCopyright))
			return false;
		if (titolareLicenza == null) {
			if (other.titolareLicenza != null)
				return false;
		} else if (!titolareLicenza.equals(other.titolareLicenza))
			return false;
		
		return true;
	}
	
	
}
