package aspectEditor.aspectEditorUtils;
import java.util.jar.JarFile;
import java.util.*;
import java.io.*;
import edu.neu.ccs.demeter.aplib.*;
import edu.neu.ccs.demeter.*;
public class StrategyGraph extends SimpleStrategy implements SimpleStrategyI, StrategyGraphI, ConstraintMapI {
  protected SGEdge_SList edges;
  public SGEdge_SList get_edges() { return edges; }
  public void set_edges(SGEdge_SList new_edges) { edges = new_edges; }
  public StrategyGraph(NameMap parsedNameMap, SGEdge_SList edges) {
    super(parsedNameMap);
    set_edges(edges);
  }
  public static StrategyGraph parse(java.io.Reader in) throws ParseException { return new Parser(in)._StrategyGraph(); }
  public static StrategyGraph parse(java.io.InputStream in) throws ParseException { return new Parser(in)._StrategyGraph(); }
  public static StrategyGraph parse(String s) {
    try { return parse(new java.io.StringReader(s)); }
    catch (ParseException e) {
      throw new RuntimeException(e.toString());
    }
  }

    List edgeList = new ArrayList();
    class IncidentEdges {
      List incoming = new ArrayList(), outgoing = new ArrayList();
    }
    Map nodes = new HashMap(); // node -> IncidentEdges
    Set sources = new HashSet(), targets = new HashSet();
    SymbolicNameMapI nameMap = null;
  
  public StrategyGraph() { edges = new SGEdge_SList(); }
  StrategyGraph toGraph() {
    if (edgeList.isEmpty()) {
      Enumeration e = edges.elements();
      int i = 0;
      Set allSources = new HashSet(), allTargets = new HashSet();
      while (e.hasMoreElements()) {
	SGEdge edge = (SGEdge) e.nextElement();
	addEdge(edge, i++);
	allSources.add(edge.get_source());
	allTargets.add(edge.get_target());
      }
      if (sources.isEmpty()) sources = allSources;
      if (targets.isEmpty()) targets = allTargets;
      if (nameMap == null)
	nameMap = (parsedNameMap == null ? new NameMap() : parsedNameMap);
      parsedNameMap = null;
    }
    return this;
  }
  public void addEdge(SGEdge edge) {
    addEdge(edge, edges.size());
    edges.addElement(edge);
  }
  void addEdge(SGEdge edge, int i) {
    edgeList.add(edge);

    GlobSpec source = edge.get_source();
    if (edge.isSource()) sources.add(source);
    IncidentEdges ie = (IncidentEdges) nodes.get(source);
    if (ie == null) nodes.put(source, ie = new IncidentEdges());
    ie.outgoing.add(new Integer(i));

    GlobSpec target = edge.get_target();
    if (edge.isTarget()) targets.add(target);
    ie = (IncidentEdges) nodes.get(target);
    if (ie == null) nodes.put(target, ie = new IncidentEdges());
    ie.incoming.add(new Integer(i));
  }
  public SimpleStrategyI toSimpleStrategy() { return toGraph(); }
  public StrategyGraphI getStrategyGraph() { return this; }
  public Collection getSources() {
    return Collections.unmodifiableCollection(sources);
  }
  public Collection getTargets() {
    return Collections.unmodifiableCollection(targets);
  }
  public Collection getNames(Object v) {
    return ((GlobSpec) v).collectClassGlobs().map(nameMap);
  }
  public ConstraintMapI getConstraintMap() { return this; }
  public Collection getNodes() {
    return Collections.unmodifiableCollection(nodes.keySet());
  }
  public Collection getIncomingEdges(Object v) {
    IncidentEdges ie = (IncidentEdges) nodes.get(v);
    return ie == null ? null : ie.incoming;
  }
  public Collection getOutgoingEdges(Object v) {
    IncidentEdges ie = (IncidentEdges) nodes.get(v);
    return ie == null ? null : ie.outgoing;
  }
  public int numEdges() { return edgeList.size(); }
  public Object getEdgeSource(int i) {
    return ((SGEdge) edgeList.get(i)).get_source();
  }
  public Object getEdgeTarget(int i) {
    return ((SGEdge) edgeList.get(i)).get_target();
  }
  public boolean meetsConstraint(int i, Object v, NameMapI N) {
    SGEdge sgedge = (SGEdge) edgeList.get(i);
    return sgedge.meetsConstraint(v, composeNameMap(N));
  }
  public boolean meetsConstraint(int i, EdgeI e, NameMapI N) {
    SGEdge sgedge = (SGEdge) edgeList.get(i);
    return sgedge.meetsConstraint(e, composeNameMap(N));
  }
  public boolean meetsConstraint(Object a, Object v, NameMapI N) {
    return ((GlobSpec) a).match(v, composeNameMap(N));
  }
  public boolean meetsConstraint(Object a, EdgeI e, NameMapI N) {
    return ((GlobSpec) a).match(e, composeNameMap(N));
  }
  NameMapI composeNameMap(NameMapI N) {
    if (N != memoN) {
      memoN = N;
      if (N == null)
	composedN = nameMap;
      else if (nameMap == null)
	composedN = N;
      else
	composedN = NameMap.compose(N, nameMap);
    }
    return composedN;
  }
 NameMapI memoN, composedN; 
  public String toString() {
    StringWriter w = new StringWriter();
    PrintWriter pw = new PrintWriter(w);
    universal_trv0(new PrintVisitor(pw));
    pw.flush();
    return w.toString();
  }
  void universal_trv0_bef(UniversalVisitor _v_) {
    super.universal_trv0_bef(_v_);
    ((UniversalVisitor) _v_).before(this);
  }

  void universal_trv0_aft(UniversalVisitor _v_) {
    ((UniversalVisitor) _v_).after(this);
    super.universal_trv0_aft(_v_);
  }

  void universal_trv0(UniversalVisitor _v_) {
    universal_trv0_bef(_v_);
    ((UniversalVisitor) _v_).before_edges(this, edges);
    edges.universal_trv0(_v_);
    ((UniversalVisitor) _v_).after_edges(this, edges);
    super.universal_trv0(_v_);
    universal_trv0_aft(_v_);
  }

  void __trav_toGraph_PathDirective_trv(__V_PathDirective_toGraph __v0) {  }

}
