package org.matheclipse.core.patternmatching;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import org.matheclipse.core.basic.Config;
import org.matheclipse.core.convert.AST2Expr;
import org.matheclipse.core.eval.interfaces.IFunctionEvaluator;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.parser.client.Parser;
import org.matheclipse.parser.client.ast.ASTNode;

public class PatternMatcherAndInvoker extends PatternMatcher {
	/**
   * 
   */
	private static final long serialVersionUID = -2448717771259975643L;

	private transient Method fMethod;
	private transient Type[] fTypes;
	private transient IFunctionEvaluator fInstance;

	@Override
	public Object clone() throws CloneNotSupportedException {
		PatternMatcherAndInvoker v = (PatternMatcherAndInvoker) super.clone();
		v.fMethod = fMethod;
		v.fTypes = fTypes;
		v.fInstance = fInstance;
		return v;
	}

	/**
	 * Create a pattern-matching rule which invokes the method name in the given
	 * instance, if leftHandSide is matching.
	 * 
	 * @param leftHandSide
	 *            could contain pattern expressions for "pattern-matching"
	 * @param instance
	 *            instance of an IFunctionEvaluator interface
	 * @param method
	 *            method to call
	 */
	public PatternMatcherAndInvoker(final IExpr leftHandSide, IFunctionEvaluator instance, final String methodName) {
		super(leftHandSide);
		this.fInstance = instance;
		initInvoker(instance, methodName);
	}

	/**
	 * Create a pattern-matching rule which invokes the method name in the given
	 * instance, if leftHandSide is matching.
	 * 
	 * @param leftHandSide
	 * @param instance
	 * @param methodName
	 */
	public PatternMatcherAndInvoker(final String leftHandSide, IFunctionEvaluator instance, final String methodName) {
		this.fInstance = instance;
		Parser parser = new Parser();
		ASTNode node = parser.parse(leftHandSide);
		IExpr lhs = AST2Expr.CONST.convert(node);
		fLhsPatternExpr = lhs;
		init(fLhsPatternExpr);
		initInvoker(instance, methodName);
	}

	private void initInvoker(IFunctionEvaluator instance, final String methodName) {
		Class c = instance.getClass();
		Method[] declaredMethods = c.getDeclaredMethods();
		List namedMethods = new ArrayList();
		for (Method method : declaredMethods) {
			if (method.getName().equals(methodName))
				namedMethods.add(method);
		}
		if (namedMethods.size() == 1) {
			this.fMethod = namedMethods.get(0);
			this.fTypes = fMethod.getGenericParameterTypes();
		} else {
			// throw an exception ?
		}
	}

	@Override
	public IExpr eval(final IExpr leftHandSide) {
		IExpr result = null;
		if (isRuleWithoutPatterns() && fLhsPatternExpr.equals(leftHandSide)) {
			if (fTypes.length != 0) {
				return null;
			}
			try {
				result = (IExpr) fMethod.invoke(fInstance);
			} catch (IllegalArgumentException e) {
				if (Config.SHOW_STACKTRACE) {
					e.printStackTrace();
				}
			} catch (IllegalAccessException e) {
				if (Config.SHOW_STACKTRACE) {
					e.printStackTrace();
				}
			} catch (InvocationTargetException e) {
				if (Config.SHOW_STACKTRACE) {
					e.printStackTrace();
				}
			}
			return result;
		}
		if (fTypes.length != fPatternMap.size()) {
			return null;
		}
		fPatternMap.initPattern();
		if (matchExpr(fLhsPatternExpr, leftHandSide)) {

			List args = fPatternMap.getValuesAsList();
			result = null;
			try {
				result = (IExpr) fMethod.invoke(fInstance, args.toArray());
			} catch (IllegalArgumentException e) {
				if (Config.SHOW_STACKTRACE) {
					e.printStackTrace();
				}
			} catch (IllegalAccessException e) {
				if (Config.SHOW_STACKTRACE) {
					e.printStackTrace();
				}
			} catch (InvocationTargetException e) {
				if (Config.SHOW_STACKTRACE) {
					e.printStackTrace();
				}
			}
		}
		return result;
	}

	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj instanceof PatternMatcherAndInvoker) {
			// don't compare fInstance, fMethod, fTypes here
			return super.equals((PatternMatcherAndInvoker) obj);
		}

		return false;
	}

	@Override
	public int hashCode() {
		return super.hashCode() * 47;
	}
}
 

Ads help maintain this website.