package org.matheclipse.core.expression;

import java.util.List;
import java.util.Map;

import org.matheclipse.core.basic.Config;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.generic.Predicates;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IPattern;
import org.matheclipse.core.interfaces.ISymbol;
import org.matheclipse.core.patternmatching.IPatternMatcher;
import org.matheclipse.core.patternmatching.PatternMatcher;
import org.matheclipse.core.visit.IVisitor;
import org.matheclipse.core.visit.IVisitorBoolean;
import org.matheclipse.core.visit.IVisitorInt;

import com.google.common.base.Predicate;

/**
 * A concrete pattern implementation.
 * 
 */
public class Pattern extends ExprImpl implements IPattern {

	private static final long serialVersionUID = 7617138748475243L;

	private static Pattern NULL_PATTERN = new Pattern(null);

	/**
	 * 
	 */
	public static IPattern valueOf(final ISymbol symbol, final IExpr check, final boolean def) {
		return new Pattern(symbol, check, def);
		// p.fSymbol = symbol;
		// p.fCondition = check;
		// p.fDefault = def;
		// return p;
	}

	/**
	 * 
	 * @param numerator
	 * @return
	 */
	public static IPattern valueOf(final ISymbol symbol, final IExpr check) {
		return new Pattern(symbol, check);
		// p.fSymbol = symbol;
		// p.fCondition = check;
		// return p;
	}

	public static IPattern valueOf(final ISymbol symbol) {
		if (symbol == null) {
			return NULL_PATTERN;
		}
		// IPattern value = F.PREDEFINED_PATTERN_MAP.get(symbol.toString());
		// if (value != null) {
		// return value;
		// }
		return new Pattern(symbol);
	}

	/**
	 * The expression which should check this pattern
	 */
	final IExpr fCondition;

	/**
	 * Index for the pattern-matcher
	 * 
	 * @see org.matheclipse.core.patternmatching.PatternMatcher
	 */
	int fIndex = -1;

	/**
	 * The hash value of this object computed in the constructor.
	 * 
	 */
	final int fHashValue;

	/**
	 * The associated symbol for this pattern
	 */
	final ISymbol fSymbol;

	/**
	 * Use default value, if no matching expression was found
	 */
	final boolean fDefault;

	private Pattern() {
		this(null, null, false);
	}

	/** package private */
	Pattern(final ISymbol symbol) {
		this(symbol, null, false);
	}

	/** package private */
	Pattern(final ISymbol symbol, IExpr condition) {
		this(symbol, condition, false);
	}

	/** package private */
	Pattern(final ISymbol symbol, IExpr condition, boolean def) {
		fHashValue = (symbol == null) ? 199 : 19 + symbol.hashCode();
		fSymbol = symbol;
		fCondition = condition;
		fDefault = def;
	}

	@Override
	public boolean equals(final Object obj) {
		if (hashCode() != obj.hashCode()) {
			return false;
		}
		if (obj instanceof Pattern) {
			if (this == obj) {
				return true;
			}
			Pattern pattern = (Pattern) obj;
			if (fSymbol == pattern.fSymbol) {
				if ((fCondition != null) && (pattern.fCondition != null)) {
					return fCondition.equals(pattern.fCondition);
				}
				return fCondition == pattern.fCondition;
			}
		}
		return false;
	}

	public IExpr getCondition() {
		return fCondition;
	}

	/**
	 * @return
	 */
	public int getIndex() {
		return fIndex;
	}

	/**
	 * @return
	 */
	public ISymbol getSymbol() {
		return fSymbol;
	}

