package context.arch.service;

import context.arch.comm.DataObject;
import context.arch.comm.CommunicationsHandler;
import context.arch.storage.AttributeNameValues;
import context.arch.service.helper.ServiceInput;
import context.arch.service.helper.FunctionDescriptions;
import context.arch.handler.AsyncServiceHandler;
import context.arch.MethodException;
import context.arch.InvalidMethodException;

/**
 * This class implements a generic inherited service.  A service is inherited
 * by a server from a widget that it uses.  It allows the server to act as
 * a proxy to widget services.
 *
 * @see context.arch.service.Service
 * @see context.arch.handler.AsyncServiceHandler
 */
public class InheritedService extends Service implements AsyncServiceHandler {

  private String serviceHost;
  private String servicePort;
  private String serviceId;
  private String serverName;
  private String serviceName;

  /**
   * Basic constructor that creates an inherited service object.
   *
   * @param comm Object that implements the CommunicationsHandler interface
   * @param serverName Name of the server offering the inherited service
   * @param serviceName Name of the service being inherited
   * @param descriptions FunctionDescriptions for the inherited service
   * @param serviceHost Hostname of the component offering the original service
   * @param servicePort Port of the component offering the original service
   * @param serviceId Id of the component offering the original service
   */
  public InheritedService(CommunicationsHandler comm, String serverName, String serviceName, FunctionDescriptions descriptions, 
                          String serviceHost, String servicePort, String serviceId) {
    super(comm,serverName+serviceName,descriptions);
    this.serviceHost = serviceHost;
    this.servicePort = servicePort;
    this.serviceId = serviceId;
    this.serviceName = serviceName;
    this.serverName = serverName;
  }

  /**
   * Basic constructor that creates an inherited service object.
   *
   * @param comm Object that implements the CommunicationsHandler interface
   * @param serverName Name of the server offering the inherited service
   * @param serviceName Name of the service being inherited
   * @param descriptions FunctionDescriptions for the inherited service
   * @param serviceHost Hostname of the component offering the original service
   * @param servicePort Port of the component offering the original service
   * @param serviceId Id of the component offering the original service
   */
  public InheritedService(CommunicationsHandler comm, String serverName, String serviceName, FunctionDescriptions descriptions, 
                          String serviceHost, int servicePort, String serviceId) {
    super(comm,serverName+serviceName,descriptions);
    this.serviceHost = serviceHost;
    this.servicePort = Integer.toString(servicePort);
    this.serviceId = serviceId;
    this.serviceName = serviceName;
    this.serverName = serverName;
  }

  /**
   * This method is called when a component requests that this inherited service
   * be executed.  It checks to see whether the service is synchronous or 
   * asynchronous and then calls the inherited service.  If the service is
   * asynchronous, it adds the request to its pending queue.
   *
   * @param serviceInput Object containing all information required to execute the service
   * @return result of the service request
   * @see CommunicationsHandler#executeSynchronousWidgetService(String,int,String,String,String,AttributeNameValues)
   * @see CommunicationsHandler#executeAsynchronousWidgetService(AsyncServiceHandler,String,int,String,String,String,AttributeNameValues,String)
   * @see context.arch.service.helper.PendingOut#addPending(ServiceInput)
   */
  public DataObject execute(ServiceInput serviceInput) {
    String timing = getFunctionDescriptions().getFunctionDescription(serviceInput.getFunctionName()).getTiming();
    if (timing.equals(SYNCHRONOUS)) {
      return comm.executeSynchronousWidgetService(serviceHost,Integer.parseInt(servicePort),serviceId,
                  serviceName,serviceInput.getFunctionName(),serviceInput.getInput());
    }
    else if (timing.equals(ASYNCHRONOUS)) {
      pending.addPending(serviceInput);
      return comm.executeAsynchronousWidgetService(this,serviceHost,Integer.parseInt(servicePort),serviceId,
                  serviceName,serviceInput.getFunctionName(),serviceInput.getInput(),
                  serviceInput.getUniqueId());
    }
    return new DataObject();
  }

  /**
   * This method is called when this inherited asynchronous service returns 
   * the result.  It collects the returned data, determines which requester
   * the data should go to, removes the request from the pending queue and
   * sends the data to the requester.
   *
   * @param requestTag Unique id to identify the request
   * @param data DataObject containing the service results
   * @return Always returns null
   *
   * @exception MethodException thrown if the asynchronous service result can't 
                be handled successfully
   * @exception InvalidMethodException thrown if the asynchronous service result
   *            was not expected and can't be routed correctly
   * @see Service#sendServiceResult(ServiceInput,AttributeNameValues)
   * @see context.arch.service.helper.PendingOut#removePending(String)
   */ 
  public DataObject asynchronousServiceHandle(String requestTag, DataObject data) throws MethodException, InvalidMethodException {
    AttributeNameValues atts = new AttributeNameValues(data);
    ServiceInput si = pending.getPending(requestTag);
    pending.removePending(requestTag);
    DataObject data2 = sendServiceResult(si,atts);
    return null;
  }

}
