public class Annotation implements Serializable {

    String text;
    HashMap features;
    Long startOffset;
    Long endOffset;

    public HashMap getFeatures() {
        return features;
    }

    public void setFeatures(HashMap features) {
        this.features = features;
    }

    List<Tree> syntaxTree;

    public List<Tree> getSyntaxTree() {
        return syntaxTree;
    }

    public void setSyntaxTree(List<Tree> syntaxTree) {
        this.syntaxTree = syntaxTree;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Long getStartOffset() {
        return startOffset;
    }

    public void setStartOffset(Long startOffset) {
        this.startOffset = startOffset;
    }

    public Long getEndOffset() {
        return endOffset;
    }

    public void setEndOffset(Long endOffSet) {
        this.endOffset = endOffSet;
    }

    public String toString() {
        StringBuffer buffer = new StringBuffer("");
        buffer.append(" Annotation: StartOffset:" + startOffset);
        buffer.append(" End offset:" + endOffset);
        buffer.append(" String:" + text);
        buffer.append(" Syntax tree:" + syntaxTree);
        if (features != null)
            buffer.append(" Features:" + features.toString());
        return buffer.toString();
    }

    public boolean equals(Object anotherObject) {
        if (this == anotherObject)
            return true;
        if (!(anotherObject instanceof Annotation))
            return false;
        if (this.startOffset == null && this.endOffset == null
                        && ((Annotation) anotherObject).startOffset != null
                        && ((Annotation) anotherObject).endOffset != null)
            return true;
        if ((anotherObject != null)
                        && (this.startOffset.longValue() == ((Annotation) anotherObject)
                                        .getStartOffset().longValue())
                        && (this.endOffset.longValue() == ((Annotation) anotherObject)
                                        .getEndOffset().longValue())
                        && (this.features.equals(((Annotation) anotherObject).features)
                        ))

            return true;
        else
            return false;
    }

    /**
     * 
     * @param aAnnot
     * @return
     */
    public boolean overlaps(Annotation aAnnot) {
        if (aAnnot == null) return false;
        if (aAnnot.getStartOffset() == null ||
                        aAnnot.getEndOffset() == null) return false;

        if (aAnnot.getEndOffset().longValue() <= this.getStartOffset().longValue())
            return false;

        if (aAnnot.getStartOffset().longValue() >= this.getEndOffset().longValue())
            return false;

        return true;
    }// overlaps


    public Object clone() {
        Object deepCopy = null;
        ByteArrayOutputStream byteArrOs = new ByteArrayOutputStream();
        ObjectOutputStream objOs;
        try {
            objOs = new ObjectOutputStream(byteArrOs);
            objOs.writeObject(this);
            ByteArrayInputStream byteArrIs =
                            new ByteArrayInputStream(byteArrOs.toByteArray());
            ObjectInputStream objIs = new ObjectInputStream(byteArrIs);
            deepCopy = objIs.readObject();
            return deepCopy;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return deepCopy;
    }

}
 public class DatatypePropertyValueElement implements OntologyElement {

	boolean isAnswer;

	public boolean isAnswer() {
		return isAnswer;
	}

	public void setAnswer(boolean isAnswer) {
		this.isAnswer = isAnswer;
	}

	/** max min sum */
	String function;

	public String getFunction() {
		return function;
	}

	public void setFunction(String function) {
		this.function = function;
	}

	/*
	 * this flag indicates whether the element is already in the list of
	 * elements and whether it should be ignored except for the function; this
	 * happens when some existing elements are modified with for example max min
	 * etc
	 */
	boolean alreadyAdded;

	public boolean isAlreadyAdded() {
		return alreadyAdded;
	}

	public void setAlreadyAdded(boolean alreadyAdded) {
		this.alreadyAdded = alreadyAdded;
	}

	/**
	 * 
	 */
	private static final long serialVersionUID = -4392076964893243529L;
	public boolean mainSubject = false;
	public List<String> results;
	Annotation annotation = new Annotation();

	public Annotation getAnnotation() {
		return annotation;
	}

	public void setAnnotation(Annotation annotation) {
		this.annotation = annotation;
	}

	public List<String> getResults() {
		return results;
	}

	public void setResults(List<String> results) {
		this.results = results;
	}

	public boolean isMainSubject() {
		return mainSubject;
	}

	public void setMainSubject(boolean mainSubject) {
		this.mainSubject = mainSubject;
	}

	private String variable;

	public String getVariable() {
		return variable;
	}

	public void setVariable(String variable) {
		this.variable = variable;
	}

	private DatatypePropertyValueIdentifier data;

	public Object getData() {
		return (DatatypePropertyValueIdentifier) data;
	}

	public void setData(Object data) {
		this.data = (DatatypePropertyValueIdentifier) data;
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		StringBuffer result = new StringBuffer("");
		result.append(this.getClass().toString());
		result.append(" Is it the main subject? ").append(isMainSubject());
		if (annotation != null)
			result.append(annotation.toString());
		result.append(" Data: ").append(getData()).toString();
		if (this.variable != null)
			result.append(" \n Variable:").append(this.variable);
		result.append("\nResults:" + results);
		return result.toString();

	}

	Score score;

	public Score getScore() {
		return this.score;
	}

	public void setScore(Score score) {
		this.score = score;
	}

	public Object clone() {
		Object deepCopy = null;
		ByteArrayOutputStream byteArrOs = new ByteArrayOutputStream();
		ObjectOutputStream objOs;
		try {
			objOs = new ObjectOutputStream(byteArrOs);

			objOs.writeObject(this);

			ByteArrayInputStream byteArrIs = new ByteArrayInputStream(byteArrOs
					.toByteArray());
			ObjectInputStream objIs = new ObjectInputStream(byteArrIs);
			deepCopy = objIs.readObject();
			return deepCopy;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return deepCopy;
	}

	public boolean equals(Object anotherObject) {
		if (this == anotherObject)
			return true;
		if (!(anotherObject instanceof DatatypePropertyValueElement))
			return false;
		if ((this.annotation != null)
				&& (((DatatypePropertyValueElement) anotherObject)
						.getAnnotation() != null)
				&& (this.getAnnotation()
						.equals(((DatatypePropertyValueElement) anotherObject)
								.getAnnotation()))
				&& this.isMainSubject() == ((DatatypePropertyValueElement) anotherObject)
						.isMainSubject()
				&& this.isAlreadyAdded() == ((DatatypePropertyValueElement) anotherObject)
						.isAlreadyAdded()
				&& ((DatatypePropertyValueIdentifier) this.getData())
						.equals(((DatatypePropertyValueIdentifier) ((DatatypePropertyValueElement) anotherObject)
								.getData()).toString())
	)
			return true;
		else
			return false;
	}
}
 public class DatatypePropertyValueIdentifier implements Serializable{

	private List<SerializableURI> instanceURIs;
	private String propertyUri;
	private String propertyValue;

	public List<SerializableURI> getInstanceURIs() {
		return instanceURIs;
	}

	public void setInstanceURIs(List<SerializableURI> instanceURIs) {
		this.instanceURIs = instanceURIs;
	}

	public String getPropertyUri() {
		return propertyUri;
	}

	public void setPropertyUri(String propertyName) {
		this.propertyUri = propertyName;
	}

	public String getPropertyValue() {
		return propertyValue;
	}

	public void setPropertyValue(String propertyValue) {
		this.propertyValue = propertyValue;
	}

	/**
	 * 
	 */
	public String toString() {
		StringBuffer result = new StringBuffer("");

		result.append(" Datatype property identifier: ").append(
				"\nInstanceURI: ").append(this.instanceURIs.toString()).append(
				"\nProperty URI: ").append(this.propertyUri).append(
				" \nProperty value: ").append(this.propertyValue).toString();
		return result.toString();

	}

	public boolean equals(DatatypePropertyValueIdentifier anotherObject) {
		if ((this.propertyValue != null)
				&& (anotherObject != null)
				&& (this.propertyValue == anotherObject.getPropertyValue())
				&& (this.propertyUri != null && this.propertyUri
						.equals(anotherObject.getPropertyUri()))
				&& (this.instanceURIs != null && this.instanceURIs != null 
						&& this.instanceURIs
						.toString().equals(
								anotherObject.getInstanceURIs().toString())))
			return true;
		else
			return false;
	}

}
 public class NoneElement implements OntologyElement {
  Annotation annotation = new Annotation();

  String id = "";

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  boolean isAnswer;

  public boolean isAnswer() {
    return isAnswer;
  }

  public void setAnswer(boolean isAnswer) {
    this.isAnswer = isAnswer;
  }

  /** max min sum */
  String function;

  Score score;

  public String getFunction() {
    return function;
  }

  public void setFunction(String function) {
    this.function = function;
  }

  /*
   * this flag indicates whether the element is already in the list of elements
   * and whether it should be ignored except for the function; this happens when
   * some existing elements are modified with for example max min etc
   */
  boolean alreadyAdded;

  public boolean isAlreadyAdded() {
    return alreadyAdded;
  }

  public void setAlreadyAdded(boolean alreadyAdded) {
    this.alreadyAdded = alreadyAdded;
  }

  String data = FreyaConstants.CLARIFICATION_OPTIONS_NONE;

  public Annotation getAnnotation() {
    return annotation;
  }

  public void setAnnotation(Annotation ann) {
    this.annotation = ann;
  }

  public Object getData() {
    // TODO Auto-generated method stub
    return this.data;
  }

  public List<String> getResults() {
    // TODO Auto-generated method stub
    return null;
  }

  public String getVariable() {
    // TODO Auto-generated method stub
    return null;
  }

  public boolean isMainSubject() {
    // TODO Auto-generated method stub
    return false;
  }

  public void setData(Object data) {
    // TODO Auto-generated method stub
  }

  public void setMainSubject(boolean value) {
    // TODO Auto-generated method stub
  }

  public void setResults(List<String> results) {
    // TODO Auto-generated method stub
  }

  public void setVariable(String key) {
    // TODO Auto-generated method stub
  }

  public Score getScore() {
    return score;
  }

  public void setScore(Score score) {
    this.score = score;
  }

  public boolean equals(Object anotherObject) {
    if(this == anotherObject) return true;
    if(!(anotherObject instanceof NoneElement)) return false;
    boolean annEqual = false;
    boolean idEqual = false;
    if((this.annotation != null)
            && (((NoneElement)anotherObject).getAnnotation() != null)
            && (this.getAnnotation().equals(((NoneElement)anotherObject)
                    .getAnnotation()))) annEqual = true;
    if(this.getId().toString().equals(
            ((NoneElement)anotherObject).getId().toString())) idEqual = true;
    if(idEqual && annEqual)
      return true;
    else return false;
  }

  public String toString() {
    StringBuffer buff =
            new StringBuffer((this.getClass().getSimpleName().toString()));
    if(annotation != null) buff.append(annotation.toString());
    buff.append(" Id:").append(id);
    buff.append("\n");
    return buff.toString();
  }
}
 public interface OntologyElement extends Serializable {

	public String getFunction();

	public void setFunction(String function);

	public boolean isAlreadyAdded();

	public void setAlreadyAdded(boolean alreadyAdded);

	public Annotation getAnnotation();
	
	public void setAnnotation(Annotation annotation);

	public String getVariable();

	public void setVariable(String key);

	public boolean isMainSubject();

	public void setMainSubject(boolean value);

	public List<String> getResults();

	public void setResults(List<String> results);

	public Object getData();

	public void setData(Object data);

	public void setScore(Score score);

	public Score getScore();

	public boolean isAnswer();

	public void setAnswer(boolean isAnswer);

	public boolean equals(Object o);

}
 public class POC {

	Annotation annotation = new Annotation();

	public Annotation getAnnotation() {
		return annotation;
	}

	public void setAnnotation(Annotation annotation) {
		this.annotation = annotation;
	}

	POC head;

	MainSubject mainSubject;
	List<String> modifiers;

	public POC getHead() {
		return head;
	}

	public void setHead(POC head) {
		this.head = head;
	}

	public List<String> getModifiers() {
		return modifiers;
	}

	public void setModifiers(List<String> modifiers) {
		this.modifiers = modifiers;
	}

	public MainSubject getMainSubject() {
		return mainSubject;
	}

	public void setMainSubject(MainSubject mainSubject) {
		this.mainSubject = mainSubject;
	}

	public String toString() {
		StringBuffer buffer = new StringBuffer("");
		buffer.append("POC:" + getAnnotation().toString());
		return buffer.toString();
	}
}
 @XmlRootElement
public class Question {

    /**
     * question type such as boolean, number, classic (all the others);
     */

    public String sentenceText;
    public Type type;

    public Type getType() {
        return type;
    }

    public void setType(Type type) {
        this.type = type;
    }

    List<HasWord> tokens;

    Tree syntaxTree;

    /* this is focus */
    POC focus;

    List<OntologyElement> answerType;

    List<POC> pocs = new ArrayList<POC>();


    public List<HasWord> getTokens() {
        return tokens;
    }

    public void setTokens(List<HasWord> tokens) {
        this.tokens = tokens;
    }


    List<List<SemanticConcept>> semanticConcepts =
                    new ArrayList<List<SemanticConcept>>();

    public List<OntologyElement> getAnswerType() {
        return answerType;
    }

    public void setAnswerType(List<OntologyElement> answerType) {
        this.answerType = answerType;
    }

    public POC getFocus() {
        return focus;
    }

    public void setFocus(POC focus) {
        this.focus = focus;
    }

    public Tree getSyntaxTree() {
        return syntaxTree;
    }

    public void setSyntaxTree(Tree syntaxTree) {
        this.syntaxTree = syntaxTree;
    }

    public List<List<SemanticConcept>> getSemanticConcepts() {
        return semanticConcepts;
    }

    public void setSemanticConcepts(List<List<SemanticConcept>> semanticConcepts) {
        this.semanticConcepts = semanticConcepts;
    }

    public List<POC> getPocs() {
        return pocs;
    }

    public void setPocs(List<POC> pocs) {
        this.pocs = pocs;
    }

    public String toString() {
        StringBuffer b = new StringBuffer("");
        b.append("sem concepts:");
        if (this.semanticConcepts != null)
            b.append(this.semanticConcepts.toString());
        b.append("pocs:");
        if (this.pocs != null) b.append(pocs.toString());
        b.append("Tree:");
        if (this.syntaxTree != null) b.append(this.syntaxTree.toString());
        return b.toString();
    }
}
 @XmlRootElement
public class SemanticConcept implements Serializable {

    OntologyElement ontologyElement;
    String function;
    Boolean verified = false;
    Double score;

    public Double getScore() {
        return score;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    public Boolean isVerified() {
        return verified;
    }

    public void setVerified(Boolean verified) {
        this.verified = verified;
    }

    public OntologyElement getOntologyElement() {
        return ontologyElement;
    }

    public void setOntologyElement(OntologyElement ontologyElement) {
        this.ontologyElement = ontologyElement;
    }

    public String getFunction() {
        return function;
    }

    public void setFunction(String function) {
        this.function = function;
    }

    public String toString() {
        StringBuffer b = new StringBuffer("");
        b.append("Ontology Elements:\n");
        if (ontologyElement != null) b.append(ontologyElement.toString());
        b.append(" Verified:").append(verified).append("\n");
        b.append(" Function:").append(function).append("\n");
        if (ontologyElement != null)
            b.append("Is ontology element already added:"
                            + ontologyElement.isAlreadyAdded() + "\n");
        return b.toString();
    }

    public Object clone() {
        Object deepCopy = null;
        ByteArrayOutputStream byteArrOs = new ByteArrayOutputStream();
        ObjectOutputStream objOs;
        try {
            objOs = new ObjectOutputStream(byteArrOs);
            objOs.writeObject(this);
            ByteArrayInputStream byteArrIs =
                            new ByteArrayInputStream(byteArrOs.toByteArray());
            ObjectInputStream objIs = new ObjectInputStream(byteArrIs);
            deepCopy = objIs.readObject();
            return deepCopy;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return deepCopy;
    }

    public boolean equals(Object theOtherConcept) {
        boolean isEqual = false;
        String function1 = this.getFunction();
        String function2 = ((SemanticConcept) theOtherConcept).getFunction();
        OntologyElement element1 = this.getOntologyElement();
        OntologyElement element2 =
                        ((SemanticConcept) theOtherConcept).getOntologyElement();
        boolean functionEquals = false;
        if (function1 != null && function2 != null)
            functionEquals = function1.equals(function2);
        else if (function1 == null && function2 == null) functionEquals = true;
        boolean verifiedEquals = false;
        if (this.isVerified().booleanValue() == ((SemanticConcept) theOtherConcept)
                        .isVerified().booleanValue()) verifiedEquals = true;
        if (functionEquals && element1.equals(element2))
            isEqual = true;
        // System.out
        // .print("************************************************************calling equals method..result is:"
        // + isEqual);
        return isEqual;
    }
}
 @Component
public class TreeUtils {
    static org.apache.commons.logging.Log logger =
                    org.apache.commons.logging.LogFactory.getLog(TreeUtils.class);

    @Value("${org.freya.parser.preterminal.pocs}") String preterminalPOCs;

    public Tree getAnswerType(Tree tree) throws Exception {
        Tree mainSubjectTree = findTheHeadOfTheNounPhrase(tree);
        return mainSubjectTree;
    }

    /**
     * @param tree
     * @return
     */
    public Tree getMainSubjectTree(Tree tree) {
        List<Tree> pocs = findPocs(tree);
        if (pocs != null && pocs.size() > 0)
            return pocs.get(0);
        else
            return null;
    }

    /**
     * finds the first NP/NN* (main subject/answer type/focus);
     * 
     * @param tree
     * @return
     */
    public Tree findTheFirstNounPhraseOld(Tree tree) {
        Tree value = null;
        // treeLabel is the pos tag: NP, VP, etc.
        String treeLabel = tree.label().value();
        if (treeLabel != null
                        && (treeLabel.startsWith("NP") || treeLabel.startsWith("NN"))
                        && !(treeLabel.startsWith("PRP")))
        // || treeLabel.startsWith("WHNP")
        {
            return tree;
        } else if (treeLabel != null
                        && (treeLabel.startsWith("WHADVP") || treeLabel.startsWith("WHNP") || treeLabel
                                        .startsWith("WHADJP"))// this is to support how long,
        // how
        // large, how big, etc.
        ) {
            List children = tree.getChildrenAsList();
            if (children != null && children.size() <= 2) {// we always expect
                // one or two
                Tree firstChild = (Tree) children.get(0);
                Tree secondChild = null;
                if (children.size() > 1) secondChild = (Tree) children.get(1);
                // this is to support where what etc
                if (secondChild == null
                                && (firstChild.label().value().startsWith("WRB"))) {
                    // || firstChild.label().value().startsWith("WP"))) {
                    return tree;
                } else if (secondChild != null) {
                    if (firstChild.label().value().startsWith("WRB")
                                    && ((secondChild.label().value().startsWith("JJ")) || secondChild
                                                    .label().value().startsWith("ADJP"))
                                    || secondChild.label().value().startsWith("NN")
                                    || secondChild.label().value().startsWith("NP")
                                    || firstChild.label().value().startsWith("NN")
                                    || firstChild.label().value().startsWith("NP"))
                        // return secondChild;// well?
                        return tree;
                }
            } else if (children != null) {
                Iterator it = children.iterator();
                while (it.hasNext()) {
                    Tree something = (Tree) it.next();
                    if (something.label().value().startsWith("NP")
                                    || (something.label().value().startsWith("NN")))
                        return something;
                }
            }
        } else {
            List<Tree> listOfChildren = tree.getChildrenAsList();
            // put them in reverse order
            // Collections.reverse(listOfChildren);
            for (Tree currentTree : listOfChildren) {
                Tree mainSubjectTree = getMainSubjectTree(currentTree);
                if (mainSubjectTree != null) {
                    value = mainSubjectTree;
                    break;
                }
            }
        }
        return value;
    }

    /**
     * fins preterminals
     * 
     * @param tree
     * @return
     */
    public List<Tree> findPrePreTerminals(Tree tree) {
        List<Tree> pocs = new ArrayList<Tree>();
        Tree value = null;
        // treeLabel is the pos tag: NP, VP, etc.
        String treeLabel = tree.label().value();
        // logger.info("label is:"+treeLabel);
        if (tree.isPrePreTerminal()) {
            pocs.add(tree);
            logger.debug(treeLabel
                            + " is prepreterminal so adding it to the list of POCs.");
            return pocs;
        } else {
            List<Tree> listOfChildren = tree.getChildrenAsList();
            // put them in reverse order
            // Collections.reverse(listOfChildren);
            // logger.info("now listing children...");
            for (Tree currentTree : listOfChildren) {
                // logger.info("child..."+currentTree.label().value());
                if (currentTree.isPrePreTerminal())
                    pocs.add(currentTree);
                else
                    pocs.addAll(findPrePreTerminals(currentTree));
                // logger.info("currently total pocs are:"+pocs.size());
            }
        }
        return pocs;
    }


    /**
     * lucene split poc which contains adjective into two pocs: adjective and the rest
     * 
     * @param pocs
     * @param root
     * @param stanfordSentence
     * @return
     */
    public List<POC> generateSeparatePOCForAdjectives(List<POC> pocs, Tree root) {
        // if there is no JJ* generate a new poc and update the current
        List<Tree> adjectives = new ArrayList<Tree>();
        List<POC> toRemove = new ArrayList<POC>();
        logger.debug("before checking jjs...pocs:" + pocs.toString());
        for (POC pocElement : pocs) {
            List<Tree> trees = pocElement.getAnnotation().getSyntaxTree();
            List<Tree> splitTrees = new ArrayList<Tree>();
            for (Tree eachTree : trees) {
                if (eachTree.isPrePreTerminal()) {
                    // split into preterminals
                    splitTrees.addAll(eachTree.getChildrenAsList());
                } else {
                    splitTrees.add(eachTree);
                }
            }
            List<Tree> remainingList = new ArrayList<Tree>();
            for (Tree pocTree : splitTrees) {
                if (isDescriptive(pocTree) && splitTrees.size() > 1) {
                    // so that if JJs are already split we do not generate
                    // duplicates
                    adjectives.add(pocTree);
                } else {
                    if (!remainingList.contains(pocTree)) remainingList.add(pocTree);
                }
            }
            // //////////////////////////////////////update
            if (remainingList != null && remainingList.size() > 0) {
                pocElement = updatePOCAnnotation(remainingList, root, pocElement);
            } else {
                // mark the poc for removal
                toRemove.add(pocElement);
            }
        }
        logger.debug("before splitting jjs...pocs:" + pocs.toString());
        // //////////////////////////////////////////
        // generate poc from the adjective
        // ////////////////////////////////////////
        if (adjectives.size() > 0) {
            for (Tree adjective : adjectives) {
                POC newPoc = new POC();
                List<Tree> adjectiveTree = new ArrayList<Tree>();
                adjectiveTree.add(adjective);
                newPoc = updatePOCAnnotation(adjectiveTree, root, newPoc);
                pocs.add(newPoc);
            }
        }
        logger.debug("after adding jjs...:" + pocs.toString());
        if (toRemove.size() > 0) pocs.removeAll(toRemove);
        return pocs;
    }

    /**
     * checks whether the tree is ajdective, adverb superlative or verb, past participle (as this verb is always part of
     * the NP we assume it has the function of adjective such as 'populated state')
     * 
     * @param tree
     * @return
     */
    boolean isDescriptive(Tree tree) {
        boolean isDescriptive = false;
        if (tree.label().value().startsWith(FreyaConstants.JJ_TAG_TREEBANK)
                        || tree.label().value().startsWith(
                                        FreyaConstants.VBN_TAG_TREEBANK)
                        || tree.label().value().startsWith(
                                        FreyaConstants.RBS_TAG_TREEBANK)
                        || tree.label().value().startsWith("ADJP")) {
            isDescriptive = true;
        }
        return isDescriptive;
    }

    /**
     * checks whether there are any JJ* or ADJP inside poc
     * 
     * @param poc
     * @return
     */
    public boolean pocContainsJJs(POC poc) {
        boolean containsJJs = false;
        for (Tree tree : poc.getAnnotation().getSyntaxTree()) {
            String treeLabel = tree.label().value();
            // logger.info("Checking whether "+treeLabel+ " is JJ");
            if (isDescriptive(tree)) {
                containsJJs = true;
                break;
            } else {
                List<Tree> children = tree.getChildrenAsList();
                for (Tree child : children) {
                    // String childLabel = child.label().value();
                    if (isDescriptive(child)) {
                        containsJJs = true;
                        break;
                    }
                }
            }
        }
        return containsJJs;
    }

    /**
     * if pocs are prepreterminals then split their tree into children
     * 
     * @param pocs
     * @return
     */
    public List<POC> splitPocs(List<POC> pocs) {
        List<POC> toRemove = new ArrayList<POC>();
        for (POC poc : pocs) {
            List<Tree> trees = poc.getAnnotation().getSyntaxTree();
            if (trees != null && trees.size() == 1) {
                // check if they are prepreterminals
                Tree tree = trees.get(0);
                if (tree.isPrePreTerminal()) {
                    // split into preterminals
                    List<Tree> newTree = new ArrayList<Tree>();
                    for (Tree child : tree.getChildrenAsList()) {
                        newTree.add(child);
                    }
                    poc.getAnnotation().setSyntaxTree(newTree);
                }
            }
        }
        return pocs;
    }


    /**
     * update the poc with new syntax tree and also update it's annotation start and end offsets and the text
     * 
     * @param treeList
     * @param root
     * @param stanfordSentence
     * @param poc
     * @return poc updated with the syntax tree; null if the tree is empty
     */
    POC updatePOCAnnotation(List<Tree> treeList, Tree root, POC poc) {
        if (treeList == null || treeList.size() == 0) return null;
        Tree firstTree = treeList.get(0);
        long parserStartOffset = Trees.leftEdge(firstTree, root);
        Tree lastTree = treeList.get(treeList.size() - 1);
        long parserEndOffset = Trees.rightEdge(lastTree, root);
        poc.getAnnotation().setStartOffset(parserStartOffset);
        poc.getAnnotation().setEndOffset(parserEndOffset);
        poc.getAnnotation().setText(getNiceString(treeList));
        poc.getAnnotation().setSyntaxTree(treeList);
        return poc;
    }


    /**
     * independent of stanfordSentence remove DT from pocs: if poc has DT then transform it to the list of its children
     * but remove DT now poc can be a list of trees which are on the same level, not only one tree
     * 
     * @param pocs
     * @return
     */
    public List<POC> removeDTFromPOCs(List<POC> pocs, Tree root) {
        // if there is no DT leave pocs as they are (one Tree in the list)
        for (POC pocElement : pocs) {
            // before executing this method all pocs are stored in list each
            // list having only one element
            Tree pocTree = pocElement.getAnnotation().getSyntaxTree().get(0);
            List<Tree> list = new ArrayList<Tree>();
            List<Tree> children = pocTree.getChildrenAsList();
            for (Tree child : children) {
                if (FreyaConstants.DT_TAG_TREEBANK.equals(child.label().value())) {
                    List<Tree> withoutDT = new ArrayList<Tree>();
                    withoutDT.addAll(children);
                    withoutDT.remove(child);
                    logger.debug("Removing DT from POC.");
                    list = withoutDT;
                    break;
                } else {
                    if (!list.contains(pocTree)) list.add(pocTree);
                }
            }
            pocElement = updatePOCAnnotation(list, root, pocElement);
        }
        return pocs;
    }

    /**
     * finds pocs: CURRENTLY these are NN* and NP*
     * 
     * @param tree
     * @return
     */
    public List<Tree> findPocs(Tree tree) {
        List<Tree> pocs = new ArrayList<Tree>();
        List<Tree> prePreTerminals = findPrePreTerminals(tree);
        for (Tree node : prePreTerminals) {
            String nodeLabel = node.label().value();
            String nodeChildLabel = node.getChildrenAsList().get(0).label().value();
            // NPs and NNs
            if (nodeLabel != null
                            && (nodeLabel.startsWith(FreyaConstants.NP_TAG_TREEBANK)
                                            || nodeLabel.startsWith(FreyaConstants.NN_TAG_TREEBANK)
                                            || nodeLabel.startsWith(FreyaConstants.NX_TAG_TREEBANK) || (nodeLabel
                                                .startsWith(FreyaConstants.ADJP_TAG_TREEBANK)))
                            && !(nodeChildLabel.startsWith(FreyaConstants.PRP_TAG_TREEBANK))
                            && !(nodeChildLabel.startsWith(FreyaConstants.EX_TAG_TREEBANK)))
                pocs.add(node);
            // //////////////////////////////////////////////////////////////////
            // this is to support how long, //////
            // how //////
            // large, how big, etc. //////
            // //////////////////////////////////////////////////////////////////
            else if (nodeLabel != null
                            && (nodeLabel.startsWith(FreyaConstants.WHADVP_TAG_TREEBANK)
                                            || nodeLabel
                                                            .startsWith(FreyaConstants.WHNP_TAG_TREEBANK) || nodeLabel
                                                // added because of high high: high is prepreterminal but
                                                // the whole how high is not
                                                .startsWith(FreyaConstants.WHADJP_TAG_TREEBANK))) {
                List children = node.getChildrenAsList();
                if (children != null && children.size() <= 2) {// we always
                    // expect
                    // one or two
                    Tree firstChild = (Tree) children.get(0);
                    Tree secondChild = null;
                    if (children.size() > 1) secondChild = (Tree) children.get(1);
                    // this is to support where what etc
                    if (secondChild == null
                                    && (firstChild.label().value().startsWith(
                                                    FreyaConstants.WRB_TAG_TREEBANK) || firstChild
                                                    .label().value().startsWith(
                                                                    FreyaConstants.WP_TAG_TREEBANK))) {
                        // || firstChild.label().value().startsWith("WP"))) {
                        List<Tree> leaves = firstChild.getLeaves();
                        for (Tree leaf : leaves) {
                            if (leaf.label().value().toLowerCase().equals("where")
                                            || leaf.label().value().toLowerCase().equals("when")
                                            || leaf.label().value().toLowerCase().equals("who")) {
                                logger
                                                .info("Found WH-");
                                // logger.info("leaf.label().value():" + leaf.label().value());
                                pocs.add(node);
                            }
                        }
                    } else if (secondChild != null) {
                        if (firstChild.label().value().startsWith(
                                        FreyaConstants.WRB_TAG_TREEBANK)
                                        && ((secondChild.label().value()
                                                        .startsWith(FreyaConstants.JJ_TAG_TREEBANK)) || secondChild
                                                        .label().value().startsWith(
                                                                        FreyaConstants.ADJP_TAG_TREEBANK))
                                        || secondChild.label().value().startsWith(
                                                        FreyaConstants.NN_TAG_TREEBANK)
                                        || secondChild.label().value().startsWith(
                                                        FreyaConstants.NP_TAG_TREEBANK)
                                        || firstChild.label().value().startsWith(
                                                        FreyaConstants.NN_TAG_TREEBANK)
                                        || firstChild.label().value().startsWith(
                                                        FreyaConstants.NP_TAG_TREEBANK)
                                        || firstChild.label().value().startsWith(
                                                        FreyaConstants.RB_TAG_TREEBANK))
                            // return secondChild;// well?
                            // this is to remove WRB in 'how long' how many etc
                            pocs.add(node);
                    }
                } else if (children != null) {
                    Iterator it = children.iterator();
                    while (it.hasNext()) {
                        Tree something = (Tree) it.next();
                        if (something.label().value().startsWith("NP")
                                        || (something.label().value().startsWith("NN")))
                            pocs.add(something);
                    }
                }
            }// if prepreterminal is WHNP, WHADJP or WHADVP
        }
        // now also add those that are preterminals and NNs but were missed in
        // findPocs method
        logger.info("Number of pocs as prepreterminals:" + pocs.size());
        pocs.addAll(findPreTerminalsThatAreNNOrINs(tree, pocs));
        logger
                        .info("Number of pocs as preterminals and prepreterminals (final num of pocs):"
                                        + pocs.size());
        return pocs;
    }

    /**
     * find those preterminals that are NNs as they were missed due to the way sp parses tree
     * 
     * @param root
     * @param pocs
     * @return
     */
    List<Tree> findPreTerminalsThatAreNNOrINs(Tree root, List<Tree> pocs) {
        long numberOfTokens = root.getLeaves().size();
        List<Tree> newList = new ArrayList<Tree>();
        Set<Long> skipList = new HashSet();

        for (Tree poc : pocs) {
            logger.debug("Checking poc:" + poc.toString());
            long start = Trees.leftEdge(poc, root);
            long end = Trees.rightEdge(poc, root);
            logger.debug("Start poc:" + start);
            logger.debug("End poc:" + end);
            for (long j = start; j < end; j++) {
                skipList.add(new Long(j));
                logger.debug("Adding element to skip list:" + j);
            }
        }
        Set<Long> listToConsider = new HashSet<Long>();
        for (long i = 0; i < numberOfTokens; i++) {
            boolean iFound = false;
            for (Long toSkip : skipList) {
                if (toSkip.longValue() == i) {
                    iFound = true;
                    break;
                } else {}
            }
            if (!iFound) listToConsider.add(i);
        }
        for (Long element : listToConsider) {
            Tree preTerminal = null;
            preTerminal = Trees.getPreTerminal(root, element.intValue());
            logger.debug("checking now:" + element.intValue()
                            + " and its preterminal:" + preTerminal);
            if (preTerminal != null
                            && startsWithTagsToConsider(preTerminal.label().value())) {
                newList.add(preTerminal);
                logger.info("Found preTerminal:" + preTerminal.toString());
            }
        }
        return newList;
    }

    /**
     * reads pocs to consider form properties file and checks whether it should be considered or not; this applies to
     * preterminal pocs only
     * 
     * @param preterminalLabelValue
     * @return
     */
    boolean startsWithTagsToConsider(String preterminalLabelValue) {
        boolean consider = false;

        // InputStream is = this.getClass().getResourceAsStream("/Service.properties");
        // Properties ps = new Properties();
        // try {
        // ps.load(is);
        // } catch(IOException e1) {
        // // TODO Auto-generated catch block
        // e1.printStackTrace();
        // }
        // String preterminalPOCs = new String(ps.getProperty("preterminalPOCs"));
        String[] tagsToConsider = preterminalPOCs.split(",");
        for (String tag : tagsToConsider) {
            if (preterminalLabelValue.startsWith(tag)) {
                consider = true;
                break;
            }
        }
        return consider;
    }

    /**
     * this method finds the head of the phrase
     * 
     * @param tree
     * @return
     */
    public Tree findTheHeadOfTheNounPhrase(Tree tree) {
        Tree toReturn = null;
        if (tree != null) {
            HeadFinder hf = new ModCollinsHeadFinder();
            Tree head = tree.headTerminal(hf);
            if (head.label().value() != null
                            && !(head.label().value().startsWith("PRP"))) {
                toReturn = head;
            }
        }
        return toReturn;
        // System.out.println("the head is:" + head.toString());
    }

    /**
     * this method finds the head of the phrase
     * 
     * @param tree
     * @return
     */
    public List<TreeGraphNode> findModifiersOfTheNounPhrase(Tree tree, Tree head) {
        if (tree == null || head == null) return null;
        HeadFinder hf = new ModCollinsHeadFinder();
        // Tree head = tree.headTerminal(hf);
        List<TreeGraphNode> toReturn = new ArrayList<TreeGraphNode>();
        TreebankLanguagePack tlp = new PennTreebankLanguagePack();
        GrammaticalStructureFactory gsf = tlp.grammaticalStructureFactory();
        GrammaticalStructure gs = gsf.newGrammaticalStructure(tree);
        //Collection tdl = gs.typedDependenciesCollapsed();
        List<TypedDependency> tdl = gs.typedDependenciesCCprocessed();
        Iterator it = tdl.iterator();
        while (it.hasNext()) {
            TypedDependency td = (TypedDependency) it.next();
            String depName = td.reln().getShortName();
            if ((depName.equals("amod") || depName.equals("dep") || depName
                            .equals("advmod"))
                            && td.gov().value() == head.value()) {
                toReturn.add(td.dep());
            }
        }
        TreePrint tp = new TreePrint("penn,typedDependenciesCollapsed");
        //tp.printTree(head);
        return toReturn;
        // System.out.println("the head is:" + head.toString());
    }

    /**
     * generates a nice string from the tree
     * 
     * @param firstNPorNN
     * @return
     */
    public String getNiceString(List<Tree> trees) {
        String niceString = "";
        for (Tree tree : trees) {
            for (Tree leaf : tree.getLeaves()) {
                if (leaf.isLeaf()) {
                    niceString = niceString + " " + leaf.value();
                } else {
                    List<Tree> leafs = new ArrayList<Tree>();
                    leafs.add(leaf);
                    niceString = niceString + " " + getNiceString(leafs);
                }
            }
        }
        return niceString.trim();
    }

    /**
     * returns the distance from one node to the other.
     * 
     * @param tree1
     * @param tree2
     * @return
     */
    public int getDistance(List<Tree> tree1List, List<Tree> tree2List, Tree root) {
        Tree tree1 = null;
        Tree tree2 = null;
        if (tree1List != null && tree1List.size() > 0) tree1 = tree1List.get(0);
        if (tree2List != null && tree2List.size() > 0) tree2 = tree2List.get(0);
        List nodes = root.pathNodeToNode(tree1, tree2);
        if (tree1 != null && tree2 != null && nodes != null) {
            logger.debug("Distance btw" + tree1.toString() + "and "
                            + tree2.toString() + " is:" + nodes.size());
        } else {
            logger.debug("Distance btw tree1:" + tree1 + "and tree2 " + tree2
                            + " is:" + nodes);
        }
        int nodeSize = 0;
        if (nodes != null) nodeSize = nodes.size();
        return nodeSize;
    }

    /**
     * get closest oc to the given poc
     * 
     * @param poc
     * @param ocs
     * @param root
     * @return
     */
    int getClosestOc(List<Tree> poc, List<List<Tree>> ocs, Tree root) {
        int min = 0;
        for (List<Tree> oc : ocs) {
            int dist = getDistance(poc, oc, root);
            if (dist < min) min = dist;
        }
        return min;
    }
} public class CATConstants {

  public static String TYPE_INSTANCE = "instance";

  public static String FEATURE_INSTANCE_URI = "instanceURI";

  /* used to set feature names for Lookups inside OntoRootGaz */
  public static String FEATURE_URI = "URI";
  public static String FEATURE_TYPE_CLASS = "class";
  
  public static String FEATURE_PROPERTY_URI = "propertyURI";

  public static String FEATURE_PROPERTY_VALUE = "propertyValue";

  public static String FEATURE_HEURISTIC_LEVEL = "heuristic_level";

  public static String FEATURE_HEURISTIC_VALUE = "heuristic_value";



  public static String CLASS_URI = "classURI";

  public static String CLASS_URI_LIST = "classURIList";

  public static String TYPE_PROPERTY = "property";

  public static String TYPE_DATATYPE_PROPERTY_VALUE = "datatypePropertyValue";

  public static String ANNOTATION_TYPE_ONTORES = "OntoRes";

  public static String ANNOTATION_TYPE_ONTORESCHUNK = "OntoResChunk";

  /** used to set feature names for Lookups inside OntoRootGaz */
  public static String TYPE_FEATURE = "type";

  /**
   * Name of the common logger
   */

  public static String LOGGER_OUPUT_LEVEL = "2000";

  /** separator used during formatting of results */
  public static String NEW_LINE =System.getProperty("line.separator");// "\n";

  public static String REGEX_CAMEL_CASE = "[a-z][A-Z]";

}
 public class AnnotationOffsetComparator implements Comparator<Annotation> {

    public int compare(Annotation a1, Annotation a2){
      int result;

      // compare start offsets
      result = a1.getStartOffset().compareTo(
          a2.getStartOffset());

      // if start offsets are equal compare end offsets
      if(result == 0) {
        result = a1.getEndOffset().compareTo(
            a2.getEndOffset());
      } // if

      return result;
    }
  
  
} public class SemanticConceptListComparator implements Comparator<List<SemanticConcept>> {

	public int compare(List<SemanticConcept> s1, List<SemanticConcept> s2) {
		OntologyElement o1=s1.get(0).getOntologyElement();
		OntologyElement o2=s2.get(0).getOntologyElement();
		
		Annotation a1 = o1.getAnnotation();
		Annotation a2 = o2.getAnnotation();
		int result;

		// compare start offsets
		result = a1.getStartOffset().compareTo(a2.getStartOffset());

		// if start offsets are equal compare end offsets
		if (result == 0) {
			result = a1.getEndOffset().compareTo(a2.getEndOffset());
		} // if

		return result;
	}

}

import edu.stanford.nlp.trees.Tree;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.freya.model.Annotation;
import org.freya.model.DatatypePropertyValueElement;
import org.freya.model.DatatypePropertyValueIdentifier;
import org.freya.model.NoneElement;
import org.freya.model.OntologyElement;
import org.freya.model.POC;
import org.freya.model.Question;
import org.freya.model.SemanticConcept;
import org.freya.parser.stanford.TreeUtils;
import org.freya.rdf.query.CATConstants;
import org.freya.util.AnnotationOffsetComparator;
import org.freya.util.SemanticConceptListComparator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

package org.freya.oc;




@Component
public class OCUtil {
    private static final Log logger = LogFactory.getLog(OCUtil.class);

    AtomicInteger id = new AtomicInteger();
    @Autowired TreeUtils treeUtils;



    /**
     * 
     * @param anns
     * @return
     */
    public Set<Annotation> filterInstanceClass(List<Annotation> anns) {
        HashMap<Long, List<Annotation>> map = new HashMap<Long, List<Annotation>>();

        for (Annotation ann : anns) {
            List<Annotation> tmp = map.get(ann.getStartOffset());
            if (tmp == null) tmp = new ArrayList<Annotation>();
            tmp.add(ann);
            map.put(ann.getStartOffset(), tmp);
        }
        // now we have all start offsets
        logger.info("Now finished puting all anns into the map where key is offsets, these are the keys:"
                        + map.keySet().toString());
        List<Long> startOffsets = new ArrayList<Long>();
        startOffsets.addAll(map.keySet());
        Collections.sort(startOffsets);
        List toRemove = new ArrayList();

        for (int i = 0; i < startOffsets.size() - 1; i++) {

            Long current = startOffsets.get(i);
            Long next = startOffsets.get(i + 1);
            logger.info("Current ofsset" + current.toString() + " next offset:" + next.toString());
            List<Annotation> currentAnnotations = map.get(current);
            List<Annotation> nextAnnotations = map.get(next);
            toRemove.addAll(whichToRemove(currentAnnotations, nextAnnotations));
            toRemove.addAll(whichToRemove(nextAnnotations, currentAnnotations));
        }

        // if (toRemove!=null)
        // anns.removeAll(toRemove);
        logger.info("Marked to remove due to classInstance:" + toRemove.size());
        // return anns;
        return new HashSet(toRemove);

    }

    // }
    /**
     * if first is class and second is instance then it checks the class of the instance and if the two match marks the
     * class to remove
     */
    List<Annotation> whichToRemove(List<Annotation> first, List<Annotation> second) {
        List<Annotation> toRemove = new ArrayList<Annotation>();
        // save in this list members from 'first' only if they are classes
        List<Annotation> firstClassesOnly = new ArrayList<Annotation>();
        // save in this list members from 'second' only if they are instances only
        List<Annotation> secondInstancesOnly = new ArrayList<Annotation>();
        for (Annotation ann1 : first) {
            String type = (String) ann1.getFeatures().get(CATConstants.TYPE_FEATURE);
            if (type.equals(CATConstants.FEATURE_TYPE_CLASS)) {
                firstClassesOnly.add(ann1);
            }
        }
        logger.info("There are " + firstClassesOnly.size() + " classes in the first column.");
        // second column
        for (Annotation ann1 : second) {
            String type = (String) ann1.getFeatures().get(CATConstants.TYPE_FEATURE);
            if (type.equals(CATConstants.TYPE_INSTANCE)) {
                secondInstancesOnly.add(ann1);
            }
        }
        logger.info("There are " + secondInstancesOnly.size() + " instances in the second column.");
        // collect classUris from first

        // now we know for sure that the first column is class and second is instance
        // so we take the second only, find all classUris of instances, and if we do find
        // that instance X is of the existing type of class then we do this:
        // - remove all instances from first
        // - remove all but X from the second column
        Set<String> allClassUrisFirst = new HashSet<String>();
        for (Annotation ann1 : firstClassesOnly) {
            String classUri = (String) ann1.getFeatures().get(CATConstants.FEATURE_URI);
            logger.info("class uri:" + classUri);
            allClassUrisFirst.add(classUri);
        }
        Set<Annotation> secondToKeep = new HashSet<Annotation>();
        for (Annotation ann1 : secondInstancesOnly) {
            logger.info("inst annotation:" + ann1.toString());

            Set<String> classUris = new HashSet((List) (ann1.getFeatures().get(CATConstants.CLASS_URI_LIST)));
            String classUri = (String) ann1.getFeatures().get(CATConstants.CLASS_URI);
            classUris.add(classUri);
            logger.info("classUris:" + classUris);
            // if classUris contain any of the classes in allClassUrisFirst then
            if (classInstanceFound(classUris, allClassUrisFirst))
            {
                secondToKeep.add(ann1);
            }
        }
        if (secondToKeep.size() > 0) {
            toRemove.addAll(first);
            toRemove.addAll(second);
            toRemove.removeAll(secondToKeep);
        }
        logger.info("marked to remove:" + toRemove.size());
        return toRemove;
    }

    /**
     * 
     * @param instanceClassUris
     * @param allClassUris
     * @return
     */
    boolean classInstanceFound(Set<String> instanceClassUris, Set<String> allClassUris) {
        boolean toReturn = false;
        for (String instClassUri : instanceClassUris) {
            logger.info("Checking:" + instClassUri);
            for (String classUri : allClassUris) {
                logger.info(" and:" + classUri);
                if (instClassUri.equals(classUri)) {
                    logger.info("Annotation should be removed?");
                    toReturn = true;
                    break;
                }
            }
        }
        return toReturn;
    }

    /**
     * finding nearest neighbour for poc
     * 
     * @param question
     * @param poc
     * @return
     */
    public List<SemanticConcept> findNearestNeighbours(Question question, POC poc) {
        List<SemanticConcept> nearestNeighbours = new ArrayList<SemanticConcept>();
        Tree root = question.getSyntaxTree();
        List<SemanticConcept> scList = null;
        try {
            scList = getLinearisedSemanticConcepts(question.getSemanticConcepts());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        int min = 1000;
        logger.info("Finding nearest neighbour for POC:"
                        + poc.getAnnotation().getText());
        logger.info("There are:" + scList.size()
                        + " candidates (semantic concepts)");
        for (SemanticConcept sConcept : scList) {

            if (sConcept.getOntologyElement() instanceof NoneElement) {
