/* Agent Tcl
   Bob Gray
   9 December 1997

   This file implements the Agent_ServerMain procedure.

   Copyright (c) 1995-1997, 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 "suppStrings.h"
#include "tcl.h"
#include "agentTcl.h"
#include "genServerInterface.h"
#include "restrictTcl.h"
#include "tcpipTcl.h"
#include "tclUtility.h"

/*
 * Maximum number of tries and maxium sleep period when sending result
 */

const UINT_32 MAXIMUM_TRIES = 10;
const UINT_32 MAXIMUM_SLEEP = 300;

/*
 * Maximum number of agents that this process can handle before it must exit
 */

const UINT_32 MAXIMUM_AGENTS_PER_PROCESS = 16;

/* Agent_ServerMain

   Purpose: Execute agents that arrive through the server

     Input: appInitProc = Tcl initialization procedure
 
    Output: The procedure should never return.
*/

void Agent_ServerMain (Tcl_AppInitProc *appInitProc)
{
    int code;
    char *result;
    Tcl_Interp *interp;
    Tcl_Interp *masterInterp;

#ifdef REUSE_INTERPRETER

	/*
	 * Create a dummy interpreter so that standard input, output
	 * and error will not be closed when we delete the other   
	 * interpreters below.  This is ugly!  The probable solution
	 * will be to keep the same master interpreter from one agent
	 * to another (which has speed benefits too).                
	 */

    Tcl_Interp *dummyInterp = Tcl_CreateInterp();

	/*
	 * Handle agents until we have handled the maximum number
	 */

    for (UINT_32 i = 0; i < MAXIMUM_AGENTS_PER_PROCESS; ++i) {

#endif

	    /* create the new agent */

#ifdef FIX_LATER
	    /* version code currently appears in two places */
	    /* (here and in Agent_AppInit in tclAppInit.cc) */
#endif

#ifndef LANGUAGE_NAME
#define LANGUAGE_NAME "STATE-TCL"
#endif

	Version version (LANGUAGE_NAME, TCL_MAJOR_VERSION, TCL_MINOR_VERSION, Version::e_PRODUCTION);
	AGENT_TCL *agent = new AGENT_TCL (version);

	    /* wait for the incoming state image */

	if (agent -> agentRestore () != AGENT_OK) {
	    exit (ServerInterface::e_CAN_NOT_RESTORE_STATE);
	}

	    /* get the interpreters */

	interp       = agent -> getInterpreter ();
	masterInterp = agent -> getMasterInterpreter ();
	assert (interp != NULL);
	assert (masterInterp != NULL);

	    /* initialize the interpreters */

	result = strcpyWithAlloc (interp -> result);

	if ((code = (*appInitProc)(interp)) != TCL_OK) {
	    Tcl_AddErrorInfo (interp, "\n    (*** initialization script ***)");
            Agent_SendResult (interp, MAXIMUM_TRIES, MAXIMUM_SLEEP, code);
 	    Tcl_DeleteInterp (interp);
	    Tcl_Exit (0);
	}

	Tcl_SetResult (interp, result, TCL_DYNAMIC);
	result = NULL;

	    /* execute the agent */

	code = agent -> agentRun ();

	    /* send the result to the root agent */

	if (interp->resultCode != TCL_REWIND) {
	    Agent_SendResult (interp, MAXIMUM_TRIES, MAXIMUM_SLEEP, interp->resultCode);
	}

	    /* delete everything */

#ifdef FIX_LATER
	    // The cleanup handler for interp (1) automatically deletes the 
	    // Agent instance that was created above and (2) automatically 
	    // calls agentEnd -- this may not be what we want in the long term.
#endif

	Tcl_DeleteInterp (interp);
	Tcl_DeleteInterp (masterInterp);
	masterInterp = NULL;
	interp = NULL;

#ifdef REUSE_INTERPRETER
    }
#endif

	/* exit */

    Tcl_Exit (0);
    abort_with_message ("should never get here");   // should never get here
}
