import context.arch.BaseObject;
import context.arch.comm.DataObject;
import context.arch.widget.WPersonPresence;
import context.arch.handler.Handler;
import context.arch.InvalidMethodException;
import context.arch.MethodException;
import context.arch.subscriber.Subscriber;
import context.arch.subscriber.Callbacks;
import context.arch.comm.language.DecodeException;
import context.arch.comm.language.InvalidDecoderException;
import context.arch.comm.language.EncodeException;
import context.arch.comm.language.InvalidEncoderException;
import context.arch.comm.protocol.ProtocolException;
import context.arch.comm.protocol.InvalidProtocolException;
import context.arch.interpreter.IIButton2Name;
import context.arch.util.Error;
import context.arch.storage.AttributeFunctions;
import context.arch.storage.Attributes;
import context.arch.storage.Attribute;
import context.arch.storage.AttributeNameValues;
import context.arch.storage.AttributeNameValue;
import context.arch.storage.Retrieval;
import context.arch.storage.Conditions;
import context.arch.storage.StorageObject;
import context.arch.storage.Storage;
import context.arch.storage.RetrievalResults;

import java.util.Vector;
import java.util.Hashtable;

/**
 * This class is a test application that uses the WPersonPresence.  It
 * contains code that tests polling and conditionally subscribing to the widget and 
 * retrieving history data from the widget.
 *
 * @see context.arch.handler.Handler 
 * @see context.arch.widget.WPersonPresence
 */
public class TestApp implements Handler {

  /** 
   * Default port to start the BaseObject on is 5555
   */
  public static final int DEFAULT_PORT = 5555;

  /**
   * Subscription ID for WPersonPresence UPDATE callback
   */
  public static final String SUBSCRIBER_ID = "PersonPresenceApp";

  private int numHandles = 0;
  private int port;  
  private String userid;

  /**
   * Constructor that creates an instance of BaseObject at the DEFAULT_PORT.  It
   * subscribes to the WPersonPresence and prints out callback info and polls
   * the widget and prints out the results
   *
   * @param location Location of the WPersonPresence
   * @param ppwHost Hostname the widget is running on
   * @param ppwPort Port the widget is running on
   * @param iib2nHost Hostname the interpreter is running on
   * @param iib2nPort Port the interpreter is running on
   * @see context.arch.BaseObject
   * @see context.arch.BaseObject#subscribeTo(context.arch.handler.Handler, int, java.lang.String,
		java.lang.String, int, java.lang.String, java.lang.String, java.lang.String)
   * @see context.arch.widget.WPersonPresence
   */
  public TestApp(String location, String ppwHost, int ppwPort, String iib2nHost, int iib2nPort) {
    this(location, DEFAULT_PORT, ppwHost, ppwPort, iib2nHost, iib2nPort);
  }

