/******************************************************************************* * Copyright (c) 2011 Sebastian Benz. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Sebastian Benz - initial API and implementation ******************************************************************************/ package de.sebastianbenz.task.query; import org.eclipse.emf.ecore.EObject; import org.eclipse.xtext.util.Pair; import org.eclipse.xtext.util.PolymorphicDispatcher; import org.eclipse.xtext.util.SimpleCache; import org.eclipse.xtext.util.Tuples; import com.google.common.base.Function; import com.google.common.base.Joiner; import de.sebastianbenz.task.Container; import de.sebastianbenz.task.Content; import de.sebastianbenz.task.Note; import de.sebastianbenz.task.Project; import de.sebastianbenz.task.Tag; import de.sebastianbenz.task.Task; public class QueryInterpreter { private PolymorphicDispatcher<Boolean> selectDispatcher = PolymorphicDispatcher .createForSingleTarget("_select", 2, 2, this); private SimpleCache<Pair<Query, EObject>, Boolean> selectionCache = new SimpleCache<Pair<Query,EObject>, Boolean>(new Function<Pair<Query, EObject>, Boolean>() { public Boolean apply(Pair<Query, EObject> args) { Query query = args.getFirst(); EObject element = args.getSecond(); if (element instanceof Container) { for (Content child : ((Container)element).getChildren()) { if(select(query, child)){ return true; } } } return internalSelect(query.getExpression(), element); } }); public boolean select(Query query, EObject element) { if (query == null || element == null) { return true; } if (query.getExpression() == null) { return true; } return selectionCache.get(Tuples.create(query, element)); } protected boolean internalSelect(Expression expr, EObject target) { if (expr == null || target == null) { return true; } return selectDispatcher.invoke(expr, target); } protected boolean _select(EObject expr, EObject object) { return false; } protected boolean _select(AndExpr andExpr, EObject object) { return internalSelect(andExpr.getLeft(), object) && internalSelect(andExpr.getRight(), object); } protected boolean _select(ParenExpr expr, EObject object) { return internalSelect(expr.getExpr(), object); } protected boolean _select(OrExpr expr, EObject object) { return internalSelect(expr.getLeft(), object) || internalSelect(expr.getRight(), object); } protected boolean _select(CompEqExpr expr, Task task) { if (isNotValue(expr.getLeft())) { return false; } if (isNotValue(expr.getRight())) { return false; } String left = valueOf((Value) expr.getLeft(), task); String right = valueOf((Value) expr.getRight(), task); if(left == null || right == null){ return false; } boolean isEqual = left.equals(right); if (expr.getOperator() == CompEqOperator.EQUAL) { return isEqual; } else { return !isEqual; } } protected boolean _select(CompExpr expr, Task task) { // FIXME left / right might be words String left = valueOf(expr.getLeft(), task); String right = valueOf(expr.getRight(), task); switch (expr.getOperator()) { case GREATER: return left.compareTo(right) > 0; case GREATER_EQUAL: return left.compareTo(right) >= 0; case LESS: return left.compareTo(right) < 0; case LESS_EQUAL: return left.compareTo(right) <= 0; } // try{ // Number left = asNumber((Value) expr.getLeft(), task); // if(left == null){ // return false; // } // Number right = asNumber((Value) expr.getRight(), task); // if(right == null){ // return false; // } // }catch (NumberFormatException e) { // // TODO: handle exception // } // // switch (expr.getOperator()) { // case GREATER: // return Numbers.greater(left, right); // case GREATER_EQUAL: // return Numbers.greaterEqual(left, right); // case LESS: // return Numbers.less(left, right); // case LESS_EQUAL: // return Numbers.lessEqual(left, right); // } return false; } protected boolean _select(Words words, Content content){ for (String word : words.getValues()) { if(!matches(content, word)){ return false; } } return true; } protected boolean _select(Word word, Content content){ return matches(content, word.getValue()); } protected boolean _select(Phrase phrase, Content content){ return matches(content, phrase.getValue()); } protected boolean matches(Content content, String string) { return content.getValue().contains(string); } private String valueOf(Expression value, Task task) { if (value instanceof TagReference) { for (Tag tag : task.getTags()) { TagReference tagReference = (TagReference)value; if (tag.getName().equals(tagReference.getValue())) { return tag.getValue(); } } return ""; } else if (value instanceof Value) { return ((Value) value).getValue(); }else if (value instanceof Words) { Words words = (Words) value; return Joiner.on(" ").join(words.getValues()); }else{ return ""; } } protected boolean isNotValue(Expression expr) { return expr == null || !(expr instanceof Value) || ((Value)expr).getValue() == null; } protected boolean _select(UnaryExpr expr, EObject object) { return !internalSelect(expr.getExpr(), object); } protected boolean _select(TagReference tagReference, Content content) { String tag = tagReference.getValue(); for (Tag current : content.getTags()) { if (current.getName().startsWith(tag)) { return true; } } return false; } protected boolean _select(TaskReference taskReference, Task task) { return task.getValue().contains(taskReference.getValue()); } protected boolean _select(TextReference taskReference, Note note) { return note.getValue().contains(taskReference.getValue()); } protected boolean _select(ProjectReference projectReference, Project project) { String projectName = projectReference.getValue(); if (projectName == null) { return true; } if(project.getValue() == null){ return false; } if (project.getValue().startsWith(projectName)) { return true; } return internalSelect(projectReference, project.getParent()); } protected boolean _select(ProjectReference projectReference, Content content) { Container parent = content.getParent(); while (parent != null) { if (parent instanceof Project && internalSelect(projectReference, parent)) { return true; } if (parent instanceof Content) { parent = ((Content) parent).getParent(); }else{ parent = null; } } return false; } }