package eu.dnetlib.enabling.ui.server;

import java.io.*;
import java.util.List;
import java.util.UUID;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.xml.sax.SAXException;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
import eu.dnetlib.enabling.is.store.BulkResourceImporter;
import eu.dnetlib.enabling.tools.ServiceLocator;
import eu.dnetlib.enabling.tools.StreamOpaqueResource;
import eu.dnetlib.enabling.ui.common.beans.DHNInfo;
import eu.dnetlib.enabling.ui.common.beans.MDStoreInfo;
import eu.dnetlib.enabling.ui.common.beans.RepositoryAggrInfo;
import eu.dnetlib.enabling.ui.common.beans.RepositoryMDStoreInfo;
import eu.dnetlib.enabling.ui.common.services.MyGwtException;
import eu.dnetlib.enabling.ui.common.services.RegistryService;

public class RegistryServlet extends RemoteServiceServlet implements RegistryService, ResourceLoaderAware {

	private static final long serialVersionUID = 8541042711174183040L;
	private ServiceLocator<ISRegistryService> isRegistryLocator;
	private ServiceLocator<ISLookUpService> isLookUpLocator;

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

	/**
	 * resource loader.
	 */
	private ResourceLoader resourceLoader;

	/**
	 * resource importer.
	 */
	private BulkResourceImporter resourceImporter;

	public RegistryServlet() {
		super();
	}

	public ServiceLocator<ISRegistryService> getIsRegistryLocator() {
		return isRegistryLocator;
	}

	@Required
	public void setIsRegistryLocator(final ServiceLocator<ISRegistryService> isRegistryLocator) {
		this.isRegistryLocator = isRegistryLocator;
	}

	public ServiceLocator<ISLookUpService> getIsLookUpLocator() {
		return isLookUpLocator;
	}

	@Required
	public void setIsLookUpLocator(final ServiceLocator<ISLookUpService> isLookUpLocator) {
		this.isLookUpLocator = isLookUpLocator;
	}

	public Boolean deleteProfile(final String id) {
		try {
			return isRegistryLocator.getService().deleteProfile(id);
		} catch (final Exception e) {
			return false;
		}
	}

	public Boolean removeAllProfiles(final List<String> list) {
		final ISRegistryService registry = isRegistryLocator.getService();
		for (final String profId : list) {
			try {
				registry.deleteProfile(profId);
			} catch (final Exception e) {
			}
		}
		return true;
	}

	public String invalidateProfile(final String id) {
		try {
			return isRegistryLocator.getService().invalidateProfile(id);
		} catch (final Exception e) {
			return null;
		}
	}

	public String validateProfile(final String id) {
		try {
			return isRegistryLocator.getService().validateProfile(id);
		} catch (final Exception e) {
			return null;
		}
	}

	public Boolean fixRepositoryFromIndex(final String id) throws MyGwtException {

		try {
			final RepositoryAggrInfo aggrRepo = Common.getRepoStatusInfo(id, isLookUpLocator.getService());
			String dmfId = null;
			for (final RepositoryMDStoreInfo md : aggrRepo.getFormats()) {
				if (md.getMdName().equals("DMF")) {
					dmfId = md.getMdstoreId();
				}
			}
			if (dmfId != null) {
				final MDStoreInfo mdInfo = Common.getMDStoreInfo(dmfId, isLookUpLocator.getService());
				if (mdInfo != null) {
					final int size = mdInfo.getIndexSize();

					isRegistryLocator.getService().updateProfileNode(id, "//NUMBER_OF_OBJECTS", "<NUMBER_OF_OBJECTS>" + size + "</NUMBER_OF_OBJECTS>");
				}
			}
		} catch (final Exception e) {
			return false;
		}
		return true;
	}

	public String importProfiles(final String path) throws MyGwtException {
		log.info("importing profiles in " + path);

		int cOk = 0;
		int cTotal = 0;

		try {
			final File dirDone = new File(path + "/done_" + UUID.randomUUID());
			boolean doneDirCreated = false;
			for (final Resource res : ResourcePatternUtils.getResourcePatternResolver(resourceLoader).getResources("file://" + path + "/*")) {
				if (res.getFile().isFile()) {
					cTotal++;
					if (registerFile(res)) {
						if(!doneDirCreated)
							doneDirCreated = dirDone.mkdirs();

						// move the file only if we could create the dest dir
						if(doneDirCreated)
							res.getFile().renameTo(new File(dirDone, res.getFile().getName()));
						cOk++;
					}
				}
			}
		} catch (final IOException e) {
			log.info("got some exception: " + e);
			throw new MyGwtException("cannot find profiles to import", e.toString());
		}

		return cOk + "/" + cTotal;
	}

	public Boolean uploadDefaultSchemas() {

		//TODO ???

		return false;
	}

	public Boolean updateDHN(final DHNInfo info) throws MyGwtException {
		final String textProps = "<SERVICE_PROPERTIES>" + "<PROPERTY key='name' value='" + info.getName() + "'/>" + "<PROPERTY key='latitude' value='"
				+ info.getLat() + "'/>" + "<PROPERTY key='longitude' value='" + info.getLng() + "'/>" + "<PROPERTY key='timezone' value='"
				+ info.getTimezone() + "'/>" + "</SERVICE_PROPERTIES>";

		try {
			return isRegistryLocator.getService().updateProfileNode(info.getIdentifier(), "//SERVICE_PROPERTIES", textProps);
		} catch (final ISRegistryException e) {
			throw new MyGwtException(e.getMessage(), "");
		}
	}

	protected boolean registerFile(final Resource resource) {
		try {
			resourceImporter.importResource(new StreamOpaqueResource(resource.getInputStream()));
			return true;
		} catch (ISRegistryException e) {
			log.warn("cannot import profile", e);
		} catch (XPathExpressionException e) {
			log.warn("cannot import profile", e);
		} catch (SAXException e) {
			log.warn("cannot import profile", e);
		} catch (IOException e) {
			log.warn("cannot import profile", e);
		} catch (ParserConfigurationException e) {
			log.warn("cannot import profile", e);
		}

		log.warn("cannot import profile " + resource.getFilename());
		return false;
	}

	@Override
	public void setResourceLoader(final ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}

	public BulkResourceImporter getResourceImporter() {
		return resourceImporter;
	}

	@Required
	public void setResourceImporter(final BulkResourceImporter resourceImporter) {
		this.resourceImporter = resourceImporter;
	}
}