  /**
   * Constructor that creates an instance of BaseObject at the given port.  It
   * subscribes to the WPersonPresence and prints out callback info and polls
   * the widget and prints out the results.
   *
   * @param localport Port the app is running on
   * @param ppwHost Hostname the widget is running on
   * @param ppwPort Port the widget is running on
   * @param iib2nHost Hostname the interpreter is running on
   * @param iib2nPort Port the interpreter is running on
   * @see context.arch.BaseObject
   * @see context.arch.BaseObject#subscribeTo(context.arch.handler.Handler, int, java.lang.String,
		java.lang.String, int, java.lang.String, java.lang.String, java.lang.String)
   * @see context.arch.widget.WPersonPresence
   */
  public TestApp(String location, int localport, String ppwHost, int ppwPort, String iib2nHost, int iib2nPort) {
    BaseObject server = new BaseObject (localport);
    port = localport;
    String widgetId = WPersonPresence.CLASSNAME+"_"+location;
    
    // query the widget's version with wrong id
    System.out.println("**********************************************");
    DataObject version = server.getVersion(ppwHost, ppwPort, widgetId+"blah");
    String versionError = new Error(version).getError();
    String versionNumber = null;
    if (versionError.equals(Error.NO_ERROR)) {
      versionNumber = (String)version.getDataObject(WPersonPresence.VERSION).getValue().firstElement();
    }
    System.out.println("Version with invalid id: "+version+"\n");
    System.out.println("error = "+versionError+", version number = "+versionNumber);
    System.out.println("**********************************************\n");

    // query the widget's version with correct id
    DataObject version2 = server.getVersion(ppwHost, ppwPort, widgetId);
    String versionError2 = new Error(version2).getError();
    String versionNumber2 = null;
    if (versionError2.equals(Error.NO_ERROR)) {
      versionNumber2 = (String)version2.getDataObject(WPersonPresence.VERSION).getValue().firstElement();
    }
    System.out.println("Version with valid id: "+version2+"\n");
    System.out.println("error = "+versionError2+", version number = "+versionNumber2);
    System.out.println("**********************************************\n");

    // query the widget's attributes with wrong id
    DataObject attributes = server.getWidgetAttributes(ppwHost, ppwPort, widgetId+"blah");
    String attributesError = new Error(attributes).getError();
    Attributes atts = null;
    if (attributesError.equals(Error.NO_ERROR)) {
      atts = new Attributes(attributes);
    }
    System.out.println("Attributes with invalid id: "+attributes+"\n");
    System.out.println("error = "+attributesError+", attributes = "+atts);
    System.out.println("**********************************************\n");

    // query the widget's attributes with correct id
    DataObject attributes2 = server.getWidgetAttributes(ppwHost, ppwPort, widgetId);
    String attributesError2 = new Error(attributes2).getError();
    Attributes atts2 = null;
    if (attributesError2.equals(Error.NO_ERROR)) {
      atts2 = new Attributes(attributes2);
    }
    System.out.println("Attributes with valid id: "+attributes2+"\n");
    System.out.println("error = "+attributesError2+", attributes = "+atts2);
    System.out.println("**********************************************\n");

    // query the widget's callbacks with correct id
    DataObject callbacks = server.getWidgetCallbacks(ppwHost, ppwPort, widgetId);
    String callbacksError = new Error(callbacks).getError();
    Callbacks calls = null;
    if (callbacksError.equals(Error.NO_ERROR)) {
      calls = new Callbacks(callbacks);
    }
    System.out.println("Callbacks with valid id: "+callbacks+"\n");
    System.out.println("error = "+callbacksError+", callbacks = "+calls);
    System.out.println("**********************************************\n");

    // query the widget with valid attributes before it has any data
    Attributes prePollAtts = new Attributes();
    prePollAtts.addAttribute(WPersonPresence.USERID);    
    DataObject poll = server.pollWidget(ppwHost, ppwPort, widgetId, prePollAtts);
    String pollError = new Error(poll).getError();
    AttributeNameValues pollAtts = null;
    if (pollError.equals(Error.NO_ERROR)) {
      pollAtts = new AttributeNameValues(poll);
    }
    System.out.println("Poll before any data: "+poll+"\n");
    System.out.println("error = "+pollError+", attributes = "+pollAtts);
    System.out.println("**********************************************\n");

    // retrieve all data from the widget before it has any data
    DataObject retrieve = server.retrieveDataFrom(ppwHost, ppwPort, widgetId);
    String retrieveError = new Error(retrieve).getError();

    RetrievalResults retrieveData = null;
    if (retrieveError.equals(Error.NO_ERROR)) {
      retrieveData = new RetrievalResults(retrieve);
    }
    System.out.println("Retrieval before any data: "+retrieve+"\n");
    System.out.println("error = "+retrieveError+", retrieval = "+retrieveData);
    System.out.println("**********************************************\n");
    
    // update and query the widget with valid attributes before it has any data
    Attributes preUpdateAtts = new Attributes();
    preUpdateAtts.addAttribute(WPersonPresence.USERID);    
    DataObject updatePoll = server.updateAndPollWidget(ppwHost, ppwPort, widgetId, preUpdateAtts);
    String updatePollError = new Error(updatePoll).getError();
    AttributeNameValues updatePollAtts = null;
    if (updatePollError.equals(Error.NO_ERROR)) {
      updatePollAtts = new AttributeNameValues(updatePoll);
    }
    System.out.println("Update&Poll before any data: "+updatePoll+"\n");
    System.out.println("error = "+updatePollError+", attributes = "+updatePollAtts);
    System.out.println("**********************************************\n");


    // subscribe to widget with invalid callback
    Error done = server.subscribeTo(this, port, SUBSCRIBER_ID, ppwHost, ppwPort, widgetId,
                 "blah", "presenceUpdate");
    System.out.println("Subscription with invalid callback: "+done.getError());
    System.out.println("**********************************************\n");
    
    // subscribe to widget with invalid attributes
    Attributes subscribeAtts = new Attributes();
    subscribeAtts.addAttribute(WPersonPresence.USERID);
    subscribeAtts.addAttribute("blah");
    Error done2 = server.subscribeTo(this, port, SUBSCRIBER_ID, ppwHost, ppwPort, widgetId,
                 WPersonPresence.UPDATE, "presenceUpdate", subscribeAtts);
    System.out.println("Subscription with invalid attributes: "+done2.getError());
    System.out.println("**********************************************\n");

    // subscribe to widget with invalid conditions
    Conditions subscribeConds = new Conditions();
    subscribeConds.addCondition("blah",Storage.EQUAL,"blah");
    Error done3 = server.subscribeTo(this, port, SUBSCRIBER_ID, ppwHost, ppwPort, widgetId,
                 WPersonPresence.UPDATE, "presenceUpdate", subscribeConds);
    System.out.println("Subscription with invalid conditions: "+done3.getError());
    System.out.println("**********************************************\n");

    // subscribe to widget with no conditions or attributes with invalid callback tag
    Error done4 = server.subscribeTo(this, port, SUBSCRIBER_ID, ppwHost, ppwPort, widgetId,
                 WPersonPresence.UPDATE, "blah");
    System.out.println("Subscription valid with no attributes/conditions but invalid callback tag: "+done4.getError());
    System.out.println("**********************************************\n");

    System.out.println("Dock with the PersonPresence widget once please");
    
    while (numHandles < 1) {
      try {
        Thread.sleep(500);
      } catch (InterruptedException ite) {
          System.out.println("Interrupted thread: "+ite);
      }
    }

    // query the widget with invalid attributes after it has data
    System.out.println("**********************************************");
    Attributes returnPollAtts2 = new Attributes();
    returnPollAtts2.addAttribute(WPersonPresence.USERID);
    returnPollAtts2.addAttribute("blah");
    DataObject poll2 = server.pollWidget(ppwHost, ppwPort, widgetId, returnPollAtts2);
    String pollError2 = new Error(poll2).getError();
    AttributeNameValues pollAtts2 = null;
    if (pollError2.equals(Error.NO_ERROR)) {
      pollAtts2 = new AttributeNameValues(poll2);
    }
    System.out.println("Poll with invalid attributes: "+poll2+"\n");
    System.out.println("error = "+pollError2+", attributes = "+pollAtts2);
    System.out.println("**********************************************\n");

    // update and query the widget with invalid attributes after it has data
    Attributes returnUpdatePollAtts2 = new Attributes();
    returnUpdatePollAtts2.addAttribute(WPersonPresence.USERID);
    returnUpdatePollAtts2.addAttribute("blah");
    DataObject updatePoll2 = server.updateAndPollWidget(ppwHost, ppwPort, widgetId, returnUpdatePollAtts2);
    String updatePollError2 = new Error(updatePoll2).getError();
    AttributeNameValues updatePollAtts2 = null;
    if (updatePollError2.equals(Error.NO_ERROR)) {
      updatePollAtts2 = new AttributeNameValues(updatePoll2);
    }
    System.out.println("Update&Poll with invalid attributes: "+updatePoll2+"\n");
    System.out.println("error = "+updatePollError2+", attributes = "+updatePollAtts2);
    System.out.println("**********************************************\n");

    // query the widget with valid attributes after it has data
    Attributes returnPollAtts3 = new Attributes();
    returnPollAtts3.addAttribute(WPersonPresence.USERID);
    returnPollAtts3.addAttribute(WPersonPresence.TIMESTAMP);
    DataObject poll3 = server.pollWidget(ppwHost, ppwPort, widgetId, returnPollAtts3);
    String pollError3 = new Error(poll3).getError();
    AttributeNameValues pollAtts3 = null;
    if ((pollError3.equals(Error.NO_ERROR)) || (pollError3.equals(Error.INCOMPLETE_DATA_ERROR))) {
      pollAtts3 = new AttributeNameValues(poll3);
    }
    System.out.println("Poll with valid attributes: "+poll3+"\n");
    System.out.println("error = "+pollError3+", attributes = "+pollAtts3);
    System.out.println("**********************************************\n");

    // update and query the widget with valid attributes after it has data
    Attributes returnUpdatePollAtts3 = new Attributes();
    returnUpdatePollAtts3.addAttribute(WPersonPresence.USERID);
    returnUpdatePollAtts3.addAttribute(WPersonPresence.TIMESTAMP);
    DataObject updatePoll3 = server.updateAndPollWidget(ppwHost, ppwPort, widgetId, returnUpdatePollAtts3);
    String updatePollError3 = new Error(updatePoll3).getError();
    AttributeNameValues updatePollAtts3 = null;
    if (updatePollError3.equals(Error.NO_ERROR)) {
      updatePollAtts3 = new AttributeNameValues(updatePoll3);
    }
    System.out.println("Update&Poll with valid attributes: "+updatePoll3+"\n");
    System.out.println("error = "+updatePollError3+", attributes = "+updatePollAtts3);
    System.out.println("**********************************************\n");

    // query the widget with all attributes after it has data
    Attributes prePollAtts4 = new Attributes();
    prePollAtts4.addAttribute(Attributes.ALL);
    DataObject poll4 = server.pollWidget(ppwHost, ppwPort, widgetId, prePollAtts4);
    String pollError4 = new Error(poll4).getError();
    AttributeNameValues pollAtts4 = null;
    if (pollError4.equals(Error.NO_ERROR)) {
      pollAtts4 = new AttributeNameValues(poll4);
    }
    System.out.println("Poll all attributes: "+poll4+"\n");
    System.out.println("error = "+pollError4+", attributes = "+pollAtts4);
    System.out.println("**********************************************\n");

    // update and query the widget with all attributes after it has any data
    Attributes preUpdateAtts4 = new Attributes();
    preUpdateAtts4.addAttribute(Attributes.ALL);
    DataObject updatePoll4 = server.updateAndPollWidget(ppwHost, ppwPort, widgetId, preUpdateAtts4);
    String updatePollError4 = new Error(updatePoll4).getError();
    AttributeNameValues updatePollAtts4 = null;
    if (updatePollError4.equals(Error.NO_ERROR)) {
      updatePollAtts4 = new AttributeNameValues(updatePoll4);
    }
    System.out.println("Update&Poll all attributes: "+updatePoll4+"\n");
    System.out.println("error = "+updatePollError4+", attributes = "+updatePollAtts4);
    System.out.println("**********************************************\n");

    System.out.println("Need to dock with the widget "+(5-numHandles)+" more times");
    while (numHandles < 5) {
      try {
        Thread.sleep(500);
      } catch (InterruptedException ite) {
          System.out.println("Interrupted thread: "+ite);
      }
    }
    
    // replace previous subscription with new valid subscription with no conditions or attributes
    Error done5 = server.subscribeTo(this, port, SUBSCRIBER_ID, ppwHost, ppwPort, widgetId,
                 WPersonPresence.UPDATE, "presenceUpdate");
    System.out.println("Subscription with no attributes/conditions: "+done5.getError());
    System.out.println("**********************************************\n");

    System.out.println("Need to dock with the widget "+(10-numHandles)+" more times");
    while (numHandles < 10) {
      try {
        Thread.sleep(500);
      } catch (InterruptedException ite) {
          System.out.println("Interrupted thread: "+ite);
      }
    }
    
    // replace previous subscription with new subscription with valid conditions and some attributes
    Attributes subscribeAtts2 = new Attributes();
    subscribeAtts2.addAttribute(WPersonPresence.USERID);
    subscribeAtts2.addAttribute(WPersonPresence.TIMESTAMP);
    Conditions subscribeConds2 = new Conditions();
    subscribeConds2.addCondition(WPersonPresence.USERID,Storage.EQUAL,"16AC850600000044");
    Error done6 = server.subscribeTo(this, port, SUBSCRIBER_ID, ppwHost, ppwPort, widgetId,
                 WPersonPresence.UPDATE, "presenceUpdate", subscribeConds2,subscribeAtts2);
    System.out.println("Subscription with valid attributes/conditions: "+done6.getError());
    System.out.println("**********************************************\n");

    // retrieve all data from the widget after it has data with invalid attributes
    DataObject retrieve2 = server.retrieveDataFrom(ppwHost, ppwPort, widgetId, "blah");
    String retrieveError2 = new Error(retrieve2).getError();

    RetrievalResults retrieveData2 = null;
    if (retrieveError2.equals(Error.NO_ERROR)) {
      retrieveData2 = new RetrievalResults(retrieve2);
    }
    System.out.println("Retrieval after have data with invalid attributes: "+retrieve2+"\n");
    System.out.println("error = "+retrieveError2+", retrieval2 = "+retrieveData2);
    System.out.println("**********************************************\n");

    // retrieve all data from the widget after it has data with invalid conditions
    DataObject retrieve3 = server.retrieveDataFrom(ppwHost, ppwPort, widgetId, "blah", Storage.EQUAL, "blah");
    String retrieveError3 = new Error(retrieve3).getError();

    RetrievalResults retrieveData3 = null;
    if (retrieveError3.equals(Error.NO_ERROR)) {
      retrieveData3 = new RetrievalResults(retrieve3);
    }
    System.out.println("Retrieval after have data with invalid conditions: "+retrieve3+"\n");
    System.out.println("error = "+retrieveError3+", retrieval3 = "+retrieveData3);
    System.out.println("**********************************************\n");

    // retrieve data from the widget after it has data with valid attributes and conditions
    DataObject retrieve4 = server.retrieveDataFrom(ppwHost, ppwPort, widgetId);
    String retrieveError4 = new Error(retrieve4).getError();

    RetrievalResults retrieveData4 = null;
    if (retrieveError4.equals(Error.NO_ERROR)) {
      retrieveData4 = new RetrievalResults(retrieve4);
    }
    System.out.println("Retrieval after have data with no attributes or conditions: "+retrieve4+"\n");
    System.out.println("error = "+retrieveError4+", retrieval4 = "+retrieveData4);
    System.out.println("**********************************************\n");

    // retrieve data from the widget after it has data with valid attributes and conditions
    AttributeFunctions preRetrieveAtts5 = new AttributeFunctions();
    preRetrieveAtts5.addAttributeFunction(WPersonPresence.USERID);
    preRetrieveAtts5.addAttributeFunction(WPersonPresence.TIMESTAMP);
    Conditions preRetrieveConds5 = new Conditions();
    preRetrieveConds5.addCondition(WPersonPresence.USERID, Storage.EQUAL, "16AC850600000044");
    DataObject retrieve5 = server.retrieveDataFrom(ppwHost, ppwPort, widgetId, new Retrieval(preRetrieveAtts5,preRetrieveConds5));
    String retrieveError5 = new Error(retrieve5).getError();

    RetrievalResults retrieveData5 = null;
    if (retrieveError5.equals(Error.NO_ERROR)) {
      retrieveData5 = new RetrievalResults(retrieve5);
    }
    System.out.println("Retrieval after have data with valid attributes and conditions: "+retrieve5+"\n");
    System.out.println("error = "+retrieveError5+", retrieval5 = "+retrieveData5);
    System.out.println("**********************************************\n");

    System.out.println("Need to dock with the widget "+(15-numHandles)+" more times");
    while (numHandles < 15) {
      try {
        Thread.sleep(500);
      } catch (InterruptedException ite) {
          System.out.println("Interrupted thread: "+ite);
      }
    }

    // ask interpreter to interpret data with bad id
    System.out.println("**********************************************");
    AttributeNameValues preInterpretAtts = new AttributeNameValues();
    preInterpretAtts.addAttributeNameValue(WPersonPresence.USERID,userid,Attribute.STRING);
    DataObject interpret = server.askInterpreter(iib2nHost, iib2nPort, "blah", preInterpretAtts);
    String interpretError = new Error(interpret).getError();
    AttributeNameValues interpretAtts = null;
    if (interpretError.equals(Error.NO_ERROR)) {
      interpretAtts = new AttributeNameValues(interpret);
    }
    System.out.println("Interpret with invalid id: "+interpret+"\n");
    System.out.println("error = "+interpretError+", interpreted atts = "+interpretAtts);
    System.out.println("**********************************************\n");

    // ask interpreter to interpret data with valid id but bad attribute
    AttributeNameValues preInterpretAtts2 = new AttributeNameValues();
    preInterpretAtts2.addAttributeNameValue(WPersonPresence.LOCATION,userid,Attribute.STRING);
    DataObject interpret2 = server.askInterpreter(iib2nHost, iib2nPort, IIButton2Name.CLASSNAME, preInterpretAtts2);
    String interpretError2 = new Error(interpret2).getError();
    AttributeNameValues interpretAtts2 = null;
    if (interpretError2.equals(Error.NO_ERROR)) {
      interpretAtts2 = new AttributeNameValues(interpret2);
    }
    System.out.println("Interpret with invalid attribute: "+interpret2+"\n");
    System.out.println("error = "+interpretError2+", interpreted atts = "+interpretAtts2);
    System.out.println("**********************************************\n");

    // ask interpreter to interpret data with valid attribute
    AttributeNameValues preInterpretAtts3 = new AttributeNameValues();
    preInterpretAtts3.addAttributeNameValue(IIButton2Name.IBUTTONID,userid,Attribute.STRING);
    DataObject interpret3 = server.askInterpreter(iib2nHost, iib2nPort, IIButton2Name.CLASSNAME, preInterpretAtts3);
    String interpretError3 = new Error(interpret3).getError();
    AttributeNameValues interpretAtts3 = null;
    if (interpretError3.equals(Error.NO_ERROR)) {
      interpretAtts3 = new AttributeNameValues(interpret3);
    }
    System.out.println("Interpret with valid attribute: "+interpret3+"\n");
    System.out.println("error = "+interpretError3+", interpreted atts = "+interpretAtts3);
    System.out.println("**********************************************\n");

    Subscriber unsub = new Subscriber(SUBSCRIBER_ID, server.getHostAddress(), port, "blah",
                       "presenceUpdate", subscribeConds2, subscribeAtts2);
    Error unsubscribe = server.unsubscribeFrom(this, ppwHost, ppwPort, widgetId, unsub);
    System.out.println("Subscription removed with invalid data: "+unsubscribe.getError());
    System.out.println("**********************************************\n");

    System.out.println("Need to dock with the widget "+(20-numHandles)+" more times");
    while (numHandles < 20) {
      try {
        Thread.sleep(500);
      } catch (InterruptedException ite) {
          System.out.println("Interrupted thread: "+ite);
      }
    }

    Subscriber unsub2 = new Subscriber(SUBSCRIBER_ID, server.getHostAddress(), port, WPersonPresence.UPDATE,
                       "presenceUpdate", subscribeConds2, subscribeAtts2);
    Error unsubscribe2 = server.unsubscribeFrom(this, ppwHost, ppwPort, widgetId, unsub2);
    System.out.println("Subscription removed with valid data: "+unsubscribe2.getError());
    System.out.println("**********************************************\n");

  }

