package owltools.gaf;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;

public class GafDocument{

	private static Logger LOG = Logger.getLogger(GafDocument.class);

	protected String id;
	protected String documentPath;

	protected transient Hashtable<String, Bioentity> bioentities;
	protected transient Hashtable<String, List<WithInfo>> withInfos;
	protected transient Hashtable<String, List<ExtensionExpression>> extensionExpressions;
	protected transient Hashtable<String, List<CompositeQualifier>> compositeQualifiers; 
	protected transient List<GeneAnnotation> annotations;

	private Map<String,Set<GeneAnnotation>> annotationMap = null;


	public GafDocument(){


		bioentities = new Hashtable<String, Bioentity>();
		withInfos = new Hashtable<String, List<WithInfo>>();
		extensionExpressions = new Hashtable<String, List<ExtensionExpression>>();
		compositeQualifiers = new Hashtable<String, List<CompositeQualifier>>();
		annotations = new ArrayList<GeneAnnotation>();
	}

	public void index() {
		annotationMap = new HashMap<String,Set<GeneAnnotation>>();
		for (GeneAnnotation a : getGeneAnnotations()) {
			String eid = a.getBioentity();
			if (!annotationMap.containsKey(eid))
				annotationMap.put(eid, new HashSet<GeneAnnotation>());
			annotationMap.get(eid).add(a);
		}
	}


	void setHibernateLoad(){
	}

	public GafDocument(String id, String documentPath) {
		this();
		this.id = id;
		this.documentPath = documentPath;
	}

	public String getId() {
		return id;
	}

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

	public String getDocumentPath() {
		return documentPath;
	}

	public void setDocumentPath(String documentPath) {
		this.documentPath = documentPath;
	}

	public Bioentity getBioentity(String id){
		return bioentities.get(id);
	}

	public Collection<Bioentity> getBioentities(){

		return bioentities.values();
	}


	public List<GeneAnnotation> getGeneAnnotations(){

		return annotations;
	}

	// TODO - improve efficiency, cache?
	public Set<GeneAnnotation> getGeneAnnotations(String bioentity){
		if (annotationMap != null) {
			return annotationMap.get(bioentity);
		}
		Set<GeneAnnotation> anns = new HashSet<GeneAnnotation>();
		for (GeneAnnotation ann : this.getGeneAnnotations()) {
			if (ann.getBioentity().equals(bioentity))
				anns.add(ann);
		}
		return anns;
	}

	public Set<GeneAnnotation> getGeneAnnotationsByGoCls(String cls){
		return null;
	}

	public void addBioentity(Bioentity bioentity){
		bioentity.setGafDocument(this.getId());
		bioentities.put(bioentity.getId(), bioentity);
	}

	public void addCompositeQualifier(CompositeQualifier compositeQualifier){
		List<CompositeQualifier> list = compositeQualifiers.get(compositeQualifier.getId());
		if(list == null){
			list = new ArrayList<CompositeQualifier>();
			compositeQualifiers.put(compositeQualifier.getId(), list);
		}

		if(!list.contains(compositeQualifier))
			list.add(compositeQualifier);
	}

	public Set<String> getCompositeQualifiersIds(){
		return compositeQualifiers.keySet();
	}

	public List<CompositeQualifier> getCompositeQualifiers(String id){
		List<CompositeQualifier> list = compositeQualifiers.get(id);


		return list;
	}

	public void addWithInfo(WithInfo withInfo){

		List<WithInfo> list = withInfos.get(withInfo.getId());
		if(list == null){
			list = new ArrayList<WithInfo>();
			withInfos.put(withInfo.getId(), list);
		}

		if(!list.contains(withInfo))
			list.add(withInfo);

	}

	public Set<String> getWithInfosIds(){
		return withInfos.keySet();
	}

	public List<WithInfo> getWithInfos(String id){
		List<WithInfo> list = withInfos.get(id);


		return list;
	}


	public List<ExtensionExpression> getExpressions(String id){
		List<ExtensionExpression> list = extensionExpressions.get(id);


		return list;
	}

	public Set<String> getExtensionExpressionIds(){
		return extensionExpressions.keySet();
	}

	public void addExtensionExpression(ExtensionExpression extensionExpression){
		List<ExtensionExpression> list = extensionExpressions.get(extensionExpression.getId());
		if(list == null){
			list = new ArrayList<ExtensionExpression>();
			extensionExpressions.put(extensionExpression.getId(), list);
		}

		if(!list.contains(extensionExpression))
			list.add(extensionExpression);
	}

	public void addGeneAnnotation(GeneAnnotation ga){
		ga.setGafDocumetObject(this);
		ga.setGafDocument(this.getId());
		annotations.add(ga);
	}

}

@@ -216,24 +216,25 @@
 a.util.Set;%0A
+%0A
 import org.a
@@ -2496,34 +2496,35 @@
 ns;%0A%09%7D%0A%0A%09public 
-Se
+Lis
 t%3CGeneAnnotation
@@ -2545,16 +2545,22 @@
 ationsBy
+Direct
 GoCls(St
@@ -2576,24 +2576,215 @@
 %7B%0A%09%09
-return null
+List%3CGeneAnnotation%3E result = new ArrayList%3CGeneAnnotation%3E();%0A%09%09for (GeneAnnotation annotation : annotations) %7B%0A%09%09%09if(cls.equals(annotation.cls)) %7B%0A%09%09%09%09result.add(annotation);%0A%09%09%09%7D%0A%09%09%7D%0A%09%09return result
 ;%0A%09%7D%0A
+%09
 %0A%09pu

implement empty method