package kinesisFHM.commonTypes;

import java.io.IOException;
import java.io.Serializable;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class DependencyGraph implements Serializable {

	// this is the dependency graph, for each event we consider the set of pre and post events
	private HashMap<String, Set<String>> post_table;
	private HashMap<String, Set<String>> pre_table;
	private HashMap<EventPair, Set<WfRType>> tags;
	
	public DependencyGraph() {
		post_table = new HashMap<String, Set<String>>();
		pre_table = new HashMap<String, Set<String>>();
		tags = new HashMap<EventPair, Set<WfRType>>();
	}

	// returns true if the edge has been added
	// otherwise returns false
	public boolean add(String from, String to, WfRType tag) {
		Set<WfRType> tagset = tags.get(new EventPair(from, to));
		if (tagset != null) {
			tagset.add(tag);
			return false;
		} else {
			tagset = EnumSet.of(tag);
			tags.put(new EventPair(from, to),  tagset);
				
			Set<String> tos = new HashSet<String>();
			post_table.put(from,  tos);
			tos.add(to);
			
			Set<String> froms = new HashSet<String>();
			pre_table.put(to,  froms);
			froms.add(from);
			
			return true;
		}
	}
	
	// returns true if the edge has been removed
	// otherwise returns false
	public boolean remove(String from, String to, WfRType tag) {
		Set<WfRType> tagset = tags.get(new EventPair(from, to));
		if (tagset == null) return false;
		
		tagset.remove(tag);
		if (!tagset.isEmpty()) return false;
		
		Set<String> tos = post_table.get(from);
		tos.remove(to);
		
		Set<String> froms = pre_table.get(to);
		froms.remove(from);
		
		tags.remove(new EventPair(from, to));
		return true;
	}
	
	public boolean isTagged(String from, String to, WfRType tag) {
		Set<WfRType> tagset = tags.get(new EventPair(from, to));
		if (tagset == null) return false;
		return tagset.contains(tag);
	}
	
	public Set<WfRType> getTags(String from, String to) {
		return tags.get(new EventPair(from, to));
	}
	
	public Set<String> getTargets(String from) {
		Set<String> tos = post_table.get(from);
		if (tos == null) {
			tos = new HashSet<String>();
			post_table.put(from,  tos);
		}
		return tos;
	}
	
	public Set<String> getCauses(String to) {
		Set<String> froms = pre_table.get(to);
		if (froms == null) {
			froms = new HashSet<String>();
			pre_table.put(to,  froms);
		}
		return froms;
	}
	
	public boolean contains(String from, String to) {
		return tags.containsKey(new EventPair(from, to));
	}
	
	private void writeObject(java.io.ObjectOutputStream out) throws IOException {
		out.writeObject(post_table);
		out.writeObject(pre_table);
		out.writeObject(tags);
	}

	private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
		this.post_table = (HashMap<String, Set<String>>) in.readObject();
		this.pre_table = (HashMap<String, Set<String>>) in.readObject();
		this.tags = (HashMap<EventPair, Set<WfRType>>) in.readObject();
	}
	
	public String toString() {
		return post_table.toString() + "\n" + pre_table.toString();
	}

}
