package demos.chat;

import java.awt.*;
import java.applet.Applet;
import java.net.*;
import java.io.*;
import org.omg.CosNaming.*;
import jdce.util.exception.*;
import org.omg.CORBA.UserException;

/**
 * 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.
 *
 * 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
ChatUser extends Applet implements  Runnable {
  Button    setIDButton;
  Button    setNameButton;
  Button    sayButton;
  Button    signOffButton;
  Button partyNameButton;
  Button test;
  Button connectButton;
  Button joinButton;
  Button whisperButton;
  Button quitButton;
  
  TextField idField;
  TextField nameField;
  TextField typeField;
  TextField partyField;
  TextField testField;
  TextArea  messageArea;
  
  Choice clientList;
  Choice bahnList;
  public jdce.byteways.dataBahn _chatBahn;
  public jdce.scheduler.sessionScheduler _chatSession;
  
  /** The name of this Client. */
  public String clientName;
  public int clientID;

  /**The name of the Party*/
  public String partyName;
  public int partyID;
  public int stressTest=1;
  
  /** 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;
  
  private Thread running = null;
  private Thread controlThread;
  public  String clientNumber="1";
  
  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;
    }
    

    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(test = new Button("StressTest"));
    test.disable();
    p.add(testField = new TextField(4)).setFont(lbl);
    testField.setText("1");
    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"));
    p.add(partyField     = new TextField(20)).setFont(lbl);
    p.add(quitButton = new Button("Quit"));
    
    p = new Panel();
    g.setConstraints(p, c);
    add(p);
    p.add(connectButton = new Button("Connect"));
    p.add(joinButton = new Button("Join"));
    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(signOffButton = new Button("InformOthers"));
    
    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("ChatUser: isConnected: " + connected);
    return(connected);
  }
  
  
  private boolean
    connect() {
    controlThread = new ClientControlThread(this);
    controlThread.start();
    return true;
  }
  
  private void binder() {
    try {
      /* Initialize the ORB. */
      org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(this, null);
      
      /* Get a reference to the Naming Service */
      org.omg.CORBA.Object nameServiceObj = 
	orb.resolve_initial_references("NameService");
      if (nameServiceObj == null) {
	System.out.println("Name Service Object = null");
	return;
      }
      
      org.omg.CosNaming.NamingContext nameService =
	org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
      if (nameService == null) {
	System.out.println("nameService = null");
	return;
      }
      
      NameComponent[] collabName = 
      { new NameComponent("Collaboration", "Scheduler")};	
      _chatSession= 
	jdce.scheduler.sessionSchedulerHelper.narrow(nameService.resolve(collabName));
    } catch(Exception e) {
      System.out.println("Exception: " + e);
    }
  }
  
  public void createDataBahn() {
    try {
      _chatSession.createBahn(partyName, "Chat");
      System.out.println("New Party created");
    } catch (jdceBahnException e) {
      System.out.println("Exception in creations" +e);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void getDataBahnHandle() {
    try {
      /* Initialize the ORB. */
      org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(this, null);
      
      /* Get a reference to the Naming Service */
      org.omg.CORBA.Object nameServiceObj = 
	orb.resolve_initial_references("NameService");      
      if (nameServiceObj == null) {
	System.out.println("Name Service Object = null");
	return;
      }
      
      org.omg.CosNaming.NamingContext nameService =
	org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
      if (nameService == null) {
	System.out.println("nameService = null");
	return;
      }
      
      NameComponent[] collabName = 
      { new NameComponent("Collaboration", partyName+"Chat"+"Coordinator")};
      
      _chatBahn= 
	jdce.byteways.dataBahnHelper.narrow(nameService.resolve(collabName));
    } catch(Exception e) {
      System.out.println("Exception: " + e);
    }
  }
  
  /*  Convert the users message to bytes and send it over the DataBahn. */  
  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(jdceBahnException e) {
      System.out.println("Excpetion in CLIENT Broadcast" + 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 (jdceBahnException e) {}    
  }


  public void whisperToClient() {
    if (clientList.getSelectedIndex()==0) {
      messageArea.setText("Please select a vaild Client");
      return true;
    }
    try {
      _chatBahn.whisper(clientName +" Whisper:" +typeField.getText(), 
			clientList.getSelectedItem());
      return true;
    } catch (jdceBahnException e) {
      System.out.println("Success in trial attempt");
    } catch (jdceClientException e) {}
  }
  
  private void
    disconnect() {
    System.out.println("Deregistring Client "+ clientName);
    try {
      _chatBahn.deregister(clientName);
    } catch (jdceClientException e) {
      System.out.println("Error in deregistring");
    }
  }
  
  public void listMembers() {
    int numberOfMembers=_chatBahn.numberOfMembers();
    String[] temp = new String[numberOfMembers];
    if (numberOfMembers!=0)
      System.arraycopy(_chatBahn.getClientNames(),0, temp,0,numberOfMembers);
    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.jdceBahnException e) {
      System.out.println("Error in listing");
    }
  }
  
  public void
    start() {
    System.out.println("ChatUser: 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("ChatUser: 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;
      }
      return true;      
    } 
    
    if ("SetID".equals(obj)) {
      clientNumber = idField.getText(); 
    }
    
    if ("Connect".equals(obj)) {
      binder();
      listDataBahns();
      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();
      System.out.println("App Server Name" +_chatBahn.getApplicationServerName());
      setNameButton.enable();
      return true;
    }
    
    if("Whisper".equals(obj)) {
      whisperToClient();
      return true;
    }
    
    if("Quit".equals(obj)) {
      disconnect();
      System.exit(0);
    }
    
    if ("Client Name".equals(obj)) {
      clientName = nameField.getText();
      if (clientNumber == null || clientName==null || partyName==null) {
	nameField.setText("Need to give a name \"Client Name\"");
	return(true);
      } else {
	connected = connect();
	signOffButton.enable();
	sayButton.enable();
	test.enable();
	whisperButton.enable();
      }
      return(true);
    } 
    return(false);
  }
}

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

