/*******************************************************************************
* E.S.O. - VLT project
#
# "@(#) $Id: eccsTestMsg_bis.C,v 1.95 1998/12/17 11:57:13 vltsccm Exp $" 
*
* waSetValue.C
*
* who       when      what
* --------  --------  ----------------------------------------------
* gchiozzi  14/04/99  created
*/

/************************************************************************
*   NAME
*   waSetValue - Sample ECCS application 
* 
*   SYNOPSIS
*   waSetValue destenv destproc
*
*   DESCRIPTION
*   This ECCS example receives the SETVAL, GETVAL and TEST commands.
*   SETVAL and GETVAL are transfered to an application running
*   on and environment and with a process name given
*   at startup on the command line.
*   This example shows a typical case of a workstation coordination
*   application redirecting ("transferring") commands to an LCU
*   for execution.
*   The CDT waSetvalue must be loaded in the environment.
*
*   CAUTION
*   This simple application is able to perfom the basic
*   task of handling the defined commands, but it cannot
*   handle any parallelism: a command must be completely 
*   handled before another can be received.
*   The behaviour if a command (or any message) is received
*   before a pending command is completed.
*   While waiting for replies to tranferred command, the 
*   application is blocked.
*
*   SEE ALSO
*   waSetValueEvh for a more complete example based on EVH
*
*------------------------------------------------------------------------
*/

#define _POSIX_SOURCE 1
#include "vltPort.h"

/* 
 * System Headers
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>


/* 
 * ECCS Headers
 */
#include "ECCS.h"
#include "eccsTestTools.h" 


#define   waSETVAL_CMD   "SETVAL"
#define   waGETVAL_CMD  "GETVAL"
#define   waTEST_CMD     "TEST"

/*
 * Support structure to handle the parameters
 * passed on the command line
 */
typedef struct {
  char *procname;    // Process name for this application
  char *destenv;     // Destination environment for transferred cmds
  char *destproc;    // Destination process for transferred cmds
} waPARMS;

/*
 * Function prototypes
 */
ccsCOMPL_STAT waParseArguments(int argc, char *argv[], waPARMS *parms);

ccsCOMPL_STAT waHandleTransfer(msgMESSAGE &msg, waPARMS &parms);
ccsCOMPL_STAT waHandleTest(msgMESSAGE &msg, waPARMS &parms);

/************************ 
 *   MAIN FUNCTION      *
 ************************/

int main(int argc, char *argv[])
{
  ccsCOMPL_STAT stat = SUCCESS;
  waPARMS parms;
  
  /*
   * Parses command line parameters
   */
  stat = waParseArguments(argc, argv, &parms);
  eccsErrExit(stat,"Error in parsing command line parameters \n");

  eccsLogComment("Process: %.30s, Destination env: %.30s, Destination process: %.30s",
		   parms.procname, parms.destenv, parms.destproc);
  
  /*
   * Initialize CCS.
   */
  stat = ccsInit(parms.procname);
  eccsErrExit(stat,"Error in Init \n");

  /*
   * Message object
   */
  msgMESSAGE msg;
  
  /*
   * Entering the infinite loop
   * where commands are received.
   */
  eccsLogComment("Entering receive command loop");

  while(TRUE)
    {
    /*
     * Block here waiting for a message and receives it
     */
    stat = msg.Receive();
    eccsErrExit(stat, "--> Error in msg.Receive()");
    
    eccsLogComment("Received command: %.30s, buffer: %.30s",
		   msg.Command(), msg.Buffer());
    
    /*
     * Depending on the command name for the 
     * received message performs a specific action
     */

    /*
     * If a TEST command is received...
     */
    if( strcmp(msg.Command(),waTEST_CMD) == 0) 
      stat = waHandleTest(msg, parms);
    /*
     * If a SETVAL command is received...
     */
    else if( strcmp(msg.Command(),waSETVAL_CMD) == 0) 
      stat = waHandleTransfer(msg, parms);
    /*
     * If a GETVAL command is received...
     */
    else if( strcmp(msg.Command(),waGETVAL_CMD) == 0) 
      stat = waHandleTransfer(msg, parms);
    /*
     * If any other (unexpected) command
     * or message is received...
     */
    else
      {
      stat = FAILURE;
      if(msg.Type() == msgTYPE_COMMAND)
	{
	eccsLogError(stdErr, "--> Unexpected command");
	/*
	 * ...must send an error reply
	 */
	msg.SendReply(*stdErr);
	}
      else
	eccsLogError(stdErr, "--> Unexpected message");
      }
    eccsErrExit(stat, "--> Error handling message");
    }

  /*
   *  end of work 
   */
  stat = ccsExit();
  eccsErrExit(stat, "--> Error in ccsExit()");
} /* end main() */




