package eu.dnetlib.data.espas.dataprovider;

import eu.dnetlib.api.data.espas.DataProviderServiceException;
import eu.dnetlib.api.enabling.ISLookUpService;
import eu.dnetlib.api.enabling.ISLookUpServiceException;
import eu.dnetlib.api.enabling.ISRegistryService;
import eu.dnetlib.api.enabling.ISRegistryServiceException;
import eu.dnetlib.domain.data.espas.HarvestHistory;
import eu.dnetlib.domain.data.espas.HarvestSchedule;
import gr.uoa.di.driver.util.ServiceLocator;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.joda.time.DateTime;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.StringWriter;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * Created by antleb on 6/24/14.
 */
@Transactional(propagation = Propagation.REQUIRED)
public class HarvestManager {

	private static Logger logger = Logger.getLogger(HarvestManager.class);

	private DataProviderDao dataProviderDao;
	private HarvestHistoryDao harvestHistoryDao;
	private ScheduleDao scheduleDao;

	private ServiceLocator<ISLookUpService> lookUpService;
	private ServiceLocator<ISRegistryService> registryService;

	public void harvest(List<String> types, Date dateFrom, Date dateTo, String dataProviderId) throws DataProviderServiceException {
		String cswId = null;
		HarvestHistory harvestHistory = new HarvestHistory();

		harvestHistory.setHarvestId(UUID.randomUUID().toString());
		harvestHistory.setTypes(types);
		harvestHistory.setStartDate(dateFrom);
		harvestHistory.setFinishDate(dateTo);
		harvestHistory.setRecordCount(0);
		harvestHistory.setDataProviderId(dataProviderId);
		harvestHistory.setErrors(Collections.EMPTY_LIST);

		try {
			harvestHistoryDao.saveHarverstHistory(harvestHistory);

			cswId = getCSWId(dataProviderId);
			String harvestProfile = createHarvestProfile(cswId, dateFrom, dateTo, types);

			logger.debug("Saving harvest profile: \n" + harvestProfile);

			saveHarvestProfile(harvestProfile);
		} catch (Exception e) {
			logger.error("Error initiating harvest", e);

			throw new DataProviderServiceException("Error initiating harvest", e);
		}
	}

	private String getCSWId(String dataProviderId) throws ISLookUpServiceException, SQLException {
		String cswURL = dataProviderDao.getProviderCSWURL(dataProviderId);
		String xquery = "//RESOURCE_PROFILE[starts-with(.//BASE_URL, '" + cswURL + "')]/HEADER[./RESOURCE_TYPE/@value='CatalogueServiceResourceType']/RESOURCE_IDENTIFIER/@value/string()";

		logger.debug("Searching for csw id using xquery: " + xquery);

		String cswId = lookUpService.getService().getResourceProfileByQuery(xquery);

		return cswId;
	}

	private void saveHarvestProfile(String harvestProfile) throws ISRegistryServiceException {
		registryService.getService().registerProfile(harvestProfile);
	}

	private String createHarvestProfile(String cswId, Date dateFrom, Date dateTo, List<String> types) throws Exception {
		logger.info("Creating harvest profile for csw " + cswId + " time period: " + dateFrom + " - " + dateTo + " and types " + types);
		VelocityEngine ve = new VelocityEngine();
		StringWriter sw = new StringWriter();

		ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
		ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
		ve.setProperty("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.NullLogSystem");

		ve.init();

		Template t = ve.getTemplate("/eu/dnetlib/data/espas/dataprovider/harvestProfile.vm");
		VelocityContext vc = new VelocityContext();

		vc.put("cswId", cswId);
		vc.put("dateFrom", new DateTime(dateFrom).toString("yyyy-MM-dd'T'HH:mm:ssZ"));
		vc.put("dateTo", new DateTime(dateTo).toString("yyyy-MM-dd'T'HH:mm:ssZ"));
		vc.put("types", StringUtils.join(types, ","));

		t.merge(vc, sw);

		return sw.toString();
	}

	public static void main(String[] args) {
		System.out.println(new DateTime().toString("yyyy-MM-dd'T'HH:mm:ssZ"));
	}

	public DataProviderDao getDataProviderDao() {
		return dataProviderDao;
	}

	public void setDataProviderDao(DataProviderDao dataProviderDao) {
		this.dataProviderDao = dataProviderDao;
	}

	public HarvestHistoryDao getHarvestHistoryDao() {
		return harvestHistoryDao;
	}

	public void setHarvestHistoryDao(HarvestHistoryDao harvestHistoryDao) {
		this.harvestHistoryDao = harvestHistoryDao;
	}

	public ScheduleDao getScheduleDao() {
		return scheduleDao;
	}

	public void setScheduleDao(ScheduleDao scheduleDao) {
		this.scheduleDao = scheduleDao;
	}

	public ServiceLocator<ISLookUpService> getLookUpService() {
		return lookUpService;
	}

	public void setLookUpService(ServiceLocator<ISLookUpService> lookUpService) {
		this.lookUpService = lookUpService;
	}

	public ServiceLocator<ISRegistryService> getRegistryService() {
		return registryService;
	}

	public void setRegistryService(ServiceLocator<ISRegistryService> registryService) {
		this.registryService = registryService;
	}
}