  /**
   * This method is required to implement the Handler interface.  It is called when
   * the callbacks this object subscribes to are triggered.  In this case, it is
   * called when an IButton is docked with the reader in the WPersonPresence.
   *
   * @param callback Name of the callback to handle
   * @param data DataObject containing the callback event data
   * @see context.arch.handler.Handler
   * @see context.arch.widget.WPersonPresence
   * @exception context.arch.InvalidMethodException if the callback specified isn't recognized	
   * @exception context.arch.MethodException if the callback specified can't be handled successfully
   */
  public DataObject handle(String callback, DataObject data) throws InvalidMethodException, MethodException {
    if (callback.equals("presenceUpdate")) {
      AttributeNameValues atts = new AttributeNameValues(data);

      System.out.println("\n\n\n**********************************************\n");
      AttributeNameValue idAtt = atts.getAttributeNameValue(WPersonPresence.USERID);
      if (idAtt != null) {
        userid = (String)idAtt.getValue();
        System.out.print(userid+" was seen at ");
      }
      else {
        System.out.print("null was seen at ");
      }      

      AttributeNameValue locAtt = atts.getAttributeNameValue(WPersonPresence.LOCATION);
      if (locAtt != null) {
        String locationValue = (String)locAtt.getValue();
        System.out.print(locationValue+" at time ");
      }
      else {
        System.out.print("null at time ");
      }      

      AttributeNameValue timeAtt = atts.getAttributeNameValue(WPersonPresence.TIMESTAMP);
      if (timeAtt != null) {
        String time = (String)timeAtt.getValue();
        System.out.print(time+"\n");
      }
      else {
        System.out.print("null\n");
      }      
      System.out.println("**********************************************\n");
      numHandles++;
    }
    else {
      numHandles++;
      throw new InvalidMethodException(Error.UNKNOWN_CALLBACK_ERROR);
    }
    return null;
  }


  /**
   * Main method that creates an instance of PersonPresenceApp
   */
  public static void main (String argv[]) {
    if (argv.length == 5) {
      System.out.println("Attempting to create a PersonPresenceApp on "+DEFAULT_PORT+" at "+argv[0]);    
      TestApp ta = new TestApp(argv[0], argv[1], Integer.parseInt(argv[2]),argv[3], Integer.parseInt(argv[4]));
    }
    else if (argv.length == 6) {
      System.out.println("Attempting to create a PersonPresenceApp on "+argv[2]+" at "+argv[0]);    
      TestApp ta = new TestApp(argv[0], Integer.parseInt(argv[1]), argv[2], Integer.parseInt(argv[3]),argv[4], Integer.parseInt(argv[5]));
    }
    else {
      System.out.println("USAGE: java TestApp <location> [port] <WPersonPresenceHost/ip> <WPersonPresencePort> <IIButton2NameHost/ip> <IIButton2NamePort>");
    }
  }

}
