package eu.dnetlib.enabling.is.registry;

import javax.annotation.Resource;
import javax.xml.xpath.XPathExpressionException;

import org.springframework.beans.factory.annotation.Required;

import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
import eu.dnetlib.enabling.tools.OpaqueResource;
import eu.dnetlib.enabling.tools.ServiceLocator;

/**
 * implement the compatibility pending profile policy.
 * 
 * <p>
 * pending profiles receive their own special resource kind and are 'moved' to a different collection
 * </p>
 * 
 * @author marko
 * 
 */
public class CompatPendingResourceManagerImpl implements PendingResourceManager, ResourceKindResolver {

	/**
	 * service locator for IS Store service. Necessary because this implementation of the pending resource manager needs
	 * to move profiles from one collection to the other.
	 */
	private ServiceLocator<ISRegistryService> registryLocator;

	/**
	 * This bean resolver
	 */
	private ResourceKindResolver resourceKindResolver;

	/**
	 * used to validate resources w.r.t. a set of defined properties.
	 */
	@Resource
	private ProfileValidationStrategy profileValidationStrategy;

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setPending(eu.dnetlib.enabling.tools.OpaqueResource)
	 */
	@Override
	public void setPending(final OpaqueResource resource, final boolean local) {
		try {
			resource.setResourceKind(getPendingKindForType(resource.getResourceType()));

			if (!local) {
				registryLocator.getService().deleteProfile(resource.getResourceId());

				final String newId = registryLocator.getService().registerProfile(resource.asString());
				resource.setResourceId(newId);
			}

		} catch (XPathExpressionException e) {
			throw new IllegalStateException(e);
		} catch (ISRegistryException e) {
			throw new IllegalStateException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setPending(eu.dnetlib.enabling.tools.OpaqueResource)
	 */
	@Override
	public void setPending(final OpaqueResource resource) {
		setPending(resource, false);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setValid(eu.dnetlib.enabling.tools.OpaqueResource)
	 */
	@Override
	public void setValid(final OpaqueResource resource) {
		try {
			if (resource.getResourceKind() != null && resource.getResourceKind().equals(getNormalKindForType(resource.getResourceType()))) {
				throw new IllegalArgumentException("trying to validate an already valid resource");
			}

			profileValidationStrategy.accept(resource, RegistrationPhase.Validate);

			resource.setResourceKind(getNormalKindForType(resource.getResourceType()));

			registryLocator.getService().deleteProfile(resource.getResourceId());

			final String newId = registryLocator.getService().registerProfile(resource.asString());
			resource.setResourceId(newId);

		} catch (XPathExpressionException e) {
			throw new IllegalStateException(e);
		} catch (ISRegistryException e) {
			throw new IllegalStateException(e);
		} catch (ValidationException e) {
			throw new IllegalStateException(e);
		}
	}

	@Override
	public String getNormalKindForType(String resourceType) throws XPathExpressionException {
		return resourceKindResolver.getNormalKindForType(resourceType);
	}

	@Override
	public String getPendingKindForType(String resourceType) throws XPathExpressionException {
		return resourceKindResolver.getPendingKindForType(resourceType);
	}

	public ServiceLocator<ISRegistryService> getRegistryLocator() {
		return registryLocator;
	}

	public void setRegistryLocator(final ServiceLocator<ISRegistryService> registryLocator) {
		this.registryLocator = registryLocator;
	}

	public ResourceKindResolver getResourceKindResolver() {
		return resourceKindResolver;
	}

	@Required
	public void setResourceKindResolver(ResourceKindResolver resourceKindResolver) {
		this.resourceKindResolver = resourceKindResolver;
	}

	public ProfileValidationStrategy getProfileValidationStrategy() {
		return profileValidationStrategy;
	}

	public void setProfileValidationStrategy(ProfileValidationStrategy profileValidationStrategy) {
		this.profileValidationStrategy = profileValidationStrategy;
	}
}
