/**
*
*/
package outputter.process;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.apache.log4j.Logger;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.xpath.XPath;
import outputter.ApplicationUtilities;
import outputter.Utilities;
import outputter.XML2EQ;
import outputter.data.CompositeEntity;
import outputter.data.CompositeQuality;
import outputter.data.Entity;
import outputter.data.EntityProposals;
import outputter.data.FormalConcept;
import outputter.data.FormalRelation;
import outputter.data.NegatedQuality;
import outputter.data.Quality;
import outputter.data.QualityProposals;
import outputter.data.REntity;
import outputter.data.RelationalQuality;
import outputter.data.SimpleEntity;
import outputter.knowledge.Dictionary;
import outputter.knowledge.PermittedRelations;
import outputter.knowledge.TermOutputerUtilities;
import outputter.search.EntitySearcherOriginal;
import outputter.search.TermSearcher;
/**
* @author hong cui
* Handles a character of a structure
* grab character and constrain info from <character> tag
*
*
* Could character be a relationalquality?
* yes, for example, "fused"
*/
public class CharacterHandler {
//input
private TermOutputerUtilities ontoutil;
Element root;
Element chara;
ArrayList<String> qualityclues; //may have multiple qualityclues: "color and shape of abc"
private ArrayList<EntityProposals> keyentities;
boolean fromcharacterstatement = false;
public static final String prepositions = "above|across|after|along|among|amongst|around|as|at|before|behind|beneath|between|beyond|by|for|from|in|into|near|of|off|on|onto|out|outside|over|than|throughout|to|toward|towards|up|upward|with|without";
//results
ArrayList<EntityProposals> entity; //the entity result will be saved here, which may be null, indicating the key entities parsed from the character statement should be used for this character
ArrayList<QualityProposals> qualities = new ArrayList<QualityProposals>(); //the quality result will be saved here. Because n structures may be involved in constraints (hence multiple relational qualities), this needs to be an arraylist. May be relationalquality, simple quality, or negated quality
ArrayList<EntityProposals> entityparts = new ArrayList<EntityProposals>(); //come from constraints, may have multiple.
ArrayList<EntityProposals> primaryentities = new ArrayList<EntityProposals>(); //entities no need to be resolved
boolean donotresolve=false;// This is to resolve between key entities and relational quality entities
//used in process
boolean resolve = false;
private ToBeResolved tobesolvedentity;
ArrayList<EntityProposals> relatedentities = new ArrayList<EntityProposals>();
ArrayList<Entity> bilateral = new ArrayList<Entity>();
static final private String specialprep = "by|through|via";
static XPath pathCharacterUnderStucture;
private static final Logger LOGGER = Logger.getLogger(CharacterHandler.class);
/**
* @param keyentities
*
*/
public CharacterHandler(Element root, Element chara, TermOutputerUtilities ontoutil, ArrayList<String> qualityclues, ArrayList<EntityProposals> keyentities, boolean fromecharacterstatement) {
this.root = root;
this.chara = chara;
this.ontoutil = ontoutil;
this.qualityclues = qualityclues;
this.keyentities = keyentities;
this.fromcharacterstatement = fromcharacterstatement;
try {
this.pathCharacterUnderStucture = XPath.newInstance(".//character");
} catch (JDOMException e) {
LOGGER.error("", e);
}
}
/**
*
* @param root
* @param chara
* @return
*/
public void handle(){
try {
parseEntity();
parseQuality();
if(resolve) resolve();
} catch (Exception e) {
LOGGER.error("", e);
}
}
/**
* can't be called out of context, so can't be a public method
*/
private void parseEntity(){
Element structure = chara.getParentElement();
if(structure.getAttributeValue("name").compareTo(ApplicationUtilities.getProperty("unknown.structure.name"))!=0){
String structureid = structure.getAttributeValue("id");
String structurename = Utilities.getStructureName(root, structureid);
EntityParser ep = new EntityParser(chara, root, structureid, structurename, keyentities, fromcharacterstatement);
this.tobesolvedentity = new ToBeResolved(structureid);
this.tobesolvedentity.setEntityCandidate(ep.getEntity());
this.tobesolvedentity.setStructure2Quality(ep.getQualityStrategy());
this.resolve = true;
this.entity=ep.getEntity();
if(this.entity!=null)
this.primaryentities.addAll(this.entity);
}
/*String structurename = (structure.getAttribute("constraint")!=null?
structure.getAttributeValue("constraint"): ""+" "+structure.getAttributeValue("name")).trim();
String structureid = structure.getAttributeValue("id");
if(structurename.compareTo(ApplicationUtilities.getProperty("unknown.structure.name"))!=0){
//otherwise, this.entity remains null
//parents separated by comma (,).
String parents = Utilities.getStructureChain(root, "//relation[@name='part_of'][@from='" + structureid + "']", 0);
this.entity = new EntitySearcherOriginal().searchEntity(root, structureid, structurename, parents, structurename, "part_of");
//if entity match is not very strong, consider whether the structure is really a quality
//if(this.entity.higestScore() < 0.8f){
// Structure2Quality rq = new Structure2Quality(root, structurename, structureid, null);
// rq.handle();
// ArrayList<QualityProposals> qualities = rq.qualities;
// if(qualities.size()>0){
// boolean settled = false;
// for(QualityProposals qp : qualities){
// if(qp.higestScore() > this.entity.higestScore() && (this.keyentities!=null && this.keyentities.size()>0)){
// this.entity = null;
// this.qualities = qualities;
// break;
// }
// }
// if(!settled){
// //park the case and resolve it later after the quality is parsed
// this.tobesolvedentity = new ToBeSolved(structurename, structureid, this.entity, qualities);
// this.resolve = true;
// }
// }
//}
this.primaryentities.add(this.entity);
//} */
}
private void parseQuality() throws Exception{
// characters => quality
//get quality candidate
String quality = Utilities.formQualityValueFromCharacter(chara);
String qualitycopy =quality;
boolean special_case = false;
// The below code handles all measure related cases like length,width,depth etc.
if((quality.matches(".*(\\d)+.*")==true)||(quality.equals("")==true)||(quality.equals("not")==true||(quality.matches(".*(width|height|length|broad|depth).*")||(quality.matches(".*(half|full|quarter|much).*")))))
{
preProcess(this.chara.getAttributeValue("name"));//handles height/width cases
if((this.chara.getAttributeValue("name")!=null)&&(this.chara.getAttributeValue("name").matches(".*(width|length|height|depth|broad).*")))
{
//To handle width,length statements of a same structure
if((this.chara.getAttributeValue("constraint")!=null)&&(this.chara.getAttributeValue("constraint").matches(".*(width|length|height|depth|broad).*"))&&(this.chara.getAttributeValue("constraintid")==null))//constraint id should be null
{
special_case =specialSizeCaseSameStructure();// handles when two properties of same entity is compared
}
else if((this.chara.getAttributeValue("constraint")!=null)&&(this.chara.getAttributeValue("constraintid")!=null))
{
//if constraintid is not null then two different structures are being compared
special_case = specialCaseDifferentStructures();
}else//handles the case where a single property is being discussed
{
quality = this.chara.getAttributeValue("name");
}
}
quality=format(quality);
}
if(special_case)
{
return;
}
boolean negated = false;
if(quality.startsWith("not ")){
negated = true;
quality = quality.substring(quality.indexOf(" ")+1).trim(); //deal with negated quality here
}
//is the candidate a relational quality?
QualityProposals relationalquality = PermittedRelations.matchInPermittedRelation(quality, false,1);
if(relationalquality!=null){
//attempts to find related entity in constraints
// constraints = qualitymodifier if quality is a relational quality
boolean usedconstraint = false;
if (chara.getAttribute("constraintid") != null) {
ArrayList<EntityProposals> relatedentities = findEntityInConstraints();
String constraint = chara.getAttributeValue("constraint").trim();
//check and see if prep of the relation need to be matched: 'separated from' <> 'separated by'
String prep = constraint.contains(" ")? constraint.substring(0, constraint.indexOf(" ")): constraint;
boolean check = false;
if(prep.matches(this.specialprep)) check = true;
for(Quality rq: relationalquality.getProposals()){
String label = rq.getLabel();
String labelprep = label.contains(" ")? label.substring(0, constraint.indexOf(" ")): label;
if(!check || (check && labelprep.matches(CharacterHandler.prepositions) && labelprep.compareTo(prep)==0)){
for(EntityProposals relatedentity: relatedentities){
QualityProposals qproposals = new QualityProposals();
qproposals.add(new RelationalQuality(relationalquality, relatedentity));
qproposals.setPhrase(quality);
Utilities.addQualityProposals(qualities, qproposals);
usedconstraint = true;
//this.qualities.add(qproposals);
}
}
}
/*ArrayList<EntityProposals> relatedentities = findEntityInConstraints();
for(EntityProposals relatedentity: relatedentities){
QualityProposals qproposals = new QualityProposals();
qproposals.add(new RelationalQuality(relationalquality, relatedentity));
qproposals.setPhrase(quality);
Utilities.addQualityProposals(qualities, qproposals);
//this.qualities.add(qproposals);
}*/
}
if(!usedconstraint){
if(structuresWithSameCharacters(this.chara.getParentElement().getParentElement())){// A and B: fused
//Processes structures with same characters(RQ's) to be related => Hariharan
Hashtable<String,ArrayList<EntityProposals>> entities = this.processStructuresWithSameCharacters(this.chara.getParentElement().getParentElement());
addREPE(entities,relationalquality);
}//check whether the parent structure(this.entity) is a bilateral entity
else if((this.entity!=null)&&(checkBilateral(this.entity)==true))//bilateral structures: fused
{
this.primaryentities.clear();//Since among the primary entities only some are bilateral and is relevant to this character/relational quality => Hariharan
for(Entity e:this.bilateral)
{
RelationalEntityStrategy re = new RelationalEntityStrategy(e);
re.handle();
Hashtable<String,ArrayList<EntityProposals>> entities = re.getEntities();
addREPE(entities,relationalquality);
}
}
else /* if(!structuresWithSameCharacters(this.chara.getParentElement().getParentElement()))*///if entity is null,then structure is whole_organism, it should be handled here
//single, non-bilateral structure: fused: for example whole_organism:fused
{
//Handling characters that belong to a single structure => Hariharan
Hashtable<String,ArrayList<EntityProposals>> entities = SingleStructures();
addREPE(entities,relationalquality);
}
/*else
{
//Handle using text
}*/
}
if((this.primaryentities.size()>0)&&(this.qualities.size()>0))
donotresolve=true;
return;
}
//constraints may yield entity parts such as entity locator, save those, resolve them later
//Need to handle this differently, if quality is size.
if (chara.getAttribute("constraintid") != null) {
ArrayList<EntityProposals> entities = findEntityInConstraints();
for(EntityProposals entity: entities){
this.entityparts.add(entity);
}
}
//not a relational quality, is this a simple quality or a negated quality?
TermSearcher ts = new TermSearcher();
ArrayList<FormalConcept> results = ts.searchTerm(quality, "quality");
if(results!=null){ //has a match
//QualityProposals qproposals = new QualityProposals();
for(FormalConcept resultfc: results){
QualityProposals qproposals = new QualityProposals();
Quality result = (Quality)resultfc;
//qualities involving length should be handled with related entity
if((result.getLabel()!=null)&&result.getLabel().matches(".*(length|width|size|depth|broad)"))
{
this.resolve=true;
}
//the below if-loop is used to reset the string to original value of quality
if((quality!=qualitycopy))
{
result.setSearchString(qualitycopy);
result.setString(qualitycopy);
}
if(negated){
/*TODO use parent classes Jim use for parent classes*/
String [] parentinfo = ontoutil.retreiveParentInfoFromPATO(result.getId());
Quality parentquality = new Quality();
parentquality.setSearchString("");
parentquality.setString(parentinfo[1]);
parentquality.setLabel(parentinfo[1]);
parentquality.setId(parentinfo[0]);
qproposals.add(new NegatedQuality(result, parentquality));
qproposals.setPhrase("not "+quality);
Utilities.addQualityProposals(qualities, qproposals);
//this.qualities.add(qproposals);
//return;
}else{
qproposals.add(result);
qproposals.setPhrase(quality);
Utilities.addQualityProposals(qualities, qproposals);
//this.qualities.add(qproposals);
//return;
}
}
return;
}else{//no match for quality, could it be something else?
//try to match it in entity ontologies
//text::Caudal fin heterocercal (heterocercal tail is a subclass of caudal fin)
//xml: structure: caudal fin, character:heterocercal
//=> heterocercal tail: present
if(this.entity!=null){
for(int i = 0; i<entity.size(); i++){
EntityProposals ep = entity.get(i);
if(ep.higestScore()>=0.8f){
for(Entity e: ep.getProposals()){
Character2EntityStrategy ces = new Character2EntityStrategy(e, quality);
ces.handle();
if(ces.getEntity()!=null && ces.getQuality()!=null){
ep = ces.getEntity();//update
//this.qualities.add(ces.getQuality());
Utilities.addQualityProposals(qualities, ces.getQuality());
//int o = this.primaryentities.indexOf(entity.get(i)); //if only update qualities, no need to update primaryentities
//if(o>=0) this.primaryentities.set(o, ep);
//else this.primaryentities.add(ep);
this.entity.set(i, ep);
return;
}
}
}
}
}
/*if((this.entity!=null)&&(this.entity.higestScore()>=0.8f)){
for(Entity e: entity.getProposals()){
Character2EntityStrategy2 ces = new Character2EntityStrategy2(e, quality);
ces.handle();
if(ces.getEntity()!=null && ces.getQuality()!=null){
this.entity = ces.getEntity();
this.qualities.add(ces.getQuality());
return;
}
}
}*/
}
//TODO: could this do any good?
//will resolve() do any good?
//Entity result = (Entity) ts.searchTerm(quality, "entity");
//still not successful, check other matches
QualityProposals qproposals = null;
ArrayList<FormalConcept> fcs = ts.getCandidateMatches(quality, "quality");
if(fcs!=null){
for(FormalConcept aquality: fcs){
if((qualityclues!=null)&&(qualityclues.size()!=0)){
for(String clue: qualityclues){
ArrayList<FormalConcept> qclues = ts.searchTerm(clue, "quality");
for(FormalConcept qcluefc: qclues){
Quality qclue = (Quality)qcluefc;
if(aquality.getLabel().compareToIgnoreCase(clue)==0 || ontoutil.isChildQuality(aquality.getClassIRI(), qclue.getClassIRI()) ){
aquality.setConfidenceScore(1.0f); //increase confidence score
}
}
}
}
//no clue or clue was not helpful
if(qproposals ==null) qproposals = new QualityProposals();
qproposals.add((Quality)aquality);
qproposals.setPhrase(quality);
Utilities.addQualityProposals(qualities, qproposals);//correct grouping of proposals
//this.qualities.add(qproposals); //incorrect, separated proposals from the same phrase
}
}
if((this.qualities.size()==0)&&(quality.equals("")==false)){
Quality result=new Quality();
result.setSearchString(quality);
result.setString(quality);
result.setConfidenceScore(0.0f); //TODO: confidence score of no-ontologized term = goodness of the phrase for ontology
if(qproposals ==null) qproposals = new QualityProposals();
qproposals.add(result);
qproposals.setPhrase(quality);
Utilities.addQualityProposals(qualities, qproposals);//correct grouping of proposals
//this.qualities.add(qproposals); //incorrect, separated proposals from the same phrase
}
return;
}
private String format(String quality) {
boolean negation = false;
if(((this.chara.getAttributeValue("name")!=null)&&(this.chara.getAttributeValue("name").matches(".*?_?(size|count|ratio)_?.*"))))
{
if(this.chara.getAttributeValue("name").matches(".*?_?size_?.*"))
{
quality="size";
}
else if(this.chara.getAttributeValue("name").matches(".*?_?count_?.*"))
{
quality="count";
}
else if(this.chara.getAttributeValue("name").equals(".*?_?ratio_?.*"))
{
quality = "ratio";
}
}
if(quality.matches(".*_?(width|height|length|depth|size)_?.*"))
{
if(this.chara.getAttributeValue("modifier")!=null)
{
if(this.chara.getAttributeValue("modifier").matches(".*\\b(not|no)\\b.*"))
{
negation = true;
}
if(this.chara.getAttributeValue("modifier").matches(".*\\b(more|great|wide|broad|large)\\b.*"))
{
quality = (negation==false?"increased ":"decreased ")+quality;
}
else
{
quality = (negation==true?"increased ":"decreased ")+quality;
}
} else if(this.chara.getAttributeValue("value")!=null)
{
if(this.chara.getAttributeValue("value").matches(".*\\b(not|no)\\b.*"))
{
negation = true;
}
if(this.chara.getAttributeValue("value").matches(".*\\b(more|great|wide|broad|large)\\b.*"))
{
quality = (negation==false?"increased ":"decreased ")+quality;
}
else
{
quality = (negation==true?"increased ":"decreased ")+quality;
}
}
}
return quality;
}
/**
* handles case where same property of two different structures are being discussed
* Here, the first entity is being identified by this.entity and related entity is identified by constraintid
* @return always return true
* @throws Exception
*/
private boolean specialCaseDifferentStructures() throws Exception {
String quality = this.chara.getAttributeValue("name");
boolean negation=false;
boolean flag=false;//used to check, if quality is modified
if(this.chara.getAttributeValue("modifier")!=null)
{
if(this.chara.getAttributeValue("modifier").matches(".*(not|no).*"))
{
negation = true;
}
if(this.chara.getAttributeValue("modifier").matches(".*(more|great|wide|broad|large|long|atleast).*"))
{
quality = (negation==false?"increased ":"decreased ")+quality;
}
else
{
quality = (negation==true?"increased ":"decreased ")+quality;
}
flag=true;
}
TermSearcher ts = new TermSearcher();
ArrayList<FormalConcept> primary_quality = ts.searchTerm(quality, "quality");
if((primary_quality==null) &&(flag==true))//removes the increased or decreased and check for the plain quality
{
quality = quality.substring(quality.indexOf(" "));
primary_quality = ts.searchTerm(quality, "quality");
}
QualityProposals qp = new QualityProposals();
qp.setPhrase(quality);
for(FormalConcept fc: primary_quality){
qp.add(fc);
}
String id = this.chara.getAttributeValue("constraintid").trim();
ArrayList<String> ids = new ArrayList<String>();
if(id.contains(" ")){
ids.addAll(Arrays.asList(id.split("\\s+")));
}else{
ids.add(id);
}
for(String aid: ids){
//Element structure = (Element) XPath.selectSingleNode(root, ".//structure[@id='"+this.chara.getAttributeValue("constraintid")+"']");
Element structure = (Element) XPath.selectSingleNode(root, ".//structure[@id='"+aid+"']");
String structureid = structure.getAttributeValue("id");
String structurename = Utilities.getStructureName(root, structureid);
EntityParser rep = new EntityParser(chara, root, structureid, structurename, keyentities, fromcharacterstatement);
structure.setAttribute("processed", "true");
if(rep!=null && rep.getEntity()!=null){
for(EntityProposals ep: rep.getEntity()){
RelationalQuality rq = new RelationalQuality(qp,ep);
QualityProposals qp1 = new QualityProposals();
qp1.add(rq);
if(rq!=null)
{
Utilities.addQualityProposals(qualities, qp1); //correct grouping
//this.qualities.add(qp); //incorrect, separating proposals of the same phrase
}
}
}
}
return true;
}
private void preProcess(String quality) {
//The below code is used to handle (height/width) kind of character name
if((quality.contains("/")==true)&&(quality.split("/").length==2))
{
this.chara.setAttribute("constraint", quality.split("/")[1]);
this.chara.setAttribute("name", quality.split("/")[0]);
}
//The below code uses quality clue to process empty names and replace them with clues
if((quality==null)||(quality.equals("")||quality.equals("size"))==true)
{
if(this.qualityclues!=null){
for(String measure:this.qualityclues)
{
if(measure.matches("(height|length|width|depth|broad|breadth)")==true)
{
this.chara.setAttribute("name", measure);
break;
}
}
}
}
if(quality.contains("_")==true)
{
if(quality.contains("height"))
{
this.chara.setAttribute("name","height");
}else if(quality.contains("width"))
{
this.chara.setAttribute("name","width");
}else if(quality.contains("depth"))
{
this.chara.setAttribute("name","depth");
}else if(quality.contains("length"))
{
this.chara.setAttribute("name","length");
}
}
}
private boolean specialSizeCaseSameStructure() {
String primaryquality = cleanUp(this.chara.getAttributeValue("name"));
String secondaryquality = cleanUp(this.chara.getAttributeValue("constraint"));
String modifier = this.chara.getAttributeValue("modifier");
boolean negation=false;
if(modifier==null)
{
modifier = this.chara.getAttributeValue("value");
}
String relation;
Entity relatedentity=null;
QualityProposals qp = new QualityProposals();
qp.setPhrase(primaryquality+":"+secondaryquality);
TermSearcher ts = new TermSearcher();
ArrayList<FormalConcept> primary_quality = ts.searchTerm(primaryquality, "quality");
ArrayList<FormalConcept> secondary_quality = ts.searchTerm(secondaryquality, "quality");
if(modifier.matches(".*(not|no).*"))
{
negation = true;
}
if(modifier.matches(".*(more|great|wide|broad|large|much|long|tall).*"))
{
relation = negation==false?"increased_in_magnitude_relative_to":"decreased_in_magnitude_relative_to";
}
else
{
relation = negation==true?"increased_in_magnitude_relative_to":"decreased_in_magnitude_relative_to";
}
FormalRelation rel = Dictionary.iheresin;
if(this.entity!=null)
{
for(EntityProposals ep: this.entity)
{
for(Entity e: ep.getProposals())
//for(Entity e:this.entity.getProposals())
{
for(FormalConcept pfc: primary_quality){
Quality primary_qualityq = (Quality)pfc;
for(FormalConcept sfc: secondary_quality){
Quality secondary_qualityq = (Quality)sfc;
relatedentity = e;
REntity related = new REntity(rel,relatedentity);
//CompositeQuality compquality = new CompositeQuality(primary_quality,secondary_quality,relation,related);
CompositeQuality compquality = new CompositeQuality(primary_qualityq,secondary_qualityq,relation,related);
qp.add(compquality);
}
}
}
}
} else
{
if(this.keyentities!=null)
{
for(EntityProposals ep:this.keyentities)
{
for(Entity e: ep.getProposals())
{
for(FormalConcept pfc: primary_quality){
Quality primary_qualityq = (Quality)pfc;
for(FormalConcept sfc: secondary_quality){
Quality secondary_qualityq = (Quality)sfc;
relatedentity = e;
REntity related = new REntity(rel,relatedentity);
CompositeQuality compquality = new CompositeQuality(primary_qualityq,secondary_qualityq,relation,related);
qp.add(compquality);
}
}
}
}
}
}
Utilities.addQualityProposals(qualities, qp);
//this.qualities.add(qp);
return true;
}
private String cleanUp(String entityname) {
if(entityname!=null)
{
if(entityname.matches(".*(length).*"))
{
entityname = "length";
}
else if(entityname.matches(".*(height).*"))
{
entityname = "height";
}
else if(entityname.matches(".*(depth).*"))
{
entityname = "depth";
}
else if(entityname.matches(".*(broad).*"))
{
entityname = "broad";
}
else{
entityname = "width";
}
}
return entityname;
}
/*
* Uses Elk to find out if which entities are bilateral
* //Checks whether the parent structure is bilateral or not
//this.entity contains the parent entity
*/
private boolean checkBilateral(ArrayList<EntityProposals> eps) {
boolean bilateralcheck = false;
for(EntityProposals ep: eps){
EntityProposals epclone = ep.clone();//cloning to avoid original entity proposals to be changed
for(Entity e:epclone.getProposals())
{
if(e.getId()!=null)
{
if(e instanceof SimpleEntity)
{
if(XML2EQ.elk.lateralsidescache.get(e.getPrimaryEntityLabel())!=null)
{
this.bilateral.add(e);
bilateralcheck=true;
}
}
else
{
for(Entity e1:((CompositeEntity) e).getEntities())
{
if(XML2EQ.elk.lateralsidescache.get(e1.getPrimaryEntityLabel())!=null)
{
this.bilateral.add(e);
bilateralcheck=true;
break;
}
}
}
}
}
}
return bilateralcheck;
}
/*
* Processes multiple structures which has same characters
*/
private boolean structuresWithSameCharacters(Element statement) {
try {
List<Element> characters;
characters = pathCharacterUnderStucture.selectNodes(statement);
int count=0;
//Checks for same characters present under multiple structures
Iterator<Element> itr = characters.listIterator();
while(itr.hasNext())
{
Element character = itr.next();
if((character.getAttribute("name").getValue().equals(this.chara.getAttribute("name").getValue()))&&(character.getAttribute("value").getValue().equals(this.chara.getAttribute("value").getValue())))
count++;
}
if(count>1)
return true;
else
return false;
} catch (JDOMException e) {
LOGGER.error("", e);
}
return false;
}
/**
* Adds Related entities and Primary entities to existing identified entities. Also remove duplicates in the entities
* @param entities
* @param relationalquality
*/
private void addREPE(Hashtable<String, ArrayList<EntityProposals>> entities, QualityProposals relationalquality) {
ArrayList<EntityProposals> primaryentities = entities.get("Primary Entity");
ArrayList<EntityProposals> relatedentities = entities.get("Related Entities");
if((relatedentities!=null)&&relatedentities.size()>0)
{
for(EntityProposals relatedentity: relatedentities){
QualityProposals qproposals = new QualityProposals();
qproposals.add(new RelationalQuality(relationalquality, relatedentity));
//this.qualities.add(qproposals);
Utilities.addQualityProposals(qualities, qproposals);
}
if(primaryentities.size()>0)
{
ListIterator<EntityProposals> itr1 = primaryentities.listIterator();
//to remove duplicate entities
while(itr1.hasNext())
{
boolean duplicate = false;
EntityProposals ep1 = (EntityProposals) itr1.next();
for(Entity en1: ep1.getProposals())
{
ListIterator<EntityProposals> itr2 = this.primaryentities.listIterator();
while(itr2.hasNext())
{
EntityProposals ep2 = (EntityProposals) itr2.next();
for(Entity en2:ep2.getProposals()){//add more conditions to analyze and handle bilateral entities
if(en2.content().compareTo(en1.content())==0)
duplicate = true;
}
}
}
if(!duplicate) Utilities.addEntityProposals(this.primaryentities, ep1);
}
/*while(itr1.hasNext())
{
EntityProposals ep1 = (EntityProposals) itr1.next();
for(Entity en1: ep1.getProposals())
{
ListIterator<EntityProposals> itr2 = this.primaryentities.listIterator();
while(itr2.hasNext())
{
EntityProposals ep2 = (EntityProposals) itr2.next();
for(Entity en2:ep2.getProposals())//add more conditions to analyze and handle bilateral entities
if(en2.getPrimaryEntityLabel().equals(en1.getPrimaryEntityLabel()))
itr1.remove(); //caused IllegalState exception when there are duplicates
}
}
}
this.primaryentities.addAll(primaryentities);
*/
}
}
}
/*
* It identifies structures which have the same characters(Relational Quality)
* and it returns all the structures which has the same characters as related entities
* if a structure is a whole_organism, it calls bilateralstructures to handle the scenario.
*
*
*/ @SuppressWarnings("unchecked")
private Hashtable<String, ArrayList<EntityProposals>> processStructuresWithSameCharacters(Element statement) {
//TODO: Handle scenario where all the characters have whole_organism as its parent structure and Keyentities is null
try {
List<Element> characters = pathCharacterUnderStucture.selectNodes(statement);
Hashtable<String,ArrayList<EntityProposals>> entities = new Hashtable<String,ArrayList<EntityProposals>>();
ArrayList<EntityProposals> primaryentities = new ArrayList<EntityProposals>();
ArrayList<EntityProposals> relatedentities = new ArrayList<EntityProposals>();
//Remove all other characters that are not same as the character under consideration
Iterator<Element> itr = characters.listIterator();
while(itr.hasNext())
{
Element character = itr.next();
if(!(character.getAttribute("name").getValue().equals(this.chara.getAttribute("name").getValue()))||!(character.getAttribute("value").getValue().equals(this.chara.getAttribute("value").getValue())))
itr.remove();
}
//First entity will be the main primary entity
if(characters.size()>1)
{
if(chara.getParentElement().getAttributeValue("name").compareTo(ApplicationUtilities.getProperty("unknown.structure.name"))!=0)
{
primaryentities.addAll(this.entity);//Since this is the identified entity of this character
}
}
//finding the related entities using structures with same character name and value
for(int i=1;i<characters.size();i++)
{
Element character = characters.get(i);
if((character.getAttribute("name").getValue().equals(this.chara.getAttribute("name").getValue()))&&(character.getAttribute("value").getValue().equals(this.chara.getAttribute("value").getValue())))
{
//read the structure(other than whole_organism) of this character, find the entity,create entity proposals
Element ParentStructure = character.getParentElement();
if(!ParentStructure.getAttributeValue("name").equals(ApplicationUtilities.getProperty("unknown.structure.name")))
{
ArrayList<EntityProposals> entity = new EntitySearcherOriginal().searchEntity(root, ParentStructure.getAttributeValue("id"),
ParentStructure.getAttributeValue("name"), "", ParentStructure.getAttributeValue("name"),"");
if(entity!=null) relatedentities.addAll(entity);
character.detach();
}
}
}
if(relatedentities.size()>0)
{
entities.put("Related Entities", relatedentities);
entities.put("Primary Entity", primaryentities);
}
return entities;
} catch (JDOMException e) {
LOGGER.error("", e);
}
return null;
}
private Hashtable<String, ArrayList<EntityProposals>> SingleStructures() {
Element ParentStructure = this.chara.getParentElement();
ArrayList<EntityProposals> primaryentities = new ArrayList<EntityProposals>();
ArrayList<EntityProposals> relatedentities = new ArrayList<EntityProposals>();
Hashtable<String,ArrayList<EntityProposals>> entities = new Hashtable<String,ArrayList<EntityProposals>>();
if(ParentStructure.getAttributeValue("name").compareTo(ApplicationUtilities.getProperty("unknown.structure.name"))==0)
{
if(this.keyentities.size()>1)//If keyentities.size> 1, first entity is a primary entity and the rest are related entities
{
for(int i=1;i<this.keyentities.size();i++)
relatedentities.add(this.keyentities.get(i));
primaryentities.add(this.keyentities.get(0));
}
//TODO: this.checkBilateral = true, but RelationalEntityStrategy return no results -- the formal check only the primary entity in a composite, the latter check the REntities as well
else if((this.keyentities.size()==1)&&(this.checkBilateral(this.keyentities)))//If keyentities.size==1, the it can be a bilateral entity
{
//call bilateral strategy on the single key entity
for(Entity e:this.bilateral)
{
RelationalEntityStrategy re = new RelationalEntityStrategy(e);
re.handle();
Hashtable<String,ArrayList<EntityProposals>> entities1 = re.getEntities();
relatedentities.addAll(entities1.get("Related Entities"));
primaryentities.addAll(entities1.get("Primary Entity"));
}
}
else if(this.keyentities.size()==1)
{
//use the the keyentities as both primary and related entities
relatedentities.addAll((Collection<? extends EntityProposals>) keyentities.clone());
primaryentities.addAll((Collection<? extends EntityProposals>) keyentities.clone());
}
entities.put("Related Entities", relatedentities);
entities.put("Primary Entity", primaryentities);
}
return entities;
}
private ArrayList<EntityProposals> findEntityInConstraints() {
ArrayList<EntityProposals> entities = new ArrayList<EntityProposals>();
if (chara.getAttribute("constraintid") != null) {
String[] conids = chara.getAttributeValue("constraintid").split("\\s+");
try{
for(String conid: conids){
String relatedentity = Utilities.getStructureName(root, conid);
//parents separated by comma (,).
String relatedentityparents = Utilities.getNamesOnPartOfChain(root, chara.getAttributeValue("constraintid"));
ArrayList<EntityProposals> result = new EntitySearcherOriginal().searchEntity(root, conid, relatedentity, relatedentityparents, relatedentity+"+"+relatedentityparents,"part_of");
if(result!=null) entities.addAll(result);
}
return entities;
}catch(Exception e){
LOGGER.error("", e);
}
}
return null;
}
/**
* resolve for entities from entity and entity parts obtained from constraints
* also when neither entity and qualities scores are strong, the keyentities scores are not strong or not ontologized
* should try to resolve them here? or in the end?
*/
public void resolve(){
//TODO
//this was how s2q was used before in SSP.
//Structure2Quality rq2 = new Structure2Quality(root,
// structname, structid, this.keyentities);
//rq2.handle();
//if(rq2.qualities.size()>0){
// entity = rq2.primaryentities;
// qualities = rq2.qualities;
//} else {
//TODO add some more conditions for resolving
//the below condition handles situation where a structure is identified to be a quality.
if(this.entity==null)
{
if(tobesolvedentity==null)
{
if(this.qualities.size()>0)
{
resolveForWholeOrganism();// Identify Entities/qualities/REntities for length or width or size
this.donotresolve=true;
}
}else if(tobesolvedentity.s2q!=null)
{
if(tobesolvedentity.s2q.qualities!=null)
{
this.qualities.clear();
this.qualities.addAll(tobesolvedentity.s2q.qualities);
tobesolvedentity.s2q.detach_character();
tobesolvedentity.s2q.cleanHandledStructures();
if(tobesolvedentity.s2q.primaryentities.size()>0)//relational quality might contain primary entities
{
this.primaryentities.clear();
this.primaryentities.addAll(primaryentities);
}
else
{
if(keyentities!=null)
{
this.primaryentities.clear();
this.primaryentities.addAll(keyentities);
}
}
}
}
}
else
{
this.donotresolve=true;
}
//Resolve for quality when it is "length"
if(this.entityparts.size()>0)
{
resolveIntoRelationalQuality();
this.donotresolve=true;
}
//need to resolve on cases where both entity!=null and S2Q!=null
}
/*
* When the parent structure is whole organism then, the first key entity is considered primary and the rest as related entity
*/
private void resolveForWholeOrganism() {
ArrayList<QualityProposals> rqp = new ArrayList<QualityProposals>();
if((this.keyentities!=null)&&(this.keyentities.size()>0))
{
if(this.entity==null)
{
//this.entity = this.keyentities.get(0);
this.entity = this.keyentities;
this.primaryentities.addAll(this.entity);
}
if(this.qualities.size()>0)
{
for(QualityProposals qp:this.qualities)
{
for(Quality q:qp.getProposals())//Reading each of the qualities
{
QualityProposals newqp = new QualityProposals();
if((q.getLabel()!=null)&&(q.getLabel().matches(".*(length|width|size|height|depth).*")))//If any of the quality label matches to "length", then the qp itself belongs to size
{
for(int i=1;i<this.keyentities.size();i++)
{
RelationalQuality rq = new RelationalQuality(qp,this.keyentities.get(i));
newqp.add(rq);
}
if(newqp.getProposals().size()>0)
{
rqp.add(newqp);
}
break;
}
}
}
}
if(rqp.size()>0)
{
this.qualities.clear();
this.qualities.addAll(rqp);
this.donotresolve = true;
}
}
}
/**
* This function handles the special case when increased/decreased length is a quality
* The entity in parts will become the Related entity instead of Entity Locator
*/
public void resolveIntoRelationalQuality() {
ArrayList<QualityProposals> rqp = new ArrayList<QualityProposals>();
if(this.qualities.size()>0)
{
for(QualityProposals qp:this.qualities)
{
for(Quality q:qp.getProposals())//Reading each of the qualities
{
QualityProposals newqp = new QualityProposals();
if((q.getLabel()!=null)&&(q.getLabel().matches(".*(length|width|size|height|depth|broad)")))//If any of the quality label matches to "length", then the qp itself belongs to size
{
for(EntityProposals ep : this.entityparts)
{
RelationalQuality rq = new RelationalQuality(qp,ep);//this forms relationalquality for each of QP and RE and used for new QP
newqp.add(rq);
}
rqp.add(newqp);
break;
}
}
}
if(rqp.size()>0)
{
this.entityparts.clear();
this.qualities.clear();
this.qualities.addAll(rqp);
}
}
}
public ArrayList<QualityProposals> getQualities(){
return this.qualities;
}
public ArrayList<EntityProposals> getEntity(){
return this.entity;
}
public ArrayList<EntityProposals> getPrimaryentities() {
return primaryentities;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}