	@Override
	public int hashCode() {
		return fHashValue;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.matheclipse.parser.interfaces.IExpr#hierarchy()
	 */
	public int hierarchy() {
		return PATTERNID;
	}

	// public boolean isString(final String str) {
	// if (fSymbol == null) {
	// return str == null;
	// }
	// return fSymbol.toString().equals(str);
	// }

	public void setIndex(final int i) {
		fIndex = i;
	}

	// public String toString() {
	// if (fCheck == null) {
	// return fSymbol.toString() + "_";
	// }
	// return fSymbol.toString() + "_" + fCheck.toString();
	// }

	@Override
	public String internalFormString(boolean symbolsAsFactoryMethod, int depth) {
		if (symbolsAsFactoryMethod) {
			final StringBuffer buffer = new StringBuffer();
			buffer.append("$p(");
			if (fSymbol == null) {
				buffer.append("(ISymbol)null");
				if (fCondition != null) {
					buffer.append("," + fCondition.internalFormString(symbolsAsFactoryMethod, 0));
				}
				if (fDefault) {
					if (fCondition == null) {
						buffer.append(",null");
					}
					buffer.append(",true");
				}
			} else {
				String symbolStr = fSymbol.toString();
				char ch = symbolStr.charAt(0);
				if (symbolStr.length() == 1 && fCondition == null && !fDefault) {
					if ('a' <= ch && ch <= 'z') {
						return "$p(" + symbolStr + ")";
					}
				}
				if (symbolStr.length() == 1 && ('a' <= ch && ch <= 'z')) {
					buffer.append(symbolStr);
				} else {
					buffer.append("\"" + symbolStr + "\"");
				}
				if (fCondition != null) {
					buffer.append("," + fCondition.internalFormString(symbolsAsFactoryMethod, 0));
				}
				if (fDefault) {
					// if (fCondition == null) {
					// buffer.append(",null");
					// }
					buffer.append(",true");
				}
			}
			buffer.append(')');
			return buffer.toString();
		}
		return toString();
	}

	@Override
	public String toString() {
		final StringBuffer buffer = new StringBuffer();
		if (fSymbol == null) {
			buffer.append('_');
			if (fDefault) {
				buffer.append('.');
			}
			if (fCondition != null) {
				buffer.append(fCondition.toString());
			}
		} else {
			if (fCondition == null) {
				buffer.append(fSymbol.toString());
				buffer.append('_');
				if (fDefault) {
					buffer.append('.');
				}
			} else {
				buffer.append(fSymbol.toString());
				buffer.append('_');
				if (fDefault) {
					buffer.append('.');
				}
				buffer.append(fCondition.toString());
			}
		}
		return buffer.toString();
	}

	public String fullFormString() {
		StringBuffer buf = new StringBuffer();
		if (fSymbol == null) {
			buf.append("Blank");
			if (Config.PARSER_USE_LOWERCASE_SYMBOLS) {
				buf.append('(');
			} else {
				buf.append('[');
			}
			if (fCondition != null) {
				buf.append(fCondition.fullFormString());
			}
			if (Config.PARSER_USE_LOWERCASE_SYMBOLS) {
				buf.append(')');
			} else {
				buf.append(']');
			}
		} else {
			buf.append("Pattern");
			if (Config.PARSER_USE_LOWERCASE_SYMBOLS) {
				buf.append('(');
			} else {
				buf.append('[');
			}
			buf.append(fSymbol.toString());
			buf.append(", ");
			buf.append("Blank");
			if (Config.PARSER_USE_LOWERCASE_SYMBOLS) {
				buf.append('(');
			} else {
				buf.append('[');
			}
			if (fCondition != null) {
				buf.append(fCondition.fullFormString());
			}
			if (Config.PARSER_USE_LOWERCASE_SYMBOLS) {
				buf.append("))");
			} else {
				buf.append("]]");
			}
		}

		return buf.toString();
	}

	/**
	 * Compares this expression with the specified expression for order. Returns
	 * a negative integer, zero, or a positive integer as this expression is
	 * canonical less than, equal to, or greater than the specified expression.
	 */
	public int compareTo(final IExpr obj) {
		if (obj instanceof Pattern) {
			int cp;
			if (fSymbol == null) {
				if (((Pattern) obj).fSymbol == null) {
					cp = -1;
				} else {
					cp = 0;
				}
			} else if (((Pattern) obj).fSymbol == null) {
				cp = 1;
			} else {
				cp = fSymbol.compareTo(((Pattern) obj).fSymbol);
			}
			if (cp != 0) {
				return cp;
			}
			if (fCondition == null) {
				if (((Pattern) obj).fCondition != null) {
					return -1;
				}
				return 0;
			} else {
				if (((Pattern) obj).fCondition == null) {
					return 1;
				} else {
					return fCondition.compareTo(((Pattern) obj).fCondition);
				}
			}
		}
		return (hierarchy() - (obj).hierarchy());
	}

	public ISymbol head() {
		return F.PatternHead;
	}

	public boolean isBlank() {
		return (fSymbol == null);
	}

	public boolean isConditionMatched(final IExpr expr) {
		if (fCondition == null) {
			return true;
		}
		if (expr.head().equals(fCondition)) {
			return true;
		}
		EvalEngine engine = EvalEngine.get();
		boolean traceMode = false;
		try {
			traceMode = engine.isTraceMode();
			engine.setTraceMode(false);
			final Predicate matcher = Predicates.isTrue(engine, fCondition);
			return matcher.apply(expr);
		} finally {
			if (traceMode) {
				engine.setTraceMode(true);
			}
		}
	}

	@Override
	public IExpr variables2Slots(final Map map, final List variableList) {
		return null;
	}

	/**
	 * {@inheritDoc}
	 */
	public  T accept(IVisitor visitor) {
		return visitor.visit(this);
	}

	/**
	 * {@inheritDoc}
	 */
	public boolean accept(IVisitorBoolean visitor) {
		return visitor.visit(this);
	}

	/**
	 * {@inheritDoc}
	 */
	public int accept(IVisitorInt visitor) {
		return visitor.visit(this);
	}

	/**
	 * Use default value, if not matching was found.
	 * 
	 * @return
	 */
	public boolean isDefault() {
		return fDefault;
	}

	/** {@inheritDoc} */
	final public boolean isPattern() {
		return true;
	}

	/** {@inheritDoc} */
	public final boolean isPatternExpr() {
		return true;
	}

	/**
	 * Groovy operator overloading
	 */
	public boolean isCase(IExpr that) {
		final IPatternMatcher matcher = new PatternMatcher(this);
		if (matcher.apply(that)) {
			return true;
		}
		return false;
	}

}
 

Ads help maintain this website.