package org.gcube.dataanalysis.geo.meta;

import it.geosolutions.geonetwork.util.GNInsertConfiguration;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.UUID;

import javax.xml.bind.JAXBException;

import org.gcube.spatial.data.geonetwork.GeoNetwork;
import org.gcube.spatial.data.geonetwork.GeoNetworkAdministration;
import org.gcube.spatial.data.geonetwork.LoginLevel;
import org.geotoolkit.metadata.iso.DefaultIdentifier;
import org.geotoolkit.metadata.iso.DefaultMetadata;
import org.geotoolkit.metadata.iso.citation.DefaultCitation;
import org.geotoolkit.metadata.iso.citation.DefaultCitationDate;
import org.geotoolkit.metadata.iso.citation.DefaultContact;
import org.geotoolkit.metadata.iso.citation.DefaultOnlineResource;
import org.geotoolkit.metadata.iso.citation.DefaultResponsibleParty;
import org.geotoolkit.metadata.iso.constraint.DefaultLegalConstraints;
import org.geotoolkit.metadata.iso.distribution.DefaultDigitalTransferOptions;
import org.geotoolkit.metadata.iso.distribution.DefaultDistribution;
import org.geotoolkit.metadata.iso.distribution.DefaultFormat;
import org.geotoolkit.metadata.iso.extent.DefaultExtent;
import org.geotoolkit.metadata.iso.extent.DefaultGeographicBoundingBox;
import org.geotoolkit.metadata.iso.identification.DefaultDataIdentification;
import org.geotoolkit.metadata.iso.identification.DefaultKeywords;
import org.geotoolkit.metadata.iso.identification.DefaultResolution;
import org.geotoolkit.metadata.iso.identification.DefaultUsage;
import org.geotoolkit.metadata.iso.lineage.DefaultLineage;
import org.geotoolkit.metadata.iso.lineage.DefaultNominalResolution;
import org.geotoolkit.metadata.iso.lineage.DefaultProcessStep;
import org.geotoolkit.metadata.iso.lineage.DefaultProcessing;
import org.geotoolkit.metadata.iso.lineage.DefaultSource;
import org.geotoolkit.metadata.iso.maintenance.DefaultMaintenanceInformation;
import org.geotoolkit.metadata.iso.quality.DefaultDataQuality;
import org.geotoolkit.metadata.iso.quality.DefaultScope;
import org.geotoolkit.metadata.iso.spatial.DefaultGeometricObjects;
import org.geotoolkit.metadata.iso.spatial.DefaultVectorSpatialRepresentation;
import org.geotoolkit.util.DefaultInternationalString;
import org.geotoolkit.xml.XML;
import org.opengis.metadata.Metadata;
import org.opengis.metadata.citation.DateType;
import org.opengis.metadata.citation.PresentationForm;
import org.opengis.metadata.citation.ResponsibleParty;
import org.opengis.metadata.citation.Role;
import org.opengis.metadata.constraint.Restriction;
import org.opengis.metadata.identification.KeywordType;
import org.opengis.metadata.identification.TopicCategory;
import org.opengis.metadata.lineage.ProcessStep;
import org.opengis.metadata.maintenance.MaintenanceFrequency;
import org.opengis.metadata.maintenance.ScopeCode;
import org.opengis.metadata.spatial.GeometricObjectType;
import org.opengis.metadata.spatial.SpatialRepresentationType;
import org.opengis.metadata.spatial.TopologyLevel;
import org.opengis.util.InternationalString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GenericLayerMetadata {

	private static final Logger LOGGER = LoggerFactory.getLogger(GenericLayerMetadata.class);
	
	private String geonetworkUrl = "http://geoserver-dev2.d4science-ii.research-infrastructures.eu/geonetwork/";
	private String geoserverUrl = "http://geoserver-dev.d4science-ii.research-infrastructures.eu/geonetwork/";
	private String geonetworkUser = "admin";
	private String geonetworkPwd = "admin";
	private String geonetworkGroup = "3";
	
	private String title = "temperature 04091217ruc.nc";
	private String layerName = "T";
	private String usageField = "Environmental enrichment";
	private String processdescription = "Maps publication";
	private String usageLimitations = "Not for commercial scopes";
	private Date sourceGenerationDate = new Date(System.currentTimeMillis());
	private String categoryTypes = "_BIOTA_";
	private String contactInfo = "support@d4science.org";
	private String abstractField = "";
	private String purpose = "Maps publication";
	private String author = "D4Science";
	private double res = 0.5d;
	private double xLL = -180;
	private double xRU = 180;
	private double yLL = -85.5;
	private double yRU = 85.5;
	private HashSet<String> customTopics;
	private Date startDate;
	private Date endDate;
	
	public void setCustomTopics(String... topics){
		customTopics  = new HashSet<String>();
		for (String topic:topics)
			customTopics.add(topic);
	}
	
	public HashSet<String> getCustomTopics(){
		return customTopics;
	}
	
	public void setStartDate(Date date){
		startDate=date;
	}
	
	public void setEndDate(Date date){
		endDate=date;
	}
	
	public Date getStartDate(){
		return startDate;
	}
	
	public Date getEndDate(){
		return endDate;
	}
	
	public String getGeonetworkUrl() {
		return geonetworkUrl;
	}

	public void setGeonetworkUrl(String geonetworkUrl) {
		this.geonetworkUrl = geonetworkUrl;
	}

	public String getGeonetworkUser() {
		return geonetworkUser;
	}

	public void setGeonetworkUser(String geonetworkUser) {
		this.geonetworkUser = geonetworkUser;
	}

	public String getGeonetworkPwd() {
		return geonetworkPwd;
	}

	public void setGeonetworkPwd(String geonetworkPwd) {
		this.geonetworkPwd = geonetworkPwd;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getLayerName() {
		return layerName;
	}

	public void setLayerName(String layerName) {
		this.layerName = layerName;
	}

	public String getUsageField() {
		return usageField;
	}

	public void setUsageField(String usageField) {
		this.usageField = usageField;
	}

	public String getProcessdescription() {
		return processdescription;
	}

	public void setProcessdescription(String processdescription) {
		this.processdescription = processdescription;
	}

	public String getUsageLimitations() {
		return usageLimitations;
	}

	public void setUsageLimitations(String usageLimitations) {
		this.usageLimitations = usageLimitations;
	}

	public Date getSourceGenerationDate() {
		return sourceGenerationDate;
	}

	public void setSourceGenerationDate(Date sourceGenerationDate) {
		this.sourceGenerationDate = sourceGenerationDate;
	}

	public String getCategoryTypes() {
		return categoryTypes;
	}

	public void setCategoryTypes(String categoryTypes) {
		this.categoryTypes = categoryTypes;
	}

	public String getContactInfo() {
		return contactInfo;
	}

	public void setContactInfo(String contactInfo) {
		this.contactInfo = contactInfo;
	}

	public String getAbstractField() {
		return abstractField;
	}

	public void setAbstractField(String abstractField) {
		this.abstractField = abstractField;
	}

	public String getPurpose() {
		return purpose;
	}

	public void setPurpose(String purpose) {
		this.purpose = purpose;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public double getResolution() {
		return res;
	}

	public void setResolution(double res) {
		this.res = res;
	}

	public double getXLeftLow() {
		return xLL;
	}

	public void setXLeftLow(double xLL) {
		this.xLL = xLL;
	}

	public double getXRightUpper() {
		return xRU;
	}

	public void setXRightUpper(double xRU) {
		this.xRU = xRU;
	}

	public double getYLeftLow() {
		return yLL;
	}

	public void setYLeftLow(double yLL) {
		this.yLL = yLL;
	}

	public double getYRightUpper() {
		return yRU;
	}

	public void setYRightUpper(double yRU) {
		this.yRU = yRU;
	}

	public String getGeoserverUrl() {
		return geoserverUrl;
	}

	public void setGeoserverUrl(String geoserverUrl) {
		this.geoserverUrl = geoserverUrl;
	}
	
	public String getGeonetworkGroup() {
		return geonetworkGroup;
	}

	public void setGeonetworkGroup(String geonetworkGroup) {
		this.geonetworkGroup = geonetworkGroup;
	}
	
	public static File meta2File(Metadata meta) throws IOException, JAXBException {
		File temp = File.createTempFile("meta", ".xml");
		FileWriter writer = new FileWriter(temp);
		writer.write(XML.marshal(meta));
		writer.close();
		return temp;
	}

	public void insertMetaData() throws Exception {

		// layer uri: wms, wfs wcs
		List<String> layerUris = new ArrayList<String>();
		layerUris.add(OGCFormatter.getWmsUrl(geoserverUrl, layerName, null, OGCFormatter.buildBoundingBox(xLL, yLL, xRU, yRU)));
		layerUris.add(OGCFormatter.getWfsUrl(geoserverUrl, layerName, OGCFormatter.buildBoundingBox(xLL, yLL, xRU, yRU), 0, "json"));
		layerUris.add(OGCFormatter.getWcsUrl(geoserverUrl, layerName, OGCFormatter.buildBoundingBox(xLL, yLL, xRU, yRU)));

		// layer keywords
		HashMap<KeywordType, HashSet<String>> descriptiveKeyWords = new HashMap<KeywordType, HashSet<String>>();
		HashSet<String> keySet = new HashSet<String>();
		keySet.add("D4Science");
		if (customTopics!=null)
			keySet.addAll(customTopics);
		
		descriptiveKeyWords.put(KeywordType.THEME, keySet);
		
		if (startDate!=null){
			HashSet<String> temporalkeySet = new HashSet<String>();
			temporalkeySet.add(startDate.toString());
			if (!endDate.equals(startDate))
				temporalkeySet.add(endDate.toString());
			descriptiveKeyWords.put(KeywordType.TEMPORAL, temporalkeySet);	
		}
				
		// author:
		DefaultResponsibleParty party = new DefaultResponsibleParty();
		party.setIndividualName(author);
		DefaultContact contact = new DefaultContact();
		contact.setContactInstructions(new DefaultInternationalString(contactInfo));
		party.setContactInfo(contact);
		party.setRole(Role.ORIGINATOR);

		// citation:
		DefaultCitation citation = new DefaultCitation();
		citation.setTitle(new DefaultInternationalString(title));
		ArrayList<DefaultCitationDate> citDates = new ArrayList<DefaultCitationDate>();
		citDates.add(new DefaultCitationDate(sourceGenerationDate, DateType.CREATION));
		citDates.add(new DefaultCitationDate(sourceGenerationDate, DateType.PUBLICATION));
		citDates.add(new DefaultCitationDate(sourceGenerationDate, DateType.REVISION));
		citation.setDates(citDates);
		ArrayList<InternationalString> citAltTitle = new ArrayList<InternationalString>();
		citAltTitle.add(new DefaultInternationalString(title));
		citation.setAlternateTitles(citAltTitle);
		citation.setEditionDate(sourceGenerationDate);
		citation.getPresentationForms().add(PresentationForm.MAP_DIGITAL);
		ArrayList<DefaultKeywords> keywordslist = new ArrayList<DefaultKeywords>();
		for (Entry<KeywordType, HashSet<String>> entry : descriptiveKeyWords.entrySet()) {
			DefaultKeywords keywords = new DefaultKeywords();
			for (String key : entry.getValue()) 
				keywords.getKeywords().add(new DefaultInternationalString(key));

			keywords.setType(entry.getKey());
			DefaultCitation thesaurus = new DefaultCitation();
			thesaurus.setTitle(new DefaultInternationalString("General"));
			thesaurus.setDates(citDates);
			keywords.setThesaurusName(thesaurus);
			keywordslist.add(keywords);
		}

		// usage:
		DefaultUsage usage = new DefaultUsage();
		usage.setSpecificUsage(new DefaultInternationalString(usageField));
		usage.setUsageDate(sourceGenerationDate);
		usage.setUserDeterminedLimitations(new DefaultInternationalString(usageLimitations));
		usage.setUserContactInfo(new ArrayList<ResponsibleParty>(Arrays.asList(party)));
		ArrayList<DefaultUsage> usages = new ArrayList<DefaultUsage>(Arrays.asList(usage));
		//build categories by guessing on the filename
		List<TopicCategory> categories = guessTopicCategory(categoryTypes);
		LOGGER.debug("Guessed Topics: "+categories);
		// Spatial Rapresentation Info
		DefaultGeometricObjects geoObjs = new DefaultGeometricObjects();
		geoObjs.setGeometricObjectType(GeometricObjectType.COMPLEX);
		DefaultVectorSpatialRepresentation spatial = new DefaultVectorSpatialRepresentation();
		spatial.setTopologyLevel(TopologyLevel.GEOMETRY_ONLY);
		spatial.getGeometricObjects().add(geoObjs);
		
		// Extent:
		DefaultExtent extent = new DefaultExtent();
		extent.setGeographicElements(Collections.singleton(new DefaultGeographicBoundingBox(xLL, xRU, yLL, yRU)));
		extent.setDescription(new DefaultInternationalString("Bounding box"));
		
		/*Only with Geotoolkit 4.x
		DefaultTemporalExtent stext = new DefaultTemporalExtent(startDate,endDate);
		stext.setStartTime(startDate);
		stext.setEndTime(endDate);
		extent.setTemporalElements(Arrays.asList(stext));
		*/
		extent.freeze();
		
		//resolution
		DefaultNominalResolution resolution = new DefaultNominalResolution();
		resolution.setGroundResolution(res);
		resolution.setScanningResolution(res);
		DefaultResolution dres = new DefaultResolution();
		dres.setDistance(res);
		
		// layers access:
		DefaultDistribution distribution = new DefaultDistribution();
		DefaultDigitalTransferOptions transferOptions = new DefaultDigitalTransferOptions();
		for (String uri : layerUris){
			DefaultOnlineResource onlineresource = new DefaultOnlineResource(new URI(uri));
			/*
			onlineresource.setName(arg0);
			onlineresource.setLinkage(arg0);
			onlineresource.setProtocol(arg0);
			onlineresource.setDescription(arg0);
			*/
			transferOptions.getOnLines().add(onlineresource);
		}
		distribution.getTransferOptions().add(transferOptions);
		DefaultFormat format1 = new DefaultFormat();
		format1.setName(new DefaultInternationalString("WMS"));
		format1.setVersion(new DefaultInternationalString("1.1.0"));
		DefaultFormat format2 = new DefaultFormat();
		format2.setName(new DefaultInternationalString("WFS"));
		format2.setVersion(new DefaultInternationalString("1.1.0"));
		DefaultFormat format3 = new DefaultFormat();
		format3.setName(new DefaultInternationalString("WCS"));
		format3.setVersion(new DefaultInternationalString("1.0.0"));

		distribution.setDistributionFormats(new ArrayList<DefaultFormat>(Arrays.asList(format1, format2, format3)));

		// legal constraints
		DefaultLegalConstraints constraints = new DefaultLegalConstraints();
		constraints.getUseLimitations().add(new DefaultInternationalString("Licensed"));
		constraints.getAccessConstraints().add(Restriction.LICENSE);
		constraints.getUseConstraints().add(Restriction.LICENSE);

		// quality declaration:
		DefaultDataQuality processQuality = new DefaultDataQuality();

		//citation
		DefaultCitation sourceCitation = new DefaultCitation();
		sourceCitation.setTitle(new DefaultInternationalString(title));
		sourceCitation.getDates().add(new DefaultCitationDate(sourceGenerationDate, DateType.CREATION));
		sourceCitation.getIdentifiers().add(new DefaultIdentifier(categoryTypes));
		
		//source
		DefaultSource source = new DefaultSource();
		source.setResolution(resolution);
		source.setDescription(new DefaultInternationalString(title));
		source.setSourceCitation(sourceCitation);

		// provenance
		DefaultProcessStep preprocessStep = new DefaultProcessStep();
		DefaultProcessStep processStep = new DefaultProcessStep(preprocessStep);
		DefaultProcessing processing = new DefaultProcessing();
		processing.setSoftwareReferences(new ArrayList<DefaultCitation>(Arrays.asList(sourceCitation)));
		processStep.setDescription(new DefaultInternationalString(processdescription));
		DefaultLineage processLineage = new DefaultLineage();
		processLineage.setProcessSteps(new ArrayList<ProcessStep>(Arrays.asList(processStep)));
		processQuality.setLineage(processLineage);
		processQuality.setScope(new DefaultScope(ScopeCode.DATASET));

		// fulfill identification
		DefaultDataIdentification ident = new DefaultDataIdentification();
		ident.setCitation(citation);
		ident.setAbstract(new DefaultInternationalString(abstractField));
		ident.setPurpose(new DefaultInternationalString(purpose));
		ident.getResourceMaintenances().add(new DefaultMaintenanceInformation(MaintenanceFrequency.AS_NEEDED));
		ident.setDescriptiveKeywords(keywordslist);
		ident.setTopicCategories(categories);
		ident.setResourceSpecificUsages(usages);
		ident.setExtents(new ArrayList<DefaultExtent>(Arrays.asList(extent)));
		ident.setSpatialRepresentationTypes(new ArrayList<SpatialRepresentationType>(Arrays.asList(SpatialRepresentationType.GRID)));
		ident.setSpatialResolutions(new ArrayList<DefaultResolution>(Arrays.asList(dres)));
		ident.setLanguages(new ArrayList<Locale>(Arrays.asList(Locale.ENGLISH)));
		
		// Metadata Obj:
		DefaultMetadata meta = new DefaultMetadata(party, sourceGenerationDate, ident);
		meta.getSpatialRepresentationInfo().add(spatial);
		meta.setDistributionInfo(distribution);
		meta.getMetadataConstraints().add(constraints);
		meta.getDataQualityInfo().add(processQuality);
		meta.setLanguage(Locale.ENGLISH);
//		System.out.println(meta);
		
		/*
		GNClient client = new GNClient(geonetworkUrl);
		client.login(geonetworkUser, geonetworkPwd);
		File tmetafile = meta2File(meta);
		client.insertMetadata(new GNInsertConfiguration(geonetworkGroup, "datasets", "_none_", true), tmetafile);
		tmetafile.delete();
	*/
		GeoNetworkAdministration readerScope = GeoNetwork.get();
		readerScope.login(LoginLevel.SCOPE);
		GNInsertConfiguration configuration = readerScope.getCurrentUserConfiguration("datasets", "_none_");
		readerScope.insertAndPromoteMetadata(configuration, meta);
	}

	public void customMetaDataInsert(String[] urls, String[] protocols) throws Exception {
		customMetaDataInsert(urls,protocols,true);
	}
	
	public void customMetaDataInsert(String[] urls, String[] protocols, boolean isprivate) throws Exception {

		// layer uri: wms, wfs wcs
		List<String> layerUris = new ArrayList<String>();
		for (int i=0;i<urls.length;i++)
			layerUris.add(urls[i]);
		
		// layer keywords
		HashMap<KeywordType, HashSet<String>> descriptiveKeyWords = new HashMap<KeywordType, HashSet<String>>();
		HashSet<String> keySet = new HashSet<String>();
		
		if (customTopics!=null)
			keySet.addAll(customTopics);
		
		descriptiveKeyWords.put(KeywordType.THEME, keySet);
		
		if (startDate!=null){
			HashSet<String> temporalkeySet = new HashSet<String>();
			temporalkeySet.add(startDate.toString());
			if (!endDate.equals(startDate))
				temporalkeySet.add(endDate.toString());
			descriptiveKeyWords.put(KeywordType.TEMPORAL, temporalkeySet);	
		}
				
		// author:
		DefaultResponsibleParty party = new DefaultResponsibleParty();
		party.setIndividualName(author);
		DefaultContact contact = new DefaultContact();
		contact.setContactInstructions(new DefaultInternationalString(contactInfo));
		party.setContactInfo(contact);
		party.setRole(Role.ORIGINATOR);

		// citation:
		DefaultCitation citation = new DefaultCitation();
		citation.setTitle(new DefaultInternationalString(title));
		ArrayList<DefaultCitationDate> citDates = new ArrayList<DefaultCitationDate>();
		citDates.add(new DefaultCitationDate(sourceGenerationDate, DateType.CREATION));
		citDates.add(new DefaultCitationDate(sourceGenerationDate, DateType.PUBLICATION));
		citDates.add(new DefaultCitationDate(sourceGenerationDate, DateType.REVISION));
		citation.setDates(citDates);
		ArrayList<InternationalString> citAltTitle = new ArrayList<InternationalString>();
		citAltTitle.add(new DefaultInternationalString(title));
		citation.setAlternateTitles(citAltTitle);
		citation.setEditionDate(sourceGenerationDate);
		citation.getPresentationForms().add(PresentationForm.MAP_DIGITAL);
		ArrayList<DefaultKeywords> keywordslist = new ArrayList<DefaultKeywords>();
		for (Entry<KeywordType, HashSet<String>> entry : descriptiveKeyWords.entrySet()) {
			DefaultKeywords keywords = new DefaultKeywords();
			for (String key : entry.getValue()) 
				keywords.getKeywords().add(new DefaultInternationalString(key));

			keywords.setType(entry.getKey());
			DefaultCitation thesaurus = new DefaultCitation();
			thesaurus.setTitle(new DefaultInternationalString("General"));
			thesaurus.setDates(citDates);
			keywords.setThesaurusName(thesaurus);
			keywordslist.add(keywords);
		}

		// usage:
		DefaultUsage usage = new DefaultUsage();
		usage.setSpecificUsage(new DefaultInternationalString(usageField));
		usage.setUsageDate(sourceGenerationDate);
		usage.setUserDeterminedLimitations(new DefaultInternationalString(usageLimitations));
		usage.setUserContactInfo(new ArrayList<ResponsibleParty>(Arrays.asList(party)));
		ArrayList<DefaultUsage> usages = new ArrayList<DefaultUsage>(Arrays.asList(usage));
		//build categories by guessing on the filename
		List<TopicCategory> categories = guessTopicCategory(categoryTypes);
		LOGGER.debug("Guessed Topics: "+categories);
		// Spatial Rapresentation Info
		DefaultGeometricObjects geoObjs = new DefaultGeometricObjects();
		geoObjs.setGeometricObjectType(GeometricObjectType.COMPLEX);
		DefaultVectorSpatialRepresentation spatial = new DefaultVectorSpatialRepresentation();
		spatial.setTopologyLevel(TopologyLevel.GEOMETRY_ONLY);
		spatial.getGeometricObjects().add(geoObjs);
		
		// Extent:
		DefaultExtent extent = new DefaultExtent();
		extent.setGeographicElements(Collections.singleton(new DefaultGeographicBoundingBox(xLL, xRU, yLL, yRU)));
		extent.setDescription(new DefaultInternationalString("Bounding box"));
		
		/*Only with Geotoolkit 4.x
		DefaultTemporalExtent stext = new DefaultTemporalExtent(startDate,endDate);
		stext.setStartTime(startDate);
		stext.setEndTime(endDate);
		extent.setTemporalElements(Arrays.asList(stext));
		*/
		extent.freeze();
		
		//resolution
		DefaultNominalResolution resolution = new DefaultNominalResolution();
		resolution.setGroundResolution(res);
		resolution.setScanningResolution(res);
		DefaultResolution dres = new DefaultResolution();
		dres.setDistance(res);
		
		// layers access:
		DefaultDistribution distribution = new DefaultDistribution();
		DefaultDigitalTransferOptions transferOptions = new DefaultDigitalTransferOptions();
		for (String uri : layerUris){
			DefaultOnlineResource onlineres = new DefaultOnlineResource(new URI(uri));
			String url = onlineres.getLinkage().toURL().toString();
			String estdescription = getDescription(url);
			String estProtocol = getProtocol(url);
			String estName = getName(title, abstractField, estProtocol, url);
			LOGGER.debug("URL:" + url + "\nDescription:" + estdescription + "\nName:" + estName + "\nProtocol:" + estProtocol);
			onlineres.setDescription(new DefaultInternationalString(estdescription));
			onlineres.setName(estName);
			onlineres.setProtocol(estProtocol);
			
			transferOptions.getOnLines().add(new DefaultOnlineResource(new URI(uri)));
			
		}
			
		distribution.getTransferOptions().add(transferOptions);
		
		DefaultFormat [] formats = new DefaultFormat[protocols.length];
		for (int i=0;i<protocols.length;i++){
				DefaultFormat format = new DefaultFormat();
				format.setName(new DefaultInternationalString(protocols[i]));
				format.setVersion(new DefaultInternationalString("1.0.0"));
				formats[i]=format;
		}
		
		distribution.setDistributionFormats(new ArrayList<DefaultFormat>(Arrays.asList(formats)));

		// legal constraints
		DefaultLegalConstraints constraints = new DefaultLegalConstraints();
		constraints.getUseLimitations().add(new DefaultInternationalString("Licensed"));
		constraints.getAccessConstraints().add(Restriction.LICENSE);
		constraints.getUseConstraints().add(Restriction.LICENSE);

		// quality declaration:
		DefaultDataQuality processQuality = new DefaultDataQuality();

		//citation
		DefaultCitation sourceCitation = new DefaultCitation();
		sourceCitation.setTitle(new DefaultInternationalString(title));
		sourceCitation.getDates().add(new DefaultCitationDate(sourceGenerationDate, DateType.CREATION));
		sourceCitation.getIdentifiers().add(new DefaultIdentifier(categoryTypes));
		
		//source
		DefaultSource source = new DefaultSource();
		source.setResolution(resolution);
		source.setDescription(new DefaultInternationalString(title));
		source.setSourceCitation(sourceCitation);

		// provenance
		DefaultProcessStep preprocessStep = new DefaultProcessStep();
		DefaultProcessStep processStep = new DefaultProcessStep(preprocessStep);
		DefaultProcessing processing = new DefaultProcessing();
		processing.setSoftwareReferences(new ArrayList<DefaultCitation>(Arrays.asList(sourceCitation)));
		processStep.setDescription(new DefaultInternationalString(processdescription));
		DefaultLineage processLineage = new DefaultLineage();
		processLineage.setProcessSteps(new ArrayList<ProcessStep>(Arrays.asList(processStep)));
		processQuality.setLineage(processLineage);
		processQuality.setScope(new DefaultScope(ScopeCode.DATASET));

		// fulfill identification
		DefaultDataIdentification ident = new DefaultDataIdentification();
		ident.setCitation(citation);
		ident.setAbstract(new DefaultInternationalString(abstractField));
		ident.setPurpose(new DefaultInternationalString(purpose));
		ident.getResourceMaintenances().add(new DefaultMaintenanceInformation(MaintenanceFrequency.AS_NEEDED));
		ident.setDescriptiveKeywords(keywordslist);
		ident.setTopicCategories(categories);
		ident.setResourceSpecificUsages(usages);
		ident.setExtents(new ArrayList<DefaultExtent>(Arrays.asList(extent)));
		ident.setSpatialRepresentationTypes(new ArrayList<SpatialRepresentationType>(Arrays.asList(SpatialRepresentationType.GRID)));
		ident.setSpatialResolutions(new ArrayList<DefaultResolution>(Arrays.asList(dres)));
		ident.setLanguages(new ArrayList<Locale>(Arrays.asList(Locale.ENGLISH)));
		
		// Metadata Obj:
		DefaultMetadata meta = new DefaultMetadata(party, sourceGenerationDate, ident);
		String id = UUID.randomUUID().toString();
		meta.setFileIdentifier(id);
		meta.getSpatialRepresentationInfo().add(spatial);
		meta.setDistributionInfo(distribution);
		meta.getMetadataConstraints().add(constraints);
		meta.getDataQualityInfo().add(processQuality);
		meta.setLanguage(Locale.ENGLISH);
		
		LOGGER.debug("id of generated metadata is {}",id);
		
		
		GeoNetworkAdministration readerScope = GeoNetwork.get();
		if (isprivate)
			readerScope.login(LoginLevel.PRIVATE);
		else
			readerScope.login(LoginLevel.SCOPE);
		
		GNInsertConfiguration configuration = readerScope.getCurrentUserConfiguration("datasets", "_none_");
		
		
		
		if (isprivate)
			readerScope.insertMetadata(configuration, meta);
		else
			readerScope.insertAndPromoteMetadata(configuration, meta);
		
		
		
		//old command
		/*
		GNClient client = new GNClient(geonetworkUrl);
		client.login(geonetworkUser, geonetworkPwd);
		File tmetafile = meta2File(meta);
		tmetafile.delete();
		client.insertMetadata(new GNInsertConfiguration(geonetworkGroup, "datasets", "_none_", true), tmetafile);
		 */
	
	}
	
	public static List<TopicCategory> guessTopicCategory(String refString){
		String searcher = refString.toLowerCase();
		List<TopicCategory> categories = new ArrayList<TopicCategory>();
		for (TopicCategory topic:TopicCategory.values()){
			if (searcher.contains("_"+topic.name().toLowerCase()+"_")){
				categories.add(topic);
			}
		}
		return categories;
	}
	
	
	public Metadata createBasicMeta(String[] urls,String[] protocols) throws Exception {
		

		// layer uri: wms, wfs wcs
		List<String> layerUris = new ArrayList<String>();
		for (int i=0;i<urls.length;i++)
			layerUris.add(urls[i].trim());
		
		// layer keywords
		HashMap<KeywordType, HashSet<String>> descriptiveKeyWords = new HashMap<KeywordType, HashSet<String>>();
		HashSet<String> keySet = new HashSet<String>();
		
		if (customTopics!=null)
			keySet.addAll(customTopics);
		
		descriptiveKeyWords.put(KeywordType.THEME, keySet);
		
		if (startDate!=null){
			HashSet<String> temporalkeySet = new HashSet<String>();
			temporalkeySet.add(startDate.toString());
			if (!endDate.equals(startDate))
				temporalkeySet.add(endDate.toString());
			descriptiveKeyWords.put(KeywordType.TEMPORAL, temporalkeySet);	
		}
				
		// author:
		DefaultResponsibleParty party = new DefaultResponsibleParty();
		party.setIndividualName(author);
		DefaultContact contact = new DefaultContact();
		contact.setContactInstructions(new DefaultInternationalString(contactInfo));
		party.setContactInfo(contact);
		party.setRole(Role.ORIGINATOR);

		// citation:
		DefaultCitation citation = new DefaultCitation();
		citation.setTitle(new DefaultInternationalString(title));
		ArrayList<DefaultCitationDate> citDates = new ArrayList<DefaultCitationDate>();
		citDates.add(new DefaultCitationDate(sourceGenerationDate, DateType.CREATION));
		citDates.add(new DefaultCitationDate(sourceGenerationDate, DateType.PUBLICATION));
		citDates.add(new DefaultCitationDate(sourceGenerationDate, DateType.REVISION));
		citation.setDates(citDates);
		ArrayList<InternationalString> citAltTitle = new ArrayList<InternationalString>();
		citAltTitle.add(new DefaultInternationalString(title));
		citation.setAlternateTitles(citAltTitle);
		citation.setEditionDate(sourceGenerationDate);
		citation.getPresentationForms().add(PresentationForm.MAP_DIGITAL);
		ArrayList<DefaultKeywords> keywordslist = new ArrayList<DefaultKeywords>();
		for (Entry<KeywordType, HashSet<String>> entry : descriptiveKeyWords.entrySet()) {
			DefaultKeywords keywords = new DefaultKeywords();
			for (String key : entry.getValue()) 
				keywords.getKeywords().add(new DefaultInternationalString(key));

			keywords.setType(entry.getKey());
			DefaultCitation thesaurus = new DefaultCitation();
			thesaurus.setTitle(new DefaultInternationalString("General"));
			thesaurus.setDates(citDates);
			keywords.setThesaurusName(thesaurus);
			keywordslist.add(keywords);
		}

		// usage:
		DefaultUsage usage = new DefaultUsage();
		usage.setSpecificUsage(new DefaultInternationalString(usageField));
		usage.setUsageDate(sourceGenerationDate);
		usage.setUserDeterminedLimitations(new DefaultInternationalString(usageLimitations));
		usage.setUserContactInfo(new ArrayList<ResponsibleParty>(Arrays.asList(party)));
		ArrayList<DefaultUsage> usages = new ArrayList<DefaultUsage>(Arrays.asList(usage));
		//build categories by guessing on the filename
		List<TopicCategory> categories = guessTopicCategory(categoryTypes);
		LOGGER.debug("Guessed Topics: "+categories);
		// Spatial Rapresentation Info
		DefaultGeometricObjects geoObjs = new DefaultGeometricObjects();
		geoObjs.setGeometricObjectType(GeometricObjectType.COMPLEX);
		DefaultVectorSpatialRepresentation spatial = new DefaultVectorSpatialRepresentation();
		spatial.setTopologyLevel(TopologyLevel.GEOMETRY_ONLY);
		spatial.getGeometricObjects().add(geoObjs);
		
		// Extent:
		DefaultExtent extent = new DefaultExtent();
		extent.setGeographicElements(Collections.singleton(new DefaultGeographicBoundingBox(xLL, xRU, yLL, yRU)));
		extent.setDescription(new DefaultInternationalString("Bounding box"));
		
		/*Only with Geotoolkit 4.x
		DefaultTemporalExtent stext = new DefaultTemporalExtent(startDate,endDate);
		stext.setStartTime(startDate);
		stext.setEndTime(endDate);
		extent.setTemporalElements(Arrays.asList(stext));
		*/
		extent.freeze();
		
		//resolution
		DefaultNominalResolution resolution = new DefaultNominalResolution();
		resolution.setGroundResolution(res);
		resolution.setScanningResolution(res);
		DefaultResolution dres = new DefaultResolution();
		dres.setDistance(res);
		
		// layers access:
		DefaultDistribution distribution = new DefaultDistribution();
		DefaultDigitalTransferOptions transferOptions = new DefaultDigitalTransferOptions();
		for (String uri : layerUris)
			transferOptions.getOnLines().add(new DefaultOnlineResource(new URI(uri)));
		distribution.getTransferOptions().add(transferOptions);
		
		DefaultFormat [] formats = new DefaultFormat[protocols.length];
		for (int i=0;i<protocols.length;i++){
				DefaultFormat format = new DefaultFormat();
				format.setName(new DefaultInternationalString(protocols[i]));
				format.setVersion(new DefaultInternationalString("1.0.0"));
				formats[i]=format;
		}
		
		distribution.setDistributionFormats(new ArrayList<DefaultFormat>(Arrays.asList(formats)));

		// legal constraints
		DefaultLegalConstraints constraints = new DefaultLegalConstraints();
		constraints.getUseLimitations().add(new DefaultInternationalString("Licensed"));
		constraints.getAccessConstraints().add(Restriction.LICENSE);
		constraints.getUseConstraints().add(Restriction.LICENSE);

		// quality declaration:
		DefaultDataQuality processQuality = new DefaultDataQuality();

		//citation
		DefaultCitation sourceCitation = new DefaultCitation();
		sourceCitation.setTitle(new DefaultInternationalString(title));
		sourceCitation.getDates().add(new DefaultCitationDate(sourceGenerationDate, DateType.CREATION));
		sourceCitation.getIdentifiers().add(new DefaultIdentifier(categoryTypes));
		
		//source
		DefaultSource source = new DefaultSource();
		source.setResolution(resolution);
		source.setDescription(new DefaultInternationalString(title));
		source.setSourceCitation(sourceCitation);

		// provenance
		DefaultProcessStep preprocessStep = new DefaultProcessStep();
		DefaultProcessStep processStep = new DefaultProcessStep(preprocessStep);
		DefaultProcessing processing = new DefaultProcessing();
		processing.setSoftwareReferences(new ArrayList<DefaultCitation>(Arrays.asList(sourceCitation)));
		processStep.setDescription(new DefaultInternationalString(processdescription));
		DefaultLineage processLineage = new DefaultLineage();
		processLineage.setProcessSteps(new ArrayList<ProcessStep>(Arrays.asList(processStep)));
		processQuality.setLineage(processLineage);
		processQuality.setScope(new DefaultScope(ScopeCode.DATASET));

		// fulfill identification
		DefaultDataIdentification ident = new DefaultDataIdentification();
		ident.setCitation(citation);
		ident.setAbstract(new DefaultInternationalString(abstractField));
		ident.setPurpose(new DefaultInternationalString(purpose));
		ident.getResourceMaintenances().add(new DefaultMaintenanceInformation(MaintenanceFrequency.AS_NEEDED));
		ident.setDescriptiveKeywords(keywordslist);
		ident.setTopicCategories(categories);
		ident.setResourceSpecificUsages(usages);
		ident.setExtents(new ArrayList<DefaultExtent>(Arrays.asList(extent)));
		ident.setSpatialRepresentationTypes(new ArrayList<SpatialRepresentationType>(Arrays.asList(SpatialRepresentationType.GRID)));
		ident.setSpatialResolutions(new ArrayList<DefaultResolution>(Arrays.asList(dres)));
		ident.setLanguages(new ArrayList<Locale>(Arrays.asList(Locale.ENGLISH)));
		
		// Metadata Obj:
		DefaultMetadata meta = new DefaultMetadata(party, sourceGenerationDate, ident);
		meta.getSpatialRepresentationInfo().add(spatial);
		meta.setDistributionInfo(distribution);
		meta.getMetadataConstraints().add(constraints);
		meta.getDataQualityInfo().add(processQuality);
		meta.setLanguage(Locale.ENGLISH);
		
		return meta;
	
	}
	
	
	public static String getProtocol(String url) {

		if (url.toLowerCase().contains("service=wfs"))
			return "OGC:WFS-1.1.0-http-get-feature";

		else if (url.toLowerCase().contains("service=wms"))
			return "OGC:WMS-1.3.0-http-get-map";

		else if (url.toLowerCase().contains("service=wcs"))
			return "OGC:WCS-1.0.0-http-get-coverage";

		else if (url.toLowerCase().contains("/dodsC"))
			return "OGC:OPeNDAP-2.0.0";

		else
			return "WWW:LINK-1.0-http--link";
	}

	public static String getDescription(String url) {

		if (url.toLowerCase().contains("service=wfs"))
			return "GIS data (WFS - JSON)";

		else if (url.toLowerCase().contains("service=wms")) {
			if (url.toLowerCase().contains("openlayers"))
				return "GIS data (WMS - OpenLayers)";
			else
				return "GIS data (WMS)";
		} else if (url.toLowerCase().contains("service=wcs"))
			return "GIS data (WCS - Geotiff)";

		else if (url.toLowerCase().contains("/dodsc"))
			return "GIS data (OPenNDAP - NetCDF)";

		else
			return "Direct HTTP link";
	}

	public static String getName(String title, String abstractTitle, String protocol, String url) {
		try{
			
		if (abstractTitle.matches(".+: ")) {
			String variablename = title.substring(title.indexOf(":"));
			LOGGER.debug("detected variable " + variablename);
			return variablename;
		} else {
			if (url.contains("catalog.xml")) {
				return "Catalogue";
			} else if (protocol.equals("WWW:LINK-1.0-http--link") || protocol.equals("OGC:OPeNDAP-2.0.0")) {
				int slash = url.lastIndexOf("/");
				if (slash > 0) {
					String file = url.substring(slash + 1);
					if (file.trim().length() > 0 && file.contains("."))
						return file;
					else
						return "Direct link to resource";
				} else
					return "Direct link to resource";
			} else {
				int check = -1;
				String checker = "";
				if (protocol.equals("OGC:WMS-1.3.0-http-get-map")) {
					checker = "layers=";
				} else if (protocol.equals("OGC:WFS-1.0.0-http-get-feature")) {
					checker = "typename=";
				} else if (protocol.equals("OGC:WCS-1.0.0-http-get-coverage")) {
					checker = "coverage=";
				}

				check = url.toLowerCase().indexOf(checker);
				if (check > 0) {
					String cutUrl = url.substring(check + checker.length());
					int end = cutUrl.indexOf("&");
					String layerName = cutUrl;
					if (end > -1)
						layerName = cutUrl.substring(0, end);

					int column = -1;
					if ((column = layerName.indexOf(":")) > 0)
						layerName = layerName.substring(column + 1);
					LOGGER.debug("Layer Name: " + layerName);
					return layerName;
				} else
					return title;
			}
		}
		}catch(Exception e){
			e.printStackTrace();
			return "LINK";
		}

	}
	
	
}
