package nxm.ucl.lib;//remove for non-nxm use

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;

/** Web to Gui Connector
 *  @author "Mike Warnock - Comp. Sci. Trainee"
 *  @version "1.0"
 *  Seriously modified by MSZ - Sr. Comp Sci
 */
public class JavaRMIFCon
{
  /** SET packet message function - for results access */
  public static final byte SET=101;
  /** GET packet message function - for results access */
  public static final byte GET=102;
  /** RET packet message function - for results access */
  public static final byte RET=103;
  /** ACK packet message function - for results access */
  public static final byte ACK=104;
  /** OPEN packet message function - open channel */
  public static final byte OPEN=105;
  /** CLOSE packet message function - close channel */
  public static final byte CLOSE=106;
  /** SEND packet message function - message access */
  public static final byte SEND=107;
  /** RECV packet message function - message access */
  public static final byte RECV=108;
  /** PING packet message function - keep alive checks */
  public static final byte PING=109;
  /** PONG packet message function - keep alive checks */
  public static final byte PONG=110;
  /** DHDR packet message function - file data access */
  public static final byte DHDR=111;
  /** DBUF packet message function - file data access */
  public static final byte DBUF=112;
  /** ADDR packet message function - address */
  public static final byte ADDR=113;
  /** MODIFY packet message function - modify */
  public static final byte MODIFY=114;
  /** OPENED packet message function - response to OPEN */
  public static final byte OPENED=115;
  /** CLOSED packet message function - response to CLOSE */
  public static final byte CLOSED=116;
  /** DBUFC packet message function - file data access */
  public static final byte DBUFC=117;
  /** DBUFD packet message function - file data access */
  public static final byte DBUFD=118;
  /** GETPROP packet message function - published keyname access */
  public static final byte GETPROP=121;
  /** RETPROP packet message function - published keyname access */
  public static final byte RETPROP=122;
  /** PKTSEND packet message function - published low-level RDP hooks */
  public static final byte PKTSEND=125;
  /** PKTSYNC packet message function - published low-level RDP hooks */
  public static final byte PKTSYNC=126;
  /** DROPPED packet message function - dropped remote state */
  public static final byte DROPPED=0;
  /** RECEIPT packet message function - dropped remote state */
  public static final byte RECEIPT=123;

  /** FUNC packet header byte offsets */
  public static final byte FUNC=0;
  /** FLAG packet header byte offsets */
  public static final byte FLAG=1;
  /** INFO packet header byte offsets */
  public static final byte INFO=2;
  /** REP packet header byte offsets */
  public static final byte REP=3;
  /** SEQ packet header byte offsets */
  public static final byte SEQ=4;
  /** TRY packet header byte offsets */
  public static final byte TRY=5;
  /** RPT packet header byte offsets */
  public static final byte RPT=6;
  /** ADJ packet header byte offsets */
  public static final byte ADJ=7;
  /** DATA packet header byte offsets */
  public static final byte DATA=8;

  /** Maximum number of retries */
  public int MaxRetries = 2;
  /** Socket timeout in milliseconds */
  public int socktimeout = 500; //should be local anyway

  private DatagramPacket dpGui;
  private String localhost;
  private byte buf[];

  /** Main driver method for running JavaRMIFCon as an instance
   *  @param args the commandline arguments
   */
  public static void main(String[] args)
  {
    JavaRMIFCon wg = new JavaRMIFCon("e2w11");
    String strSend = "MSGNAME=MJWJRCOMPSCI,FIELD1=MIKE,FIELD2=WORKS,MSGID=MJ,FROM=MIKE,MSGID=MJW,ID=ME";
    wg.sendCommand(strSend,"localhost",7001,"ME");
  }

  /** Traces any given message as a string
   *  @param strInMsg the message as a string to be traced
   */
  public void TraceMessage(String strInMsg)
  {
    try {
      System.out.println(strInMsg);
    } catch (Exception e) {
      System.err.println("JavaRMIFCon()::TraceMessage - Error:"+ e);
    }
    return;
  }

  /** JavaRMIFCon Constructor
   *  @param localhost the localhost url
   */
  public JavaRMIFCon(String localhost) {
    this.localhost=localhost;
    return;
  }

  /** Sends a command over a DatagramSocket.
   *  @param strCmd Command to be sent
   *  @param m_host Message receiver host
   *  @param m_port Message receiver port
   *  @param infid  From ID
   *  @return Status code 0
   */
  public int sendCommand(String strCmd,String m_host,int m_port,String infid)
  {
    DatagramSocket sock;
    try {
        sock = new DatagramSocket();
        sock.setSoTimeout(socktimeout);
        String fid = "";
        if (infid.length()>0) { fid="FROMID="+infid+","; }
        String strSend = "{" + fid + strCmd + ",REPLYHP="+localhost+":"+sock.getLocalPort()+"}";
        TraceMessage("JavaRMIFCon::sendCommand - Sending "+ strSend + " to "+m_host+"/"+m_port);
        byte[] bySend = strSend.getBytes();
        int nSendLen = bySend.length + DATA;
        buf = new byte[nSendLen];
        dpGui = new DatagramPacket(buf,nSendLen);
        for( int i=0; i<nSendLen; i++) buf[i] = 0;
        buf[FUNC] = SET;
        buf[FLAG] = 0;
        buf[INFO] =1;
        buf[REP ] = 5;
        buf[SEQ] = 5;
        System.arraycopy (bySend,0, buf,DATA,nSendLen-DATA);
        dpGui.setPort(m_port);
        dpGui.setAddress(InetAddress.getByName(m_host));
        sock.send(dpGui);
        int nRecvLen = 0;
        int nRetries = 0;
        try {
           byte[] ibuf = new byte[256];
           dpGui = new DatagramPacket(ibuf,256);
           dpGui.setLength(256);
           while (nRecvLen == 0 && nRetries < MaxRetries) {
             if (nRetries>0) TraceMessage("JavaRMIFCon::sendCommand - Waiting for RECEIPT");
             try {
               sock.receive(dpGui);
             } catch (SocketTimeoutException ste) { nRetries++; continue; }
             nRecvLen =  dpGui.getLength();
             nRetries++;
           }
        } catch(SocketException e) {TraceMessage("JavaRMIFCon::sendCommand - Receive recv err" +e);}
        catch(Exception e) {TraceMessage("JavaRMIFCon::sendCommand - Receive recv err" + e);}

        if (nRecvLen > 0) {
           byte[] ibuf = dpGui.getData();
           String strRecv = new String(ibuf,DATA,dpGui.getLength());
//           TraceMessage("JavaRMIFCon::sendCommand - Received " +nRecvLen + " bytes "+ ibuf[FUNC] + "-"+ibuf[SEQ] + " " + strRecv);
        }

        try {
          sock.close();
        } catch(Exception e) {}
    } catch (Exception e) {
      TraceMessage("JavaRMIFCon::sendCommand - Error while processing "+ m_host + ":" + m_port +" :"+ e);
    }
//    TraceMessage("JavaRMIFCon::sendCommand - Done");
    return 0;
  }
}