package ps4;

import java.io.*;
import java.util.*;

/**
 * This class implements a testing driver for Simulator.  The
 * driver manages Simulators for integer arithmetic.
 **/

public class SimulatorTestDriver {

    // Fields
    HashMap simulators, simulatorsByNode;

    /**
     * @effects Constructs a new test driver.
     */
    public SimulatorTestDriver () {
        simulators = new HashMap ();
        simulatorsByNode = new HashMap();
    }

    /**
     * @requires simName != null
     * @modifies this
     * @effects Creates a new Simulator that shall be named
     * simName.  The simulator's graph is initially empty.
     */
    public void createSimulator(String simName) {
        simulators.put(simName, new Simulator());
    }

    /**
     * @requires createSimulator(simName) &&
     *                   nodeName != null
     *                   && nodeName has not been used in a previous
     *                          addPipe, addPlusFilter, or addGCDFilter
     *                          call on this object
     * @modifies this, simulator named simName
     * @effects Creates a new IntPipe named by the string nodeName.
     * The node can be referred to by name after it has been created
     * with this method.
     * Adds a pipe represented by the string nodeName
     * to the simulator named simName.
     */
    public void addPipe (String simName, String nodeName) {
        Simulator sim = (Simulator) simulators.get(simName);
        sim.addPipe(nodeName, new IntPipe(nodeName, sim));
        simulatorsByNode.put(nodeName, sim);
    }

    /**
     * @requires createSimulator(simName) && 
     *                   nodeName != null
     *                   && nodeName has not been used in a previous
     *                          addPipe, addPlusFilter, or addGCDFilter
     *                          call on this object
     * @modifies this, simulator named simName
     * @effects Creates a new PlusFilter named by the string nodeName.
     * The node can be referred to by name after it has been created
     * with this method.
     * Adds a filter represented by the string nodeName
     * to the simulator named simName.
     */
    public void addPlusFilter(String simName, String nodeName) {
        Simulator sim = (Simulator) simulators.get(simName);
        sim.addFilter(nodeName, new PlusFilter(nodeName, sim));
        simulatorsByNode.put(nodeName, sim);
    }

    /**
     * @requires createSimulator(simName) && 
     * @requires nodeName != null
     *                   && nodeName has not been used in a previous
     *                          addPipe, addPlusFilter, or addGCDFilter
     *                          call on this object
     * @modifies this, simulator named simName
     * @effects Creates a new GCDFilter named by the string nodeName.
     * The node can be referred to by name after it has been created
     * with this method.
     * Adds a filter represented by the string nodeName
     * to the simulator named simName.
     */
    public void addGCDFilter(String simName, String nodeName) {
        Simulator sim = (Simulator) simulators.get(simName);
        sim.addFilter(nodeName, new GCDFilter(nodeName, sim));
        simulatorsByNode.put(nodeName, sim);
    }

    /**
     * @requires createSimulator(simName)
     *                   && (         (addPipe(parentName) && addFilter(childName))
     *                                 || (addFilter(parentName) && addPipe(childName)) )
     *                   && edgeLabel != null
     *                   && node named parentName has no other outgoing edge labeled edgeLabel
     *                   && node named childName has no other incoming edge labeled edgeLabel
     * @modifies simulator named simName
     * @effects Adds an edge from the node parentName to the node
     * childName in the simulator simName.  The new edge's label is the
     * string edgeLabel.
     */
    public void addEdge(String simName, 
        String parentName, 
        String childName, 
        String edgeLabel) {
        Simulator sim = (Simulator) simulators.get(simName);
        sim.addEdge(parentName, childName, edgeLabel);
    }

    /**
     * @requires addPipe(pipeName)
     * @modifies simulator containing pipe named pipeName
     * @effects pushes the integer value into the pipe named pipeName
     */
    public void injectInput (String pipeName,
        int value) {
        Simulator sim = (Simulator) simulatorsByNode.get(pipeName);
        sim.injectIntoPipe(pipeName, new Integer(value));
    }

    /**
     * @requires addPipe(pipeName)
     * @return a space-separated list of the integer values currently in
     * the pipe named pipeName
     */
    public String listContents (String pipeName) {
        Simulator sim = (Simulator) simulatorsByNode.get(pipeName);
        StringBuffer s = new StringBuffer();

        Object o;
        
        for (Iterator it = sim.pipeContentsIterator(pipeName); it.hasNext(); )
        {
            s.append(" ");
            s.append(((Integer) it.next()).toString());
        }

        String str = s.toString();

        if (str.equals(""))
        {
            return str;
        } else {
            return str.substring(1); // chop off the leading space
        }
        
    }
        
    /**
     * @requires createSimulator(simName)
     * @modifies simulator named simName
     * @effects runs simulator named simName for a single 1-second time slice
     */
    public void simulate (String simName) {
        Simulator sim = (Simulator) simulators.get(simName);

        sim.simulate(1);
    }
}
