/* Agent Tcl
   Bob Gray
   30 August 1995

   tclMask.cc

   This file implements the library routines 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 "tclMasks.h"

/* Agent_MaskNew

   Purpose: Create a new mask

     Input: interp = the current interpreter

    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 "handle" to the new mask handle.
*/

int Agent_MaskNew (Tcl_Interp *interp, UINT_32 *handle)
{
    int code;
    UINT_32 scratch;
    AGENT_TCL *agent;
    MASKS_TCL *masks;

	/* assertions on the parameters */

    assert (interp != NULL);
    assert (handle != NULL);

	/* AGENT structure */

    agent = AGENT_TCL::get_agent (interp);
    assert (agent != NULL);

	/* MASKS structure */

    masks = (MASKS_TCL *) agent -> get_masks ();

	/* create the new mask */

    if ((code = masks -> maskCreate (scratch)) == MASK_OK) {
	*handle = scratch;
	return TCL_OK; 
    }

	/* error so set errorCode and the error message */

    Tcl_SetErrorCode (interp, masks -> maskCodeToShortString (code).value(), (char *) NULL);
    Tcl_SetResult (interp, masks -> maskCodeToLongString (code, scratch, NULL).value(), TCL_VOLATILE); 
    return TCL_ERROR;
}

/* Agent_MaskDelete

   Purpose: Delete a mask

     Input: interp = the current interpreter
		     (Tcl_Interp *)

            handle = the mask handle
		     (UINT_32)

    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 Agent_MaskDelete (Tcl_Interp *interp, UINT_32 handle)
{
    int code;
    AGENT_TCL *agent;
    MASKS_TCL *masks;

	/* assertions on the parameters */

    assert (interp != NULL);

	/* AGENT structure */

    agent = AGENT_TCL::get_agent (interp);
    assert (agent != NULL);

	/* MASKS structure */

    masks = (MASKS_TCL *) agent -> get_masks ();
 
	/* delete the mask */

    if ((code = masks -> maskDelete (handle)) == MASK_OK) {
	return TCL_OK;
    }

	/* error so set errorCode and the error message */

    Tcl_SetErrorCode (interp, masks -> maskCodeToShortString (code).value(), (char *) NULL);
    Tcl_SetResult (interp, masks -> maskCodeToLongString (code, handle, NULL).value(), TCL_VOLATILE); 
    return TCL_ERROR;
}

/* Agent_MaskFill

   Purpose: Make a mask accept ANY incoming item

     Input: interp = the current interpreter
		     (Tcl_Interp *)

            handle = the mask handle
		     (UINT_32)

    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 fills the mask.
*/

int Agent_MaskFill (Tcl_Interp *interp, UINT_32 handle)
{  
  int code;
  AGENT_TCL *agent;
  MASKS_TCL *masks;

	/* assertions on the parameters */

    assert (interp != NULL);

	/* AGENT structure */

    agent = AGENT_TCL::get_agent (interp);
    assert (agent != NULL);

	/* MASKS structure */

    masks = (MASKS_TCL *) agent -> get_masks ();

	/* fill the mask */

    if ((code = masks -> maskFill (handle)) == MASK_OK) {
	return TCL_OK;
    }

	/* error so set errorCode and the error message */

    Tcl_SetErrorCode (interp, masks -> maskCodeToShortString(code).value(), (char *) NULL);
    Tcl_SetResult (interp, masks -> maskCodeToLongString(code, handle, NULL).value(), TCL_VOLATILE); 
    return TCL_ERROR;
}

/* Agent_MaskEmpty

   Purpose: Make a mask accept NO incoming items

     Input: interp = the current interpreter
		     (Tcl_Interp *)

            handle = the mask handle
		     (UINT_32)

    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 empties the mask.
*/

int Agent_MaskEmpty (Tcl_Interp *interp, UINT_32 handle)
{  
    int code;
    AGENT_TCL *agent;
    MASKS_TCL *masks;

	/* assertions on the parameters */

    assert (interp != NULL);

	/* AGENT structure */

    agent = AGENT_TCL::get_agent (interp);
    assert (agent != NULL);

	/* MASKS structure */

    masks = (MASKS_TCL *) agent -> get_masks ();

	/* fill the mask */

    if ((code = masks -> maskEmpty (handle)) == MASK_OK) {
	return TCL_OK;
    }

	/* error so set errorCode and the error message */

    Tcl_SetErrorCode (interp, masks -> maskCodeToShortString(code).value(), (char *) NULL);
    Tcl_SetResult (interp, masks -> maskCodeToLongString(code, handle, NULL).value(), TCL_VOLATILE); 
    return TCL_ERROR;
}

/* Agent_MaskAdd

   Purpose: Add entries to a mask
  
     Input: interp  = the current interpreter
		      (struct Tcl_Interp *)

            handle  = the mask handle
		      (UINT_32)

            count   = the number of entries
		      (int)

            entries = the entries
		      (class MaskEntry **)

    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 adds the entries to the mask.
*/

int Agent_MaskAdd (Tcl_Interp *interp, UINT_32 handle, int count, AgentMaskEntry **entries)
{
    int code;
    int returnCode;
    register int i;
    AGENT_TCL *agent;
    MASKS_TCL *masks;

	/* assertions on the parameters */

    assert (interp != NULL);
    assert (entries != NULL);

	/* AGENT structure */

    agent = AGENT_TCL::get_agent (interp);
    assert (agent != NULL);

	/* MASKS structure */

    masks = (MASKS_TCL *) agent -> get_masks ();
    assert (masks != NULL);

	/* add each mask entry to the mask */

    returnCode = TCL_OK;

    for (i = 0; i < count; i++) {
	if ((code = masks -> maskAdd (handle, *(entries[i]))) != MASK_OK) {
	    Tcl_SetErrorCode (interp, masks -> maskCodeToShortString(code).value(), (char *) NULL);
	    Tcl_SetResult (interp, masks -> maskCodeToLongString(code, handle, entries[i]).value(), TCL_VOLATILE); 
	    returnCode = TCL_ERROR;
	    break;
	}
    }

    return (returnCode);
}

/* Agent_MaskRemove

   Purpose: Remove entries from a mask
 
     Input: interp  = the current interpreter
		      (struct Tcl_Interp *)

            handle  = the mask handle
		      (UINT_32)

            count   = the number of entries
		      (int)

            entries = the entries
		      (class MaskEntry **)

    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 removes the entries from the mask.
*/

int Agent_MaskRemove (Tcl_Interp *interp, UINT_32 handle, int count, AgentMaskEntry **entries)
{
    int code;
    int returnCode;
    register int i;
    AGENT_TCL *agent;
    MASKS_TCL *masks;

	/* assertions on the parameters */

    assert (interp != NULL);
    assert (entries != NULL);

	/* AGENT structure */

    agent = AGENT_TCL::get_agent (interp);
    assert (agent != NULL);

	/* MASKS structure */

    masks = (MASKS_TCL *) agent -> get_masks ();

	/* add each mask entry to the mask */

    returnCode = TCL_OK;

    for (i = 0; i < count; i++) {
	if ((code = masks -> maskRemove (handle, *(entries[i]))) != MASK_OK) {
	    Tcl_SetErrorCode (interp, masks -> maskCodeToShortString(code).value(), (char *) NULL);
	    Tcl_SetResult (interp, masks -> maskCodeToLongString(code, handle, entries[i]).value(), TCL_VOLATILE); 
	    returnCode = TCL_ERROR;
	    break;
	}
    }

    return (returnCode);
}

/* Agent_MaskSpecial

   Purpose: Change one of the three distinguished masks

     Input: interp  = the current interpreter
		      (struct Tcl_Interp *)

	    which   = MESSAGE_ITEM, MEETING_ITEM or EVENT_ITEM
		      (int)

	    handle  = new mask handle
		      (UINT_32)

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

int Agent_MaskSpecial (Tcl_Interp *interp, int which, UINT_32 handle)
{
    int code;
    AGENT_TCL *agent;
    MASKS_TCL *masks;

	/* assertions on the parameters */

    assert (interp != NULL);
    assert ((which == MESSAGE_ITEM) || (which == MEETING_ITEM) || (which == EVENT_ITEM));

	/* AGENT and MASKS */

    agent = AGENT_TCL::get_agent (interp);
    assert (agent != NULL);
    masks = (MASKS_TCL *) agent -> get_masks ();

	/* change the mask */

    if ((code = masks -> updateHandle (which, handle)) == MASK_OK) {
	return TCL_OK;
    }

    Tcl_SetErrorCode (interp, masks -> maskCodeToShortString(code).value(), (char *) NULL);
    Tcl_SetResult (interp, masks -> maskCodeToLongString(code, handle, NULL).value(), TCL_VOLATILE); 
    return TCL_ERROR;
}

/* Agent_MaskContents

   Purpose: Get the contents of a mask

     Input: interp = the current Tcl interpreter
		     (struct Tcl_Interp *)

	    handle = the mask handle 
		     (UINT_32)

    Output: The procedure returns NULL and sets the interpreter result to an
	    appropriate error message on error.  Otherwise the procedure
	    returns a pointer to a dynamically allocated MASK structure that 
            contains the mask contents.
*/

struct AgentMask *Agent_MaskContents (Tcl_Interp *interp, UINT_32 handle)
{
    AgentMask *mask;
    MASKS_TCL *masks;
    AGENT_TCL *agent;

	/* assertions on the parameters */

    assert (interp != NULL);

	/* AGENT and MASKS */

    agent = AGENT_TCL::get_agent (interp);
    assert (agent != NULL);
    masks = (MASKS_TCL *) agent -> get_masks ();
    assert (masks != NULL);

	/* get the mask */

    if ((mask = masks -> maskGet (handle)) != NULL) {
	return (mask);
    }

	/* set up errorCode and error string */

    Tcl_SetErrorCode (interp, masks -> maskCodeToShortString(MASK_INVALID_HANDLE).value(), (char *) NULL);
    Tcl_SetResult (interp, masks -> maskCodeToLongString(MASK_INVALID_HANDLE, handle, NULL).value(), TCL_VOLATILE); 
    return ((AgentMask *) NULL); 
} 
