package org.gcube.portlets.user.speciesdiscovery.server.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;

import org.gcube.data.spd.model.Properties;
import org.gcube.data.spd.model.Property;
import org.gcube.portlets.user.speciesdiscovery.shared.Coordinate;
import org.gcube.portlets.user.speciesdiscovery.shared.DataSourceModel;
import org.gcube.portlets.user.speciesdiscovery.shared.SearchFilters;
import org.gcube.portlets.user.speciesdiscovery.shared.SearchType;

public class QueryBuilder {


	public static String buildQuery(String searchTerm, SearchType searchType, SearchFilters searchFilters){
		StringBuilder query = new StringBuilder();

		//ADD search term;
		query.append('\'');
		query.append(searchTerm);
		query.append('\'');

		//ADD search type;
		switch (searchType) {
			case BY_SCIENTIFIC_NAME: query.append(" as ScientificName "); break;
			case BY_COMMON_NAME: query.append(" as CommonName "); break;
		}
		

		//ADD data sources;
		if (searchFilters.getListDataSources()!=null && searchFilters.getListDataSources().size()>0) {
			query.append(" in ");
			
			Iterator<DataSourceModel> dsIterator = searchFilters.getListDataSources().iterator();
			while(dsIterator.hasNext()) {
				DataSourceModel ds = dsIterator.next();
				query.append(" ");
				query.append(ds.getId());
				if (dsIterator.hasNext()) query.append(", ");
				else query.append(" ");
			}		
		}
		

		List<Property> properties = createFilterProperties(searchFilters);

		//ADD filters
		if(properties.size()>0){
			query.append(" where ");
			
			Iterator<Property> pIterator = properties.iterator();
			while (pIterator.hasNext()) {
				Property property = pIterator.next();
				String statement = getQueryStatementFromProperty(property);
				query.append(statement);
				
				if (pIterator.hasNext()) query.append(" AND ");
				else  query.append(" ");
				
			}
		}

		//ADD return type
		
		query.append(" return ");
		if (searchFilters.getResultType()!=null) { 
			switch (searchFilters.getResultType()) {
//				case RESULTITEM: query.append("*"); break; //Modify by Francesco
				case RESULTITEM: query.append("* having Occurrence"); break;
				case TAXONOMYITEM: query.append("Taxon"); break; 
			}
		} else {
//			query.append("*"); Modify by Francesco
			query.append("* having Occurrence");
		}

		return query.toString();

	}

	protected static String getQueryStatementFromProperty(Property property){

		String statement = null;
		Properties prop = property.getProp();

		if(prop.equals(Properties.CoordinateTo)){
			statement= Properties.CoordinateTo.name() + " IS " + property.getValue();

		}else if(prop.equals(Properties.CoordinateFrom)){
			statement= Properties.CoordinateFrom.name() + " IS " + property.getValue();

		}else if(prop.equals(Properties.DateFrom)){
			statement= Properties.DateFrom.name() + " IS " + property.getValue();

		}else if(prop.equals(Properties.DateTo)){
			statement= Properties.DateTo.name() + " IS " + property.getValue();

		}

		return statement;

	}

	protected static List<Property> createFilterProperties(SearchFilters searchFilters)
	{
		List<Property> properties = new ArrayList<Property>();
		if (searchFilters.getUpperBound()!=null) properties.add(new Property(Properties.CoordinateTo, convert(searchFilters.getUpperBound())));
		if (searchFilters.getLowerBound()!=null) properties.add(new Property(Properties.CoordinateFrom, convert(searchFilters.getLowerBound())));

		if (searchFilters.getFromDate()!=null) {
			Calendar fromDate = Calendar.getInstance();
			fromDate.setTime(searchFilters.getFromDate());
			properties.add(new Property(Properties.DateFrom, fromDate));
		}
		if (searchFilters.getToDate()!=null) {
			Calendar toDate = Calendar.getInstance();
			toDate.setTime(searchFilters.getToDate());
			properties.add(new Property(Properties.DateTo, toDate));
		}

		return properties;
	}

	protected static org.gcube.data.spd.model.Coordinate convert(Coordinate coordinate)
	{
		return new org.gcube.data.spd.model.Coordinate(coordinate.getLatitude(), coordinate.getLongitude());
	}
}
