/*
 * Copyright (c) 2012, 2018 CEA and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v20.html
 *
 * Contributors:
 *   Christian W. Damus (CEA) - initial API and implementation
 *   Kenn Hussey - 535301
 */
package org.eclipse.uml2.uml.validation;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.DiagnosticChain;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.validation.model.Category;
import org.eclipse.emf.validation.model.CategoryManager;
import org.eclipse.emf.validation.model.IModelConstraint;
import org.eclipse.emf.validation.service.AbstractConstraintProvider;
import org.eclipse.emf.validation.service.ConstraintExistsException;
import org.eclipse.emf.validation.service.IConstraintDescriptor;
import org.eclipse.uml2.common.util.UML2Util;
import org.eclipse.uml2.uml.UMLPlugin;

/**
 * A provider of constraints that delegate to an {@link EPackage}'s constraints
 * via its generated {@link EValidator}.
 */
public class DelegatingConstraintProvider
		extends AbstractConstraintProvider {

	private static final String E_CATEGORY = "category"; //$NON-NLS-1$

	private static final String A_PATH = "path"; //$NON-NLS-1$

	private static final String E_EVALIDATOR_PROVIDER = "eValidatorProvider"; //$NON-NLS-1$

	private static final String A_CLASS = "class"; //$NON-NLS-1$

	/**
	 * Initializes me.
	 */
	public DelegatingConstraintProvider() {
		super();
	}

	@Override
	public void setInitializationData(IConfigurationElement config,
			String propertyName, Object data)
			throws CoreException {

		super.setInitializationData(config, propertyName, data);

		// first, grab the categories that I'll be assigning to my constraints
		final Set<Category> categories = getCategories(config);

		// get an EValidator provider
		IEValidatorProvider validatorProvider = getEValidatorProvider(config);

		// then find the constraints that I need to adapt
		for (String next : getNamespaceUris()) {
			// find the EValidator for this package
			EPackage epackage = EPackage.Registry.INSTANCE.getEPackage(next);

			if (epackage == null) {
				UMLPlugin.INSTANCE
					.log(new Status(
						IStatus.WARNING,
						UMLPlugin.INSTANCE.getSymbolicName(),
						"No such EPackage available for model validation: " + next)); //$NON-NLS-1$
			} else {
				EValidator validator = validatorProvider
					.getEValidator(epackage);
				if (validator == null) {
					UMLPlugin.INSTANCE
						.log(new Status(
							IStatus.WARNING,
							UMLPlugin.INSTANCE.getSymbolicName(),
							"No generated validator available for package: " + next)); //$NON-NLS-1$
				} else {
					EValidator.SubstitutionLabelProvider labelProvider = validatorProvider
						.getSubstitutionLabelProvider(epackage);

					try {
						Iterable<? extends IModelConstraint> constraints = createConstraints(
							config.getNamespaceIdentifier(), epackage,
							validator, labelProvider);

						if (!categories.isEmpty()) {
							Category[] cats = categories
								.toArray(new Category[categories.size()]);
							for (IModelConstraint constraint : constraints) {
								IConstraintDescriptor desc = constraint
									.getDescriptor();
								for (int i = 0; i < cats.length; i++) {
									desc.addCategory(cats[i]);
								}
							}
						}
					} catch (ConstraintExistsException e) {
						throw new CoreException(new Status(IStatus.ERROR,
							UMLPlugin.INSTANCE.getSymbolicName(),
							"Failed to register model validation constraints.", //$NON-NLS-1$
							e));
					}
				}
			}
		}
	}

	private Set<Category> getCategories(IConfigurationElement config) {
		final Set<Category> result = new java.util.HashSet<Category>();
		for (IConfigurationElement next : config.getChildren(E_CATEGORY)) {
			String path = next.getAttribute(A_PATH);

			if (!UML2Util.isEmpty(path)) {
				// if the category doesn't already exist, it is implicitly
				// created, so
				// we won't get a null category
				result.add(CategoryManager.getInstance().getCategory(path));
			}
		}

		return result;
	}

	private IEValidatorProvider getEValidatorProvider(
			IConfigurationElement config) {

		IEValidatorProvider result = null;

		IConfigurationElement[] vpConfig = config
			.getChildren(E_EVALIDATOR_PROVIDER);
		if (vpConfig.length > 0) {
			Object ext;
			try {
				ext = vpConfig[0].createExecutableExtension(A_CLASS);
				if (ext instanceof IEValidatorProvider) {
					result = (IEValidatorProvider) ext;
				}
			} catch (CoreException e) {
				UMLPlugin.INSTANCE.log(e.getStatus());
			}
		}

		if (result == null) {
			result = new IEValidatorProvider.Default();
		}

		return result;
	}

	private Iterable<? extends IModelConstraint> createConstraints(
			final String namespace, final EPackage epackage,
			final EValidator validator,
			final EValidator.SubstitutionLabelProvider labelProvider)
			throws ConstraintExistsException {

		final List<IModelConstraint> result = new java.util.ArrayList<IModelConstraint>();
		final Matcher m = Pattern.compile("validate\\w+_validate(\\w+)") //$NON-NLS-1$
			.matcher(""); //$NON-NLS-1$
		final Map<Class<?>, EClass> eclasses = new java.util.HashMap<Class<?>, EClass>();

		for (Method next : validator.getClass().getDeclaredMethods()) {
			if (Modifier.isPublic(next.getModifiers())) {
				final Class<?>[] signature = next.getParameterTypes();

				m.reset(next.getName());
				if (m.matches()
					&& isConstraintMethod(next.getReturnType(), signature)) {
					EClass eclass = getEClass(eclasses, epackage, signature[0]);

					// constraint methods could exist for EDataTypes; this
					// framework doesn't handle them
					if (eclass != null) {
						result.add(new DelegatingModelConstraint(namespace,
							validator, labelProvider, eclass, next));
					}
				}
			}
		}

		getConstraints().addAll(result);
		registerConstraints(result);

		return result;
	}

	private static boolean isConstraintMethod(Class<?> returnType,
			Class<?>[] parameterTypes) {

		boolean result = false;

		if ((returnType == boolean.class) && (parameterTypes.length == 3)) {
			result = EObject.class.isAssignableFrom(parameterTypes[0])
				&& (parameterTypes[1] == DiagnosticChain.class)
				&& (parameterTypes[2] == Map.class);
		}

		return result;
	}

	/**
	 * Look up an {@link EClass} by instance-class, using a cache for
	 * performance of repeated queries.
	 * 
	 * @param cache
	 *            a cache of previous look-up results
	 * @param epackage
	 *            the epackage in which to find the eclass
	 * @param interfaceType
	 *            the Java interface type by which to look up the eclass
	 * 
	 * @return the eclass, or {@code null} if not found
	 */
	private static EClass getEClass(Map<Class<?>, EClass> cache,
			EPackage epackage, Class<?> interfaceType) {

		EClass result = cache.get(interfaceType);

		if (result == null) {
			for (EClassifier next : epackage.getEClassifiers()) {
				if ((next.getInstanceClass() == interfaceType)
					&& (next instanceof EClass)) {
					result = (EClass) next;
					cache.put(interfaceType, result);
					break;
				}
			}
		}

		return result;
	}
}
