package demos.rmi;

import java.awt.*;
import java.applet.Applet;
import java.net.*;
import java.io.*;
import jdce.util.exception.*;
import java.rmi.*;
import java.rmi.server.*;
import java.awt.image.*;
import java.awt.*;

/**
 * This is just a simple server/client based proof-of-concept
 * implementation to make sure that the compensation classes have
 * all the required API in them. </b></i>
 *
 * Below is the Chat User program. The applet consists of three parts:
 * - a means of setting a name for the user
 * - a scrolling list of messages
 * - a means of sending a new message
 *
 * @version     Alpha 1.0 6th October 1997
 * @author      shrideep@npac.syr.edu
 * @author      Shrideep Pallickara
 * @author      NorthEast Parallel Architectures Center
 */

public class
RMIChatUser extends Applet implements  Runnable, Remote {
  Button    setIDButton;
  Button    setNameButton;
  Button    sayButton;
  Button    signOffButton;
  Button partyNameButton;
  Button test;
  Button clientHostButton;
  Button clientPortButton;  
  Button connectButton;
  Button joinButton;
  Button whisperButton;
  Button quitButton;
   
  TextField clientHostField;
  TextField clientPortField;
  TextField idField;
  TextField nameField;
  TextField typeField;
  TextField partyField;
  TextField testField;
  TextArea  messageArea;

  Choice clientList;
  Choice bahnList;
  
  public jdce.byteways.RMIDataBahn _chatBahn;
  public jdce.scheduler.RMISessionScheduler _chatSession;
  private Remote remoteObject;
  
  /** The name of this Client. */
  public String clientName;
  public int clientID;
    /**The name of the Party*/
  public String partyName;
  public int partyID;
  
  /** Indicates if the client is successfully connected to the server. */
  boolean connected = false;
  
  /* Default setup, will mostly be overriden by attributes. */
  int     width       = 250;
  int     height      = 250;
  String  hostname    = "dodo.npac.syr.edu";
  int port            = 9999;
  String  clientHostname;
  int clientPort;
  public int stressTest=1;
  
  private Thread running = null;
  private Thread controlThread;
  public  String clientNumber="1";
  
  String testerString="Check for transfer file mode";;
  static int messageNumber=0;
  
  private long startTime, stopTime;
  
  
  public synchronized void
    init() {
    Panel p;
    Font               lbl;
    GridBagLayout      g;
    GridBagConstraints c;
    
    /* Get needed attributes from the html page. */
    if (getParameter("width") != null) {
      width = Integer.parseInt(getParameter("width"));
    } else {
      width = 250;
    }
    
    if (getParameter("height") != null) {
      height = Integer.parseInt(getParameter("height"));
    } else {
      height = 250;
    }
    
    if (getParameter("serverHostname") != null) {
      hostname = getParameter("serverHostname");
    } else {
      hostname = "dodo.npac.syr.edu";
    }
    
    if (getParameter("serverPort") != null) {
      port = Integer.parseInt(getParameter("serverPort"));
    } else {
      port = 250;
    }
    
    
    lbl = new Font("Helvetica", Font.BOLD, 14);
    g   = new GridBagLayout();
    c   = new GridBagConstraints();
    c.fill      = GridBagConstraints.NONE;
    c.weightx   = 1.0;
    c.gridwidth = GridBagConstraints.REMAINDER;
    setLayout(g);
    
    p = new Panel();
    g.setConstraints(p, c);
    add(p);
    p.add(clientHostButton = new Button("ClientHost"));
    p.add(clientHostField  = new TextField(30)).setFont(lbl);
    
    p = new Panel();
    g.setConstraints(p, c);
    add(p);
    p.add(clientPortButton = new Button("ClientPort"));
    p.add(clientPortField  = new TextField(5)).setFont(lbl);
    p.add(setNameButton = new Button("Client Name"));
    setNameButton.disable();
    p.add(nameField     = new TextField(10)).setFont(lbl);
    
    p = new Panel();
    g.setConstraints(p, c);
    add(p);
    p.add(partyNameButton = new Button("Create Bahn"));
    partyNameButton.disable();
    p.add(partyField     = new TextField(10)).setFont(lbl);
    p.add(signOffButton = new Button("InformOthers"));
    signOffButton.disable();
    
    p = new Panel();
    g.setConstraints(p, c);
    add(p);
    p.add(quitButton = new Button("Quit"));
    quitButton.disable();
    p.add(connectButton = new Button("Connect"));
    p.add(joinButton = new Button("Join"));
    joinButton.disable();
    p.add(bahnList =new Choice());
    bahnList.addItem("Data Bahn List");
    
	
    p = new Panel();
    g.setConstraints(p, c);
    add(p);
    p.add(new Label("Messages: "));
    p.add(messageArea = new TextArea(6, 30));
    
    p = new Panel();
    g.setConstraints(p, c);
    add(p);
    p.add(sayButton = new Button("Say"));
    sayButton.disable();
    p.add(typeField = new TextField(20));
    p.add(test = new Button("StressTest"));
    test.disable();
    p.add(testField = new TextField(4)).setFont(lbl);
    
    p = new Panel();
    g.setConstraints(p, c);
    add(p);
    p.add(whisperButton = new Button("Whisper"));
    whisperButton.disable();
    p.add(clientList = new Choice());
    clientList.addItem("Clients On Bahn");
    signOffButton.disable();
    resize(width, height);
    show();
  }
  
  private boolean
    isConnected() {
    System.out.println("RMIChatUser: isConnected: " + connected);
    return(connected);
  }
  
  
  private boolean
    connect() {
    controlThread = new ClientControlThread(this);
    controlThread.start();
    return true;
  }
  
  private void binder() {
    try {
      remoteObject = 
	Naming.lookup("rmi://" + hostname +":" +port +"/Scheduler");
    } catch (java.lang.Exception exec) {
      System.out.println("Unable to lookup created Scheduler");
    }
    _chatSession = (jdce.scheduler.RMISessionScheduler) remoteObject;
  }
    
  public void createDataBahn() {
    try {
      _chatSession.createBahn(partyName, "Chat");
      System.out.println("New Party created");
    } catch (jdceRMIBahnException e) {
      System.out.println("Exception in creations" +e);
    } catch (Exception e) {
      e.printStackTrace();
    }   
  }
  
  public void getCoordinatorHandle() { 
    try {
      _chatBahn = _chatSession.getDataBahnHandle(partyName, "Chat");
    }  catch (jdceRMIBahnException e) {
      System.out.println("Exception in creations" +e);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  /*  Convert the users message to bytes and send it over the channel. */
  
  public boolean
    broadcast(String message) {
    jdce.util.message.jdceMessage _message = 
      new jdce.util.message.jdceMessage();
    _message.setContent((Object)typeField.getText());
    _message.setSender(clientName);
    _message.setBahnName(partyName+"Chat" +"Bahn");
    
    try {
      for (int i=0; i <stressTest; i++) {
	_message.setContent((Object)(typeField.getText()) );
	_chatBahn.broadcastMessage(_message);
      }
    } catch(jdceRMIBahnException e) {
      System.out.println("Excpetion in CLIENT Broadcast" + e);
    } catch (RemoteException e) {
      System.out.println("Remote Excpetion " + e);
    }
    
    return true;
  }
  
  
  public boolean dataReceive(String Message) {
    int     position;
    String message=  Message + "\n";
    position = messageArea.getText().length();
    messageArea.insertText(message, position);
    return true;
  }
  
  public boolean messageReceive(jdce.util.message.jdceMessage Message) {
    int     position;
    String message;
    synchronized(Message) {
      message=  (String)Message.getContent() + "\n";
    }
    position = messageArea.getText().length();
    messageArea.insertText(message, position);
    return true;
  }
  
  
  public void informOthers() {
    jdce.util.message.jdceMessage _mess = 
      new jdce.util.message.jdceMessage();
    _mess.setSender(clientName);
    _mess.setBahnName(partyName+"Chat"+"Bahn");

    try {
      for (int i=0; i < stressTest; i++) {
	_mess.setContent((Object)typeField.getText() + " Inform" +i);
	_chatBahn.inform(_mess);
      }
    } 
    catch (jdceRMIBahnException e) {}
    catch (RemoteException e) {
      System.out.println("Remote Excpetion " + e);
    }

  }
  
  
  public void whisperToClient() {
    if (clientList.getSelectedIndex()==0) {
      messageArea.setText("Please select a vaild Client");
      return true;
    }
    try {
      for (int i=0; i < stressTest; i++) {
	_chatBahn.whisper(clientName +" Whisper:" +typeField.getText(), 
			  clientList.getSelectedItem());
      }
      return true;
    } catch (jdceRMIBahnException e) {
      System.out.println(e.typeToString(e.getType()));
    } catch (jdceRMIClientException e) {
      System.out.println(e.typeToString(e.getType()));
    }
    catch (RemoteException e) {}   
  }
  
  
  private void
    disconnect() {
    try {
      _chatBahn.deregister(clientName);
      System.out.println("Deregistring Client "+ clientName);
    } catch (jdceRMIClientException e) {
      System.out.println("Error in deregistring");
    } catch (RemoteException e) {
      e.printStackTrace();
    }
  }
  
  public void listMembers() {
    int numberOfMembers=10;
    try {
      numberOfMembers=_chatBahn.numberOfMembers();
    } catch (RemoteException e) {
      System.out.println("Remote Excpetion " + e);
    }
    String[] temp = new String[numberOfMembers];    
    if (numberOfMembers !=0) {
      try {
	System.arraycopy(_chatBahn.getClientNames(),0, temp,0,numberOfMembers);
      } catch (RemoteException e) {
	System.out.println("Remote Excpetion " + e);
      }
      clientList.removeAll();
      clientList.addItem("Clients On Bahn");
      for (int i=0;i< numberOfMembers; i++) {
	System.out.println(temp[i]);
	clientList.addItem(temp[i]);
      }
      System.out.println("Listing complete");
    }
  }
  
  public void listDataBahns() {
    int numberOfMembers;
    String [] temp;
    try {
      numberOfMembers = _chatSession.listBahns("Chat").length;
      temp = new String[numberOfMembers];
      System.arraycopy(_chatSession.listBahns("Chat"), 0, temp, 0, numberOfMembers);
      bahnList.removeAll();
      bahnList.addItem("DataBahn List");
      for (int i=0;i< numberOfMembers; i++) {
	System.out.println(temp[i]);
	bahnList.addItem(temp[i]);
      }
    } catch (jdce.util.exception.jdceRMIBahnException e) {
      System.out.println("Error in listing");
    } catch (RemoteException e) {
      System.out.println("Remote Excpetion " + e);
    }
  }
  
  public void
    start() {
    System.out.println("RMIChatUser: start.");
    if (running == null) {
      running = new Thread(this);
      running.start();
    }
  }
  
  
  public void
    stop() {
    if (running != null) {
      running.stop();
      running = null;
    }
  }    
  
  
  public void
    run() {
  }
  
  
  public void
    destroy() {
    System.out.println("destroyed session");
  }
  
  public boolean
    action(Event event, Object obj) {
    System.out.println("RMIChatUser: action.");
    
    if ("InformOthers".equals(obj)) {
      informOthers();
      return true;
    } 
    if ("Say".equals(obj)) {
      return broadcast(clientName +":"+typeField.getText());
    }
    if ("StressTest".equals(obj)) {
      try {
	stressTest = Integer.parseInt(testField.getText());
      } catch (java.lang.NumberFormatException e) {
	stressTest=1;
      }	  
    } 
    if("Whisper".equals(obj)) {
      whisper();
      return true;
    }
    if("Quit".equals(obj)) {
      disconnect();
      System.exit(0);
    }
    if ("Connect".equals(obj)) {
      binder();
      listDataBahns();
      partyNameButton.enable();
      joinButton.enable();	  
      return true;
    }
    if("Join".equals(obj)) {
      if (bahnList.getSelectedIndex()==0) {
	messageArea.setText("Please select a valid Bahn Name");
	return true;
      }
      partyName = bahnList.getSelectedItem();
      partyName = partyName.substring(0, partyName.length() -4);
      System.out.println(partyName);
      getDataBahnHandle();
      listMembers();
      setNameButton.enable();
      return true;
    }
    
    if ("Create Bahn".equals(obj)) {
      partyName=partyField.getText();
      createDataBahn();
      getDataBahnHandle();
      setNameButton.enable();
      listMembers();
      try {
	System.out.println("App Server Name" + _chatBahn.getApplicationServerName());}
      catch (RemoteException e) {
	System.out.println("Remote Excpetion " + e);
      }
      System.out.println("Received Party Handle");
      return true;
    }
    
    if ("ClientHost".equals(obj)) {
      if (clientHostField.getText()!=null) {
	clientHostname=clientHostField.getText();
      }
      return true;
    }
    
    if ("ClientPort".equals(obj)) {
      if (clientPortField.getText()!=null) {
	clientPort=Integer.parseInt(clientPortField.getText());
      }
      return true;
    }
    
    if ("Client Name".equals(obj)) {
      clientName = nameField.getText();
      if (clientNumber == null || clientName==null || partyName==null) {
	nameField.setText("Need to give a name + ID before \"Set Name\"");
	return(true);
      } else {
	connected = connect();
	signOffButton.enable();
	sayButton.enable();
	test.enable();
	whisperButton.enable();
	quitButton.enable();
      }
      return(true);
    } 
    return(false);
  }
}

/*This thread is responsible for the callbacks from the Server side */

class ClientControlThread extends Thread {
  private RMIChatUser thisClient;
  private jdce.byteways.RMIDataBahn _chatBahn;
  private jdce.scheduler.RMISessionScheduler _chatSession;
  private jdce.client.RMIClientProxy control;
  String identity;

  ClientControlThread(RMIChatUser client) { 
    thisClient = client;
  }

  public void run()  {  
    try
      { 
	control = new RMIClientControlImpl(thisClient);
	identity= "rmi://" + thisClient.clientHostname +":"+
	  thisClient.clientPort +"/"+thisClient.clientName;
	Naming.rebind(identity, control);
	System.out.println("ClientControl Export done.");
      }
    catch (RemoteException re) {
      System.out.println("No luck dude" + re);
    }
    catch (MalformedURLException e) {
      System.out.println("MalformedURLException CoordinatorImpl.main: " + e);
    }
    
    try {
      thisClient._chatBahn.register(thisClient.clientName,
				      control);
    } catch (jdceRMIBahnException e) {
      System.out.println(e.typeToString(e.getType()));
      System.out.println("Registration Failed");
    } catch (jdceRMIClientException e){}
    catch (RemoteException e) {System.out.println("OPOOOOuch!!");}
    
    System.out.println("Control: Waiting for requests");
  }
}