/* Agent Tcl
   Bob Gray
   27 February 1995

   tclRandom.cc

   This file implements the library routines that handle the random number
   generator. 

   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 "agentTcl.h"
#include "random.h"
#include "tcl.h"
#include "truefalse.h"

/* Agent_Trueevent

   Purpose: Seed the random number pool using the measured time (and other
	    environmental differences) since the last trueevent call 

      Input: interp = the current interpreter
		      (struct Tcl_Interp *)
	
	     c      = the character associated with the event
		      (char)

     Output: The procedure returns -1 and sets the interpreter result
	     to an appropriate error message on error.  Otherwise the
	     procedure returns TCL_OK and returns the number of
	     bits of entropy that were added to the random pool.
*/

int Agent_Trueevent (Tcl_Interp * /*interp*/, char c)
{
    unsigned bits;

	/* seed the random pool */

    bits = trueRandEvent (c);
    return ((int) bits);
}

/* Agent_Trueseed

    Purpose: Seed the random number pool using the measured time (and
	     other environmental differences) between user keystrokes

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

	     bits   = the desired number of random bits
		      (int)

     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 seeds the random number pool.
*/

int Agent_Trueseed (Tcl_Interp *interp, int bits)
{
	/* assertions on the parameters */

    assert (interp != NULL);
    assert (bits > 0);

#ifdef TCL8

	/* Tcl 8.0 can not yet handle trueseed */

    abort_with_message ("Tcl 8.0 does not yet support trueseed");
    return TCL_ERROR;
    
#else

	/* make sure that we are in interactive mode */

    if (!(interp -> interactive)) {
	Tcl_SetResult (interp, "must be in interactive mode", TCL_STATIC);
	return TCL_ERROR;
    }

#endif

	/* seed the random number pool */

#ifdef FIX_LATER

	/* There are undoubtedly many ways for trueRandAccum to fail -- */
	/* all of them relate to whether or not stdin is actually open  */
	/* and is actually connected to a tty.                          */

#endif

    trueRandAccum (bits);
    return TCL_OK;
}

/* Agent_Seed

    Purpose: Add (additional) seed information to the random pool

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

	     seed   = the seed information 
		      (UINT_32)

     Output: The procedure returns TCL_OK and adds the seed information to
	     the random pool.
*/

int Agent_Seed (Tcl_Interp *interp, UINT_32 seed)
{
    AGENT_TCL *agent;

	/* assertions on the parameters */

    assert (interp != NULL);

	/* agent structure */

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

	/* seed */

    agent -> agentSeed (seed);
    return TCL_OK;
}

/* Agent_Random

   Purpose: Return a cryptographically secure random number -- note that
            the number is only cryptographically secure if the agent is
	    registered or was able to contact the local agent server on
	    startup -- there should probably be some kind of flag in the
	    agent array to indicate whether "random" is currently 
	    cryptographically secure.

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

    Output: The procedure returns TCL_OK and sets *number to the random
	    number.
*/

int Agent_Random (Tcl_Interp *interp, UINT_32 *number)
{
    AGENT_TCL *agent;

	/* assertions on the parameters */

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

	/* agent structure */

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

	/* get the random number */

    *number = agent -> agentRandom ();
    return (TCL_OK);
}
