import context.arch.BaseObject;
import context.arch.comm.DataObject;
import context.arch.widget.WPersonNamePresence;
import context.arch.handler.Handler;
import context.arch.InvalidMethodException;
import context.arch.MethodException;
import context.arch.subscriber.Subscriber;
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.storage.AttributeNameValues;
import context.arch.storage.Attributes;
import context.arch.util.Error;

import java.util.Vector;

/**
 * This class is a test application that uses the WPersonNamePresence.  It
 * contains code that tests polling and subscribing to the widget.
 *
 * @see context.arch.handler.Handler 
 * @see context.arch.widget.WPersonNamePresence
 */
public class PersonNamePresenceApp implements Handler {

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

  /**
   * Subscription ID for WPersonNamePresence UPDATE callback
   */
  public static final String SUBSCRIBER_ID = "PersonNamePresenceApp";

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

  /**
   * Constructor that creates an instance of BaseObject at the given port.  It
   * subscribes to the WPersonNamePresence and prints out callback info and polls
   * the widget and prints out the results.
   *
   * @param location Location of the WPersonNamePresence
   * @param localport Port the app is running on
   * @param pnpwHost Hostname the widget is running on
   * @param pnpwPort Port the widget is running on
   * @see context.arch.BaseObject
   * @see context.arch.BaseObject#subscribeTo(context.arch.handler.Handler, java.lang.String, int, java.lang.String,
		java.lang.String, int, java.lang.String, java.lang.String, java.lang.String)
   * @see context.arch.widget.WPersonNamePresence
   */
  public PersonNamePresenceApp(String location, int localport, String pnpwHost, int pnpwPort) {
    BaseObject server = new BaseObject (localport);
    Error done = server.subscribeTo((Handler)this, localport, SUBSCRIBER_ID,
			pnpwHost, pnpwPort, WPersonNamePresence.CLASSNAME+"_"+location, 
			WPersonNamePresence.UPDATE, "presenceUpdate");

    // query the widget's version
    DataObject d3 = server.getVersion(pnpwHost,pnpwPort,WPersonNamePresence.CLASSNAME+"_"+location);
    System.out.println("Version is: "+d3+"\n\n");

    DataObject data = pollPersonNamePresenceWidget(server, location, pnpwHost, pnpwPort);
    if (data != null) {
      String error = new Error(data).getError();
      if (!(error.equals(Error.NO_ERROR))) {
        System.out.println("Error in polling: "+error);
      }
      else {
        System.out.println("\n\n\n**********************************************\n");
        AttributeNameValues anvs = new AttributeNameValues(data);
        String who = (String)anvs.getAttributeNameValue(WPersonNamePresence.USERNAME).getValue();
        String where = (String)anvs.getAttributeNameValue(WPersonNamePresence.LOCATION).getValue();
        String when = (String)anvs.getAttributeNameValue(WPersonNamePresence.TIMESTAMP).getValue();
        System.out.print(who+" was seen at ");
        System.out.print(where+" at time ");
        System.out.println(when+"\n");
        System.out.println("**********************************************\n");
      }
    }
    else {
      System.out.println("results of polling was null!!!");
    }

    System.out.println("done was "+done);
  }

  /**
   * This private method polls the WPersonNamePresence for current information.
   *
   * @param server BaseObject containing the communications infrastructure
   * @param location Physical location of the WPersonNamePresence
   * @param host Hostname the widget is running on
   * @param port Port the widget is running on
   * @return DataObject containing the results of the poll
   */
  private DataObject pollPersonNamePresenceWidget(BaseObject server, String location, String host, int port) {
    DataObject widget = new DataObject (WPersonNamePresence.ID, WPersonNamePresence.CLASSNAME+"_"+location);
    Attributes atts = new Attributes();
    atts.addAttribute(WPersonNamePresence.USERNAME);
    atts.addAttribute(WPersonNamePresence.LOCATION);
    atts.addAttribute(WPersonNamePresence.TIMESTAMP);
    Vector v = new Vector();
    v.addElement(widget);
    v.addElement(atts.toDataObject());
    DataObject query = new DataObject(WPersonNamePresence.QUERY, v);

    try {
      return server.userRequest(query, WPersonNamePresence.QUERY, host, port);
    } catch (DecodeException de) {
        System.out.println("PersonPresenceApp pollPersonNamePresenceWidget() Decode: "+de);
    } catch (EncodeException ee) {
        System.out.println("PersonPresenceApp pollPersonNamePresenceWidget() Encode: "+ee);
    } catch (InvalidDecoderException ide) {
        System.out.println("PersonPresenceApp pollPersonNamePresenceWidget() InvalidDecoder: "+ide);
    } catch (InvalidEncoderException iee) {
        System.out.println("PersonPresenceApp pollPersonNamePresenceWidget() InvalidEncoder: "+iee);
    } catch (InvalidProtocolException ipe) {
        System.out.println("PersonPresenceApp pollPersonNamePresenceWidget() InvalidProtocol: "+ipe);
    } catch (ProtocolException pe) {
        System.out.println("PersonPresenceApp pollPersonNamePresenceWidget() Protocol: "+pe);
    }
    return null;
  }


  /**
   * 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 WPersonNamePresence.
   *
   * @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.WPersonNamePresence
   * @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")) {
      System.out.println("\n\n\n**********************************************\n");
      AttributeNameValues anvs = new AttributeNameValues(data);
      String who = (String)anvs.getAttributeNameValue(WPersonNamePresence.USERNAME).getValue();
      String when = (String)anvs.getAttributeNameValue(WPersonNamePresence.TIMESTAMP).getValue();
      String where = (String)anvs.getAttributeNameValue(WPersonNamePresence.LOCATION).getValue();
      System.out.print(who+" was seen at ");
      System.out.print(where+" at time ");
      System.out.println(when+"\n");
      System.out.println("**********************************************\n");
    }
    else {
      throw new InvalidMethodException(Error.UNKNOWN_CALLBACK_ERROR);
    }
    return null;
  }


  /**
   * Main method that creates an instance of PersonNamePresenceApp
   */
  public static void main (String argv[]) {

    if (argv.length == 3) {
      System.out.println("Attempting to create a PersonNamePresenceApp on "+DEFAULT_PORT+" at "+argv[0]);    
      PersonNamePresenceApp pnpa = new PersonNamePresenceApp(argv[0], argv[1], Integer.parseInt(argv[2]));
    }
    else if (argv.length == 4) {
      System.out.println("Attempting to create a PersonNamePresenceApp on "+argv[2]+" at "+argv[0]);    
      PersonNamePresenceApp pnpa = new PersonNamePresenceApp(argv[0], Integer.parseInt(argv[1]), argv[2], Integer.parseInt(argv[3]));
    }
    else {
      System.out.println("USAGE: java context.apps.PersonPresenceApp.PersonNamePresenceApp <location> [port] <WPersonNamePresenceHost/ip> <WPersonNamePresencePort>");
    }
  }

}

