package eu.dnetlib.openaire.exporter;

import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import eu.dnetlib.enabling.database.rmi.DatabaseService;
import eu.dnetlib.enabling.resultset.client.IterableResultSetClient;
import eu.dnetlib.enabling.resultset.client.ResultSetClientFactory;
import eu.dnetlib.enabling.tools.ServiceLocator;
import eu.dnetlib.miscutils.collections.MappedCollection;
import eu.dnetlib.miscutils.functional.xml.ApplyXslt;

public class ProjectsController {

	private ServiceLocator<DatabaseService> dbServiceLocator;
	private String dbName;
	private Resource dspaceXslt;
	private Resource eprintsXslt;

	@javax.annotation.Resource
	private ResultSetClientFactory resultSetClientFactory;

	private ProjectQueryParamsFactory projectQueryParamsFactory;

	private static final Log log = LogFactory.getLog(ProjectsController.class); // NOPMD by marko on 11/24/08 5:02 PM

	@RequestMapping(value = "/openaire/export/**/project/dspace.do")
	void processDspace(final HttpServletRequest request,
			final ServletResponse response,
			@RequestParam(value = "startFrom", required = false) final String startFrom,
			@RequestParam(value = "startUntil", required = false) final String startUntil,
			@RequestParam(value = "endFrom", required = false) final String endFrom,
			@RequestParam(value = "endUntil", required = false) final String endUntil) throws Exception {

		response.setContentType("text/xml");

		ProjectQueryParams params = projectQueryParamsFactory.generateParams(request, startFrom, startUntil, endFrom, endUntil);

		ServletOutputStream out = response.getOutputStream();

		String head = "<?xml version='1.0' encoding='UTF-8'?>\n\n" + "<form-value-pairs>\n" + "	<value-pairs value-pairs-name='" + params.getFundingProgramme()
				+ "projects' dc-term='relation'>\n";

		String tail = "	</value-pairs>\n" + "</form-value-pairs>\n";

		IOUtils.copy(new StringReader(head), out);
		emit(out, dspaceXslt, obtainQuery(params));
		IOUtils.copy(new StringReader(tail), out);
	}

	@RequestMapping(value = "/openaire/export/**/project/eprints.do")
	void processEprints(final HttpServletRequest request,
			final ServletResponse response,
			@RequestParam(value = "startFrom", required = false) final String startFrom,
			@RequestParam(value = "startUntil", required = false) final String startUntil,
			@RequestParam(value = "endFrom", required = false) final String endFrom,
			@RequestParam(value = "endUntil", required = false) final String endUntil) throws Exception {
		response.setContentType("text/html");
		emit(response.getOutputStream(), eprintsXslt, obtainQuery(projectQueryParamsFactory.generateParams(request, startFrom, startUntil, endFrom, endUntil)));
	}

	private String obtainQuery(final ProjectQueryParams params) {
		String query = "select " + "p.acronym as acronym, " + "p.title as title, "
				+ "regexp_replace(p.id, '^corda_______::'  , '') as grant_agreement_number, " + "p.startdate as start_date, " + "p.enddate as end_date, "
				+ "f1.name as subdivision, " + "f2.name as specificprogramme, " + "f3.name as fundingprogramme " + "from projects p "
				+ "left outer join project_funding pf on (p.id = pf.project) " + "left outer join funding_funding ff1 on (pf.funding = ff1.funding1) "
				+ "left outer join funding_funding ff2 on (ff1.funding2 = ff2.funding1) " + "left outer join fundings f1 on (f1.id = ff1.funding1) "
				+ "left outer join fundings f2 on (f2.id = ff2.funding1) " + "left outer join fundings f3 on (f3.id = ff2.funding2) "
				+ "where f3.id = 'corda_______::FP7' ";

		if (params.getSubdivision() != null) {
			query += "AND f1.name = '" + params.getSubdivision() + "'";
		}
		if (params.getSpecificProgramme() != null) {
			query += "AND f2.name = '" + params.getSpecificProgramme() + "'";
		}
		if (params.getFundingProgramme() != null) {
			query += "AND f3.name = '" + params.getFundingProgramme() + "'";
		}
		if (params.getStartFrom() != null) {
			query += "AND p.startdate >= '" + params.getStartFrom() + "'";
		}
		if (params.getStartUntil() != null) {
			query += "AND p.startdate <= '" + params.getStartUntil() + "'";
		}
		if (params.getEndFrom() != null) {
			query += "AND p.enddate >= '" + params.getEndFrom() + "'";
		}
		if (params.getEndUntil() != null) {
			query += "AND p.enddate <= '" + params.getEndUntil() + "'";
		}

		log.info("Executing query: " + query);

		return query;
	}

	void emit(final OutputStream out, final Resource xslt, final String query) throws IOException {
		W3CEndpointReference epr = dbServiceLocator.getService().searchSQL(dbName, query);

		IterableResultSetClient iter = resultSetClientFactory.getClient(epr);

		for (String s : new MappedCollection<String, String>(iter, new ApplyXslt(xslt))) {
			out.write(s.getBytes());
		}
	}

	public String getDbName() {
		return dbName;
	}

	@Required
	public void setDbName(final String dbName) {
		this.dbName = dbName;
	}

	public Resource getDspaceXslt() {
		return dspaceXslt;
	}

	@Required
	public void setDspaceXslt(final Resource dspaceXslt) {
		this.dspaceXslt = dspaceXslt;
	}

	public Resource getEprintsXslt() {
		return eprintsXslt;
	}

	@Required
	public void setEprintsXslt(final Resource eprintsXslt) {
		this.eprintsXslt = eprintsXslt;
	}

	public ServiceLocator<DatabaseService> getDbServiceLocator() {
		return dbServiceLocator;
	}

	@Required
	public void setDbServiceLocator(final ServiceLocator<DatabaseService> dbServiceLocator) {
		this.dbServiceLocator = dbServiceLocator;
	}

	public ProjectQueryParamsFactory getProjectQueryParamsFactory() {
		return projectQueryParamsFactory;
	}

	@Required
	public void setProjectQueryParamsFactory(final ProjectQueryParamsFactory projectQueryParamsFactory) {
		this.projectQueryParamsFactory = projectQueryParamsFactory;
	}
}
