/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author nathan
 * 
 */
import java.io.*;
import java.net.*;
import java.util.*;

public class IgorTalkServer implements Runnable {
  final static int BUF_SIZE = 2048;
  static final byte[] EOL = {(byte) '\r', (byte) '\n'};

  /* buffer to use for requests */
  byte[] buf;
  protected final int PORT = 1491; //The port number the server binds to
  /* timeout on client connections */
  static int timeout = 0;
  static Socket s = null;
  static PrintStream ps = null;
  
  // The defualt constructor
  public IgorTalkServer() {
    buf = new byte[BUF_SIZE];
    p("Starting IgorTalk Server ...");
  }

  /* print to stdout */
  protected static void p(String s) {
    System.out.println(s);
  }
  
  // method to spectradata to igor
  public String copySpectraDataToIgor(SpectraData[] sda) {
    String waveNames = ""; // stores the names of the waves that was copied to igor
    
    for (SpectraData spectraData : sda) {
      if(!spectraData.is3D()) {
        String[] igorData = SpectraDataUtil.getDataForIgor(spectraData);
        try {
          sendCommand(igorData[0]); // send x wave
          Thread.sleep(200);
          sendCommand(igorData[1]); // send y wave
          Thread.sleep(200);
          String name = spectraData.getName();
          waveNames += ";" + name + "_X;" + name + "_Y";
        } catch (InterruptedException ioe) { }
      }
      else { // copy 3D data
        String[] igorData = SpectraDataUtil.get2DDataForIgor(spectraData);
        try {
          sendCommand(igorData[0]); // send x wave
          Thread.sleep(200);
          sendCommand(igorData[1]); // send y wave
          Thread.sleep(200);
          sendCommand(igorData[2]); // send z wave
          Thread.sleep(200); //wait a little bit for data transfer to finish 
          String name = spectraData.getName();
          waveNames += ";" + name + "_X;" + name + "_Y;" + name + "_Z";
        } catch (InterruptedException ioe) { }
      }
    }
    
    return waveNames; 
  }
  
  // function to plot a 2D Spectra
  public void plotSpectraDataUsingIgor(SpectraData[] sda) {
    String waveNames = copySpectraDataToIgor(sda);
    String command = "PLOT_WAVE" + waveNames;
    sendCommand(command);
  }
  
  // plot to plot a single waterfall plot
  public void plotWaterfallUsingIgor(SpectraData spectraData) {
    // copy the data fist
    String[] igorData = SpectraDataUtil.get2DDataForIgor(spectraData);
    String name = spectraData.getName();
    try {
      sendCommand(igorData[0]); // send x wave
      Thread.sleep(200);
      sendCommand(igorData[1]); // send y wave
      Thread.sleep(200);
      sendCommand(igorData[2]); // send z wave
      Thread.sleep(200); //wait a little bit for data transfer to finish 
    } catch (InterruptedException ioe) { }
    
    // now send the plot command
    String command = "Execute; NewWaterfall '"+ name +"_Z' vs {'" + 
            name + "_X','"+ name + "_Y'}";
    sendCommand(command);
  }
  
  // Method to print the header
  private void openSocket() {
    try {
      ServerSocket ss = new ServerSocket(PORT);
      s = ss.accept();
      notify();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
  }
  // Method to close the socket connection
  public void closeSocket() {
    try {
      s.close();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    } catch (NullPointerException npe) {
      System.out.println("Sockiet must not have been initialized");
    }
  }
  
  // Method to printout to the 
  public void sendCommand(String command) {
    ps.print(command);
  }
  
  public synchronized void run() {
    openSocket(); // open the socet connection

    try {
      handleClient();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void handleClient() throws IOException {
    InputStream is = new BufferedInputStream(s.getInputStream());
    ps = new PrintStream(s.getOutputStream());
    /* we will only block in read for this many milliseconds
     * before we fail with java.io.InterruptedIOException,
     * at which point we will abandon the connection.
     */
    s.setSoTimeout(IgorTalkServer.timeout);
    s.setTcpNoDelay(true);

    /* zero out the buffer from last time */
    for (int i = 0; i < BUF_SIZE; i++) {
      buf[i] = 0;
    }

    // read any information
    try {
      /* We only support HTTP GET/HEAD, and don't
       * support any fancy HTTP options,
       * so we're only interested really in
       * the first line.
       */
      int nread = 0, r = 0;

      outerloop:
      while (nread < BUF_SIZE) {
        r = is.read(buf, nread, BUF_SIZE - nread);
        if (r == -1) {
          /* EOF */
          return;
        }
        int i = nread;
        nread += r;
        for (; i < nread; i++) {
          if (buf[i] == (byte) '\n' || buf[i] == (byte) '\r') {
            /* read one line */
            break outerloop;
          }
        }
      }

      

      printHeaders(ps);
    } finally {
      //s.close();
    }
  }

  public void printHeaders(PrintStream ps) throws IOException {
    p("Connection From " + s.getInetAddress().getHostAddress());

    //ps.write(EOL);
    ps.print("Server: InstruView IgorTalk");
    //ps.write(EOL);
    ps.print("Date: " + (new Date()));
    //ps.write(EOL);
    ps.flush();
  }
}