/*
 *****************************************************************************
 */

/**
 * This is a generic function to handle a transfer
 * command, i.e. to 
 *  - take a command
 *  - re-send it to another process
 *  - wait for the replies
 *  - forward back the replies to the original sender
 *  and finally go back to the caller (the command receive
 *  loop)
 */
ccsCOMPL_STAT waHandleTransfer(msgMESSAGE &msg, waPARMS &parms)
{
  ccsCOMPL_STAT stat = SUCCESS;

  /*
   * Prepares the command to be sent by copying
   * the in the message structure the command name and
   * buffer of the received command
   */
  msgMESSAGE transfer;

  transfer.Destenv(parms.destenv);
  transfer.Destproc(parms.destproc);
  transfer.Command(msg.Command());
  transfer.Buffer(msg.Buffer());

  eccsLogComment("--- Sending command: %.30s, buffer: %.30s",
		 transfer.Command(), transfer.Buffer());

  /*
   * Send the command
   */
  stat = transfer.SendCommand();
  if( stat == FAILURE )
    {
    eccsLogError(stdErr, "--> Error in SendCommand");
    msg.SendReply(*stdErr); 
    return stat;
    }

  /*
   * Blocks here waiting for the reply
   * and receive it.
   * It is assumed that the only message that can
   * be received here is the expected reply.
   * If any other message is received, the bahaviour is
   * undefined.
   */
  eccsLogComment("waiting for reply...");
  stat = transfer.Receive();
  if(stat == FAILURE)
    {
    eccsLogError(stdErr, "--> Error in Receive");
    msg.SendReply(*stdErr); 
    return stat;
    }

  /*
   * Sends back the reply to the originator of 
   * the transferred command.
   * It is assumed that no intermediate replies
   * will be received ( a loop should handle that.
   */
  eccsLogComment("Received reply to command: %.30s, buffer: %.30s",
		 transfer.Command(), transfer.Buffer());
  if ( transfer.Type() == msgTYPE_ERROR_REPLY )
    {
    eccsLogError(stdErr, "--> Received error reply");
    stat = msg.SendReply(*stdErr); 
    }
  else
    stat = msg.SendReply(transfer.Buffer()); 

  return stat;
} /* end waHandleTransfer() */

/**
 * This is a simple function to send an immediate rely
 * to a command, with a copy of the receive message buffer
 */
ccsCOMPL_STAT waHandleTest(msgMESSAGE &msg, waPARMS &)
{
  ccsCOMPL_STAT stat = SUCCESS;

  stat = msg.SendReply(msg.Buffer()); 
  return stat;
} /* end waHandleTest() */

/*
 *****************************************************************************
 */

/**
 * This is a simple support function to print
 * a command line help if at process startup the 
 * command line parameters are not succesfully parsed
 * It used by waParseArguments().
 */ 
ccsCOMPL_STAT waPrintCLineHelp(void)
{

    fprintf(stderr,"*****************************************************\n");
    fprintf(stderr,"*    waSetValue                                     *\n");
    fprintf(stderr,"*****************************************************\n");
    fprintf(stderr,"                                                     \n");
    fprintf(stderr,"Usage: waSetValue destenv destproc\n");
    fprintf(stderr,"\n");

    return SUCCESS;

} /* end waPrintCLineHelp() */

/**
 * This function parses the command line parameters
 * at application startup and fills in the parms 
 * structure
 */
ccsCOMPL_STAT waParseArguments(int argc, char *argv[], waPARMS *parms)
{
  ccsCOMPL_STAT stat = SUCCESS;

  if(argc != 3)
    {
    waPrintCLineHelp();
    stat = FAILURE;
    }
  else
    {
    parms->procname = argv[0];
    parms->destenv  = argv[1];
    parms->destproc = argv[2];
    }
  
  return stat;

} /* end waParseArguments() */

/*___oOo___*/










