import java.util.Vector;

public class TMports
   {

// Sends and receives data from ports on a circuit in the DE-3

TMdata tm;
Vector<String> portNames;
Vector<Integer> portDirs;
Vector<Integer> portWidths;

public final static int READ = 0;
public final static int WRITE = 1;

public TMports() throws java.io.IOException {
   this(null);
}


public TMports(String hostname) throws java.io.IOException {

   // Create a TMports object.  Try connecting to the board on hostname.

   tm = new TM(hostname);
   portNames = new Vector<String>();
   portDirs = new Vector<Integer>();
   portWidths = new Vector<Integer>();
}


public void describePort(String portName, int direction, int portWidthBits) throws java.io.IOException {

   // Tell TMports about this port, so open() can recognize ports by
   // their names.
   // XXX -- you have to call describePort in the same order that they are
   // listed in the *.ports file, so that it get the port numbers right.
   // Maybe this routine should take the port number as an argument instead.

   if(portNames.contains(portName)) {
      throw new java.io.IOException("TMports.describePort() ignoring duplicate port named: " + portName);
   }

   if(direction != TMports.READ && direction != TMports.WRITE) {
      throw new java.io.IOException("TMports.describePort() illegal direction for port named: " + portName + " : " + direction);
   }

   portNames.add(portName);
   portDirs.add(new Integer(direction));
   portWidths.add(new Integer(portWidthBits));
}


public int open(String portName, String rw) throws java.io.IOException {

   // Open this port, and return a descriptor that refers to it

   int result = portNames.indexOf(portName);

   if(result == -1) {
      throw new java.io.IOException("TMports.open() can't find port named: " + portName);
   }

   int direction = portDirs.elementAt(result);

   if(rw.equals("r") && direction != TMports.READ) {
      throw new java.io.IOException("TMports.open() port named: " + portName + " is not a read port");
   }

   if(rw.equals("w") && direction != TMports.WRITE) {
      throw new java.io.IOException("TMports.open() port named: " + portName + " is not a write port");
   }

   return(result);
}


public void close(int port) throws java.io.IOException {

   // Close this port.

   if(port < 0 || port >= portNames.size()) {
      throw new java.io.IOException("TMports.close() port out of bounds: " + port);
   }
}


public int read(
          int port, 
          byte[] b,
          int off,
          int len) throws java.io.IOException {

   // Read len bytes from the port into b[], starting at off.

   if(port < 0 || port >= portNames.size()) {
      throw new java.io.IOException("TMports.read() port out of bounds: " + port);
   }

   if(portDirs.elementAt(port) != TMports.READ) {
      throw new java.io.IOException("TMports.read() port named: " + portNames.elementAt(port) + " is not a read port");
   }

   int portWidthBits = portWidths.elementAt(port);

   int result = tm.readPacket(b, off, len, port, portWidthBits);

   return(result);
}


public int write(
          int port, 
          byte[] b,
          int off,
          int len) throws java.io.IOException {

   // Write len bytes from b[] starting at off into the port

   if(port < 0 || port >= portNames.size()) {
      throw new java.io.IOException("TMports.write() port out of bounds: " + port);
   }

   if(portDirs.elementAt(port) != TMports.WRITE) {
      throw new java.io.IOException("TMports.write() port named: " + portNames.elementAt(port) + " is not a write port");
   }

   int portWidthBits = portWidths.elementAt(port);

   int result = tm.writePacket(b, off, len, port, portWidthBits);

   return(result);
}

}