class ClientControlThread extends Thread {
  private ChatUser thisClient;
  private jdce.byteways.dataBahn _chatBahn;
  private jdce.scheduler.sessionScheduler _chatSession;
  
  ClientControlThread(ChatUser client) { 
    thisClient = client;
  }
  
  public void run() {  
    try
      { /* Initialize the ORB. */
	org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(thisClient);
	/* Create the ClientControl object. */
	ClientControlImpl control = new ClientControlImpl(thisClient);
	orb.connect(control);
	
	try {
	  /* Get a reference to the Naming Service */
	  org.omg.CORBA.Object nameServiceObj = 
	    orb.resolve_initial_references("NameService");
	  if (nameServiceObj == null) {
	    System.out.println("Name Service Object = null");
	    return;
	  }
	  
	  org.omg.CosNaming.NamingContext nameService =
	    org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
	  if (nameService == null) {
	    System.out.println("nameService = null");
	    return;
	  }
	  
	  NameComponent[] collabName = 
	  { new NameComponent("Collaboration", 
			      thisClient.partyName+"Chat"+"Coordinator")};	  	  
          _chatBahn= jdce.byteways.dataBahnHelper.narrow(nameService.resolve(collabName));

	} catch(Exception e) {
	  System.out.println("Exception: " + e);
	}
	
	try {
	  thisClient._chatBahn.register(thisClient.clientName,
					  (jdce.client.clientProxy)control);
	} catch (jdceBahnException e) {
	  System.out.println(e.typeToString(e.getType()));
	  System.out.println("Registration Failed");
	} catch (jdceClientException e){}
	
	System.out.println("Control: Waiting for requests");
	try {
	  Thread.currentThread().join();
	}catch(InterruptedException e) {
	  System.out.println("error" + e);
	}
      }
    catch(org.omg.CORBA.SystemException e) {
      System.err.println(e);
    }
  }
}