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;

/**
 * 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 {

	/**
	 * IS Registry
	 */
	private ISRegistryService isRegistry;

	/**
	 * 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) {
				isRegistry.deleteProfile(resource.getResourceId());
				final String newId = isRegistry.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()));

			isRegistry.deleteProfile(resource.getResourceId());

			final String newId = isRegistry.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(final String resourceType) throws XPathExpressionException {
		return resourceKindResolver.getNormalKindForType(resourceType);
	}

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

	public ResourceKindResolver getResourceKindResolver() {
		return resourceKindResolver;
	}

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

	public ProfileValidationStrategy getProfileValidationStrategy() {
		return profileValidationStrategy;
	}

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

	public ISRegistryService getIsRegistry() {
		return isRegistry;
	}

	@Required
	public void setIsRegistry(final ISRegistryService isRegistry) {
		this.isRegistry = isRegistry;
	}

}
