package owltools.graph;

import java.util.List;
import java.util.Vector;

import org.semanticweb.owlapi.model.OWLObject;
import org.semanticweb.owlapi.model.OWLObjectPropertyExpression;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLNamedObject;
import org.semanticweb.owlapi.model.OWLRestriction;

import owltools.graph.OWLQuantifiedProperty.Quantifier;

public class OWLGraphEdge {
	
	
	private OWLObject source;
	private OWLObject target;
	private OWLOntology ontology;
	private int distance = 1;
	private List<OWLQuantifiedProperty> quantifiedPropertyList = new Vector<OWLQuantifiedProperty>();
	
	public OWLGraphEdge(OWLObject source, OWLObject target,
			OWLOntology ontology, OWLQuantifiedProperty qp) {
		super();
		this.source = source;
		this.target = target;
		this.ontology = ontology;
		setSingleQuantifiedProperty(qp);
	}

	public OWLGraphEdge(OWLRestriction s, OWLObject t,
			OWLQuantifiedProperty el, OWLOntology o) {
		super();
		this.source = s;
		this.target = t;
		this.ontology = o;
		setSingleQuantifiedProperty(el);
	}

	public OWLGraphEdge(OWLObject source, OWLObject target, List<OWLQuantifiedProperty> qpl, OWLOntology ontology) {
		super();
		this.source = source;
		this.target = target;
		this.ontology = ontology;
		this.quantifiedPropertyList = qpl;
	}

	
	public OWLGraphEdge(OWLObject source, OWLObject target, OWLOntology ontology) {
		super();
		this.source = source;
		this.target = target;
		this.ontology = ontology;
		setSingleQuantifiedProperty(new OWLQuantifiedProperty(Quantifier.SUBCLASS_OF)); // defaults to subclass
	}


	public OWLGraphEdge(OWLObject source, OWLObject target) {
		super();
		this.source = source;
		this.target = target;
	}


	public OWLGraphEdge(OWLObject s, OWLObject t, OWLObjectPropertyExpression p,
			Quantifier q, OWLOntology o) {
		super();
		OWLQuantifiedProperty el = new OWLQuantifiedProperty(p,q);
		this.source = s;
		this.target = t;
		this.ontology = o;
		setSingleQuantifiedProperty(el);
	}


	public OWLGraphEdge(OWLObject s, OWLObject t, Quantifier q) {
		super();
		OWLQuantifiedProperty el = new OWLQuantifiedProperty(null,q);
		this.source = s;
		this.target = t;
		setSingleQuantifiedProperty(el);
	}

	public OWLObject getSource() {
		return source;
	}
	public String getSourceId() {
		return source.toString();
	}
	public void setSource(OWLObject source) {
		this.source = source;
	}
	public OWLObject getTarget() {
		return target;
	}
	public String getTargetId() {
		return target.toString();
	}

	public void setTarget(OWLObject target) {
		this.target = target;
	}
	
	public int getDistance() {
		return distance;
	}

	public void setDistance(int distance) {
		this.distance = distance;
	}


	/**
	 * @return copy of QPL
	 */
	public List<OWLQuantifiedProperty> getQuantifiedPropertyList() {
		return new Vector<OWLQuantifiedProperty>(quantifiedPropertyList);
	}

	public void setQuantifiedPropertyList(List<OWLQuantifiedProperty> qps) {
		this.quantifiedPropertyList = qps;
	}

	public OWLQuantifiedProperty getSingleQuantifiedProperty() {
		return quantifiedPropertyList.get(0);
	}
	
	public OWLQuantifiedProperty getLastQuantifiedProperty() {
		return (OWLQuantifiedProperty)quantifiedPropertyList.get(quantifiedPropertyList.size()-1);
	}

	public void setSingleQuantifiedProperty(OWLQuantifiedProperty qp) {
		quantifiedPropertyList = new Vector<OWLQuantifiedProperty>();
		quantifiedPropertyList.add(qp);
	}

	public OWLQuantifiedProperty getFinalQuantifiedProperty() {
		return quantifiedPropertyList.get(quantifiedPropertyList.size()-1);
	}

	public OWLOntology getOntology() {
		return ontology;
	}
	public void setOntology(OWLOntology ontology) {
		this.ontology = ontology;
	}


	public boolean isSourceNamedObject() {
		return (source instanceof OWLNamedObject);
	}
	public boolean isTargetNamedObject() {
		return (target instanceof OWLNamedObject);
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		sb.append(source);
		sb.append(" ");
		sb.append(getQuantifiedPropertyList());
		sb.append(" ");
		sb.append(" ");
		sb.append(target);
		sb.append("]");
		return sb.toString();
	}
	
	public int hashCode() {
		// TODO use an explicit function here. Do not rely on toString()
		// TODO cache the hashcode (calculation is expensive): 
		//      Requires control over the input parameters, e.g.
		//      invalidate current hashcode when they are changed! 
		return toString().hashCode();
	}
	
	public boolean isEq(Object a, Object b) {
		if (a == null && b == null)
			return true;
		if (a == null || b == null)
			return false;
		
		return a.equals(b);
	}
	
	public boolean equals(Object e) {
		
		if(e == null && !(e instanceof OWLGraphEdge))
			return false;
		
		OWLGraphEdge other = (OWLGraphEdge) e;
		
		
		return 
		isEq(other.getSource(),getSource()) &&
		isEq(other.getTarget(),getTarget()) &&
		isEq(quantifiedPropertyList,other.getQuantifiedPropertyList());
		
	}


}

@@ -4204,53 +4204,23 @@
 ODO 
-use an explicit function here. Do not rely on
+remove usage of
  toS
@@ -4230,28 +4230,39 @@
 ng()
-%0A%09%09// TODO cache the
+ for owlQuantifiedProperties in
  has
@@ -4267,17 +4267,16 @@
 ashcode 
-(
 calculat
@@ -4282,176 +4282,412 @@
 tion
- is expensive): %0A%09%09//      Requires control over the input parameters, e.g.%0A%09%09//      invalidate current 
+%0A%09%09final int prime = 31;%0A%09%09int result = 1;%0A%09%09List%3COWLQuantifiedProperty%3E owlQuantifiedProperties = getQuantifiedPropertyList();%0A%09%09result = prime * result + ((owlQuantifiedProperties == null) ? 0 : owlQuantifiedProperties.toString().
 hash
-code when they are changed! %0A%09%09return toString().hashCode()
+Code());%0A%09%09result = prime * result + ((source == null) ? 0 : source.hashCode());%0A%09%09result = prime * result + ((target == null) ? 0 : target.hashCode());%0A%09%09return result
 ;%0A%09%7D

use create explicit hash function for speed up