/* Agent Tcl
   Bob Gray
   30 August 1995

   tclMaskCmd.cc

   This file implements the Tcl commands that handle the message, meeting 
   and event masks.

   Copyright (c) 1995, Robert S. Gray Dartmouth College

   See the file "agent.terms" for information on usage and redistribution
   of this file and for a DISCLAIMER OF ALL WARRANTIES.
*/

#include "platPorting.h"
#include "agentTclInt.h"
#include "agentTcl.h"
#include "genAgentConv.h"
#include "tclMasks.h"

/* maskRemoveCmd

   Tcl syntax: mask remove <handle> [ ALL | <agent_id> ...]

      Purpose: Remove an entry from a mask

        Input: dummy  = client data (unused)
               interp = the current interpreter
               argc   = the number of command arguments
               argv   = the command arguments

       Output: The procedure returns TCL_ERROR and sets the interpreter
               result to an appropriate error message on error.  Otherwise
               the procedure returns TCL_OK and sets the interpreter result
               to the empty string.
*/

int maskRemoveCmd (ClientData, Tcl_Interp *interp, int argc, char **argv)
{
    int i;
    int count;                  /* number of masks to be removed */
    int handle;                 /* mask handle                   */
    AgentMaskEntry **masks;           /* masks to be removed           */
    int returnCode = TCL_OK;    /* return value                  */
    char temp[128];

	/* check the number of arguments */

    if (argc < 4) {
	Tcl_AppendResult (interp, "wrong # of args: should be \"", argv[0], " add <handle> [ ALL | <agent_id> ... ]\"", (char *) NULL);
	return TCL_ERROR;
    }

	/* get the handle */

    if ((Tcl_GetInt (interp, argv[2], &handle) != TCL_OK) || (handle < 0)) {
	sprintf (temp, "invalid mask handle \"%s\"", argv[2]);
        Tcl_SetResult (interp, temp, TCL_VOLATILE);
	return TCL_ERROR;
    }

	/* ALL means remove every entry from the mask */

    if (!strcmp(argv[3], "ALL")) {

	if (argc != 4) { 
	    Tcl_AppendResult (interp, "extraneous arguments after \"ALL\"", (char *) NULL);
	    return TCL_ERROR;
        }

        return (Agent_MaskEmpty (interp, handle));
    }

	/* remove the masks listed in the command */

    argc -= 3;
    argv += 3;
    count = 0;
    masks = new AgentMaskEntry * [argc];

    for (i = 0; i < argc; i++) {

	    /* get each mask */

	if ((masks[i] = Agent_SplitAgentMaskEntry (interp, argv[i])) == NULL) {
	    Tcl_AppendResult (interp, ": invalid mask entry \"", argv[i], "\"", (char *) NULL);
	    returnCode = TCL_ERROR;
	    break;
	}

	count += 1;
    }

	/* remove the masks if each mask was specified correctly */

    if (returnCode == TCL_OK) {
	returnCode = Agent_MaskRemove (interp, handle, count, masks);
    }

	/* cleanup and return */

    for (i = 0; i < count; i++) {
	delete (masks[i]);
    }

    return (returnCode);
}

/* maskAddCmd

   Tcl syntax: mask add <handle> [ ALL | <agent_id> ...]

      Purpose: Add an entry to a mask

        Input: dummy  = client data (unused)
               interp = the current interpreter
               argc   = the number of command arguments
               argv   = the command arguments

       Output: The procedure returns TCL_ERROR and sets the interpreter
               result to an appropriate error message on error.  Otherwise
               the procedure returns TCL_OK and sets the interpreter result
	       to the empty string.
*/

int maskAddCmd (ClientData, Tcl_Interp *interp, int argc, char **argv)
{
    int i;
    int count;                 /* number of masks to be added */
    int handle;                /* mask handle                 */
    AgentMaskEntry **masks;          /* masks to be added           */
    int returnCode = TCL_OK;   /* return value                */
    char temp[128];            /* error message */

	/* check the number of arguments */

    if (argc < 4) {
	Tcl_AppendResult (interp, "wrong # of args: should be \"", argv[0], " add <handle> [ ALL | <agent_id> ... ]\"", (char *) NULL);
	return TCL_ERROR;
    }

	/* get the handle */

    if ((Tcl_GetInt (interp, argv[2], &handle) != TCL_OK) || (handle < 0)) {
	sprintf (temp, "invalid mask handle \"%s\"", argv[2]);
	Tcl_SetResult (interp, temp, TCL_VOLATILE); 
	return TCL_ERROR;
    }

	/* ALL means add every possible mask */

    if (!strcmp(argv[3], "ALL")) {

	if (argc != 4) { 
  	     Tcl_AppendResult (interp, "extraneous arguments after \"ALL\"", (char *) NULL);
	     return TCL_ERROR;
	}

	return (Agent_MaskFill (interp, handle));
    }


	/* add the masks listed in the command */

    argc -= 3;
    argv += 3;
    count = 0;
    masks = new AgentMaskEntry * [argc];

    for (i = 0; i < argc; i++) {

	if ((masks[i] = Agent_SplitAgentMaskEntry (interp, argv[i])) == NULL) {
	    Tcl_AppendResult (interp, ": invalid mask entry \"", argv[i], "\"", (char *) NULL);
	    returnCode = TCL_ERROR;
	    break;
	}

	count += 1;
    }


    /* add the masks if each mask was obtained correctly */

  if (returnCode == TCL_OK) {
    returnCode = Agent_MaskAdd (interp, handle, count, masks);
  }

    /* cleanup and return */

  for (i = 0; i < count; i++) {
    delete (masks[i]);
  }

  return (returnCode);
}

/* maskDisplayCmd

   Tcl syntax: mask display <handle>

      Purpose: Display the contents of a mask

        Input: dummy  = client data (unused)
               interp = the current interpreter
               argc   = the number of command arguments
               argv   = the command arguments

       Output: The procedure returns TCL_ERROR and sets the interpreter
               result to an appropriate error message on error.  Otherwise
               the procedure returns TCL_OK and sets the interpreter result
	       to a list of the mask contents.
*/

int maskDisplayCmd (ClientData, Tcl_Interp *interp, int argc, char **argv)
{
  AgentMask *mask;
  int handle;
  char *string;

    /* check the number of arguments */

  if (argc != 3) {
    Tcl_AppendResult (interp, "wrong # of args: should be \"", argv[0], " display <handle>\"", (char *) NULL);
    return TCL_ERROR;
  }

    /* get the mask handle */

  if ((Tcl_GetInt (interp, argv[2], &handle) != TCL_OK) || (handle < 0)) {
    Tcl_SetResult (interp, "invalid mask handle: must be an integer 0 or greater", TCL_STATIC);
    return TCL_ERROR;
  }

    /* get the contents of the mask */

  if ((mask = Agent_MaskContents (interp, handle)) == NULL) {
    return TCL_ERROR;
  }

    /* turn the contents into a human readable list */

  if (mask -> getType() == MASK_ACCEPT_ALL) {

    Tcl_SetResult (interp, "ALL", TCL_STATIC);

  } else if (mask -> getType() == MASK_ACCEPT_NONE) {

    Tcl_SetResult (interp, "NONE", TCL_STATIC);

  } else {

    for (int i = 0; i < mask -> getCount(); i++) {
      string = Agent_AgentMaskEntryToString (&mask -> getEntry(i));
      Tcl_AppendElement (interp, string);
      delete (string);
    } 
  }

  delete (mask);
  return TCL_OK;
}

/* maskDeleteCmd 

   Tcl syntax: mask delete <handle>

      Purpose: Delete a mask

        Input: dummy  = client data (unused)
               interp = the current interpreter
               argc   = the number of command arguments
               argv   = the command arguments

       Output: The procedure returns TCL_ERROR and sets the interpreter 
               result to an appropriate error message on error.  Otherwise
               the procedure returns TCL_OK and sets the interpreter result
               to the empty string.
*/

int maskDeleteCmd (ClientData, Tcl_Interp *interp, int argc, char **argv)
{
  int handle;
  char temp[64];

    /* check the number of arguments */

  if (argc != 3) {
    Tcl_AppendResult (interp, "wrong # of args: should be \"", argv[0], " delete [ ALL | <handle> ]\"", (char *) NULL);
    return TCL_ERROR;
  }

    /* get the mask handle */

  if ((Tcl_GetInt(interp, argv[2], &handle) != TCL_OK) || (handle < 0)) {
    sprintf (temp, "invalid mask handle \"%s\"", argv[2]);
    Tcl_SetResult (interp, temp, TCL_VOLATILE);
    return TCL_ERROR;
  }

    /* delete the mask */

  return (Agent_MaskDelete (interp, handle));
}

/* maskNewCmd

   Tcl syntax: mask new

      Purpose: Create a new mask

        Input: dummy  = client data (unused)
               interp = the current interpreter 
               argc   = the number of command arguments
               argv   = the command arguments

       Output: The procedure returns TCL_ERROR and sets the interpreter result 
               to an appropriate error message on error.  Otherwise the
               procedure returns TCL_OK and sets the interpreter result to the
               mask handle.
*/

int maskNewCmd (ClientData, Tcl_Interp *interp, int argc, char **argv)
{
  UINT_32 handle;
  char scratch[16];

    /* check the number of arguments */

  if (argc != 2) {
    Tcl_AppendResult (interp, "wrong # of args: should be \"", argv[0], " new\"", (char *) NULL);
    return TCL_ERROR;
  }

    /* create the new mask */

  if (Agent_MaskNew (interp, &handle) != TCL_OK) {
    return TCL_ERROR;
  }

    /* set the interpreter result to the mask handle */

  sprintf (scratch, "%u", handle);
  Tcl_SetResult (interp, scratch, TCL_VOLATILE);
  return TCL_OK; 
}

/* Agent_MaskCmd

   Tcl syntax: mask new
	       mask delete    <handle>
	       mask display   <handle>
	       mask add       <handle> ALL 
	       mask add       <handle> <agent_id> ...
               mask remove    <handle> ALL
	       mask remove    <handle> <agent_id> ... 

      Purpose: Create, delete, expand or shrink a mask

        Input: dummy  = client data (unused)
               interp = the current intepreter
               argc   = the number of command arguments
               argv   = the command arguments

       Output: The procedure returns TCL_ERROR and sets the interpreter result
               to an appropriate error message on error.  Otherwise the
	       procedure returns TCL_OK and sets the interpreter result to
               the empty string (except for "mask display" which sets the
               interpreter result to a human-readable version of the mask
	       contents and "mask new" which sets the interpreter result to
               the mask handle).
*/

int Agent_MaskCmd (ClientData dummy, Tcl_Interp *interp, int argc, char **argv)
{ 
    char *op;
    int returnCode;

	/* check the number of arguments */

    if (argc <= 1) {
	Tcl_AppendResult (interp, "wrong # of args: should be \"", argv[0], " option ?arg ...?\"", (char *) NULL);
	return TCL_ERROR;
    }

	/* determine which operation is being performed */

    op = argv[1];

    if ((*op == 'a') && !strcmp(op,"add")) {
	returnCode = maskAddCmd (dummy, interp, argc, argv);
    } else if ((*op == 'r') && !strcmp(op,"remove")) {
	returnCode = maskRemoveCmd (dummy, interp, argc, argv);
    } else if ((*op == 'n') && !strcmp(op,"new")) {
	returnCode = maskNewCmd (dummy, interp, argc, argv); 
    } else if ((*op == 'd') && !strcmp(op,"delete")) {
	returnCode = maskDeleteCmd (dummy, interp, argc, argv);
    } else if ((*op == 'd') && !strcmp(op,"display")) {
	returnCode = maskDisplayCmd (dummy, interp, argc, argv);
    } else {
	Tcl_AppendResult (interp, "bad option \"", argv[1], "\": should be new, delete, add, remove or display", (char *) NULL);
	returnCode = TCL_ERROR;
    }

    return (returnCode);
}
