/* Agent Tcl
   Bob Gray
   2 August 1995
 
   tclTime.cc

   This file implements the library routine that puts an agent to sleep.

   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 "platSystem.h"
#include "platTimeval.h"
#include "tcl.h"
#include "agentTcl.h"
#include "agentTclInt.h"
#include "tclRestrict.h"

/* Agent_CurrentTime

   Purpose: Return the current time

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

    Output: The procedure returns the number of seconds that have elapsed
	    since January 1, 1970.
*/

double Agent_CurrentTime (Tcl_Interp *)
{
    double seconds;
    struct timeval tv;
    tv = SystemUtil::getCurrentWall ();
    seconds = TimevalUtil::timevalToSeconds (tv);
    return (seconds);
}

/* Agent_CurrentCpuTime

   Purpose: Return the current CPU time

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

    Output: The procedure returns the number of CPU seconds that have elapsed
	    since the program started executing.
*/

double Agent_CurrentCpuTime (Tcl_Interp *)
{
    double seconds;
    struct timeval tv;
    tv = SystemUtil::getCurrentCpu ();
    seconds = TimevalUtil::timevalToSeconds (tv);
    return (seconds);
}

/* Agent_StartTime

   Purpose: Return the time at which the agent started executing

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

    Output: The procedure returns the time at which the agent started 
	    executing (expressed as the number of seconds since January 1,
	    1970).
*/

double Agent_StartTime (Tcl_Interp *interp)
{
    double seconds;
    AGENT_TCL *agent;
    RESTRICT_TCL *restrict;
    struct timeval tv;

	/* AGENT structure */

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

	/* RESTRICT structure */

    restrict = (RESTRICT_TCL *) agent -> get_restrict ();
    assert (restrict != NULL);

	/* get the start time */

    tv = restrict -> getStartTimeval ();
    seconds = TimevalUtil::timevalToSeconds (tv);
    return (seconds);
} 

/* Agent_StartCpuTime

   Purpose: Return the CPU start time which is currently is always 0.0.

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

    Output: The procedure returns 0.0. 
*/

double Agent_StartCpuTime (Tcl_Interp *)
{
    return (0.0);
} 

/* Agent_ElapsedTime

   Purpose: Return the elapsed time since the agent started executing

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

    Output: The procedure returns the number of seconds that have elapsed 
	    since the agent started executing.
*/

double Agent_ElapsedTime (Tcl_Interp *interp)
{
    double seconds;
    AGENT_TCL *agent;
    RESTRICT_TCL *restrict;
    struct timeval start;
    struct timeval current;
    struct timeval diff;

	/* AGENT structure */

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

	/* RESTRICT TCL */

    restrict = (RESTRICT_TCL *) agent -> get_restrict ();
    assert (restrict != NULL);

	/* get the current and start time */

    start = restrict -> getStartTimeval ();
    current = SystemUtil::getCurrentWall ();

	/* take the difference */

    diff = TimevalUtil::subTimevals (current, start);
    seconds = TimevalUtil::timevalToSeconds (diff);
    return (seconds);
}

/* Agent_ElapsedCpuTime

   Purpose: Return the elapsed CPU time since the agent started executing

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

    Output: The procedure returns the number of CPU seconds that have elapsed 
	    since the agent started executing.
*/

double Agent_ElapsedCpuTime (Tcl_Interp *interp)
{
    double seconds;
    AGENT_TCL *agent;
    struct timeval current;

	/* AGENT structure */

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

	/* get the current CPU time */

    current = SystemUtil::getCurrentCpu ();
    seconds = TimevalUtil::timevalToSeconds (current);
    return (seconds);
}

/* Agent_Sleep

   Purpose: Sleep for the specified number of seconds

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

            seconds = the number of seconds
		      (double)

    Output: The procedure returns TCL_ERROR and sets the interpreter result
            to an appropriate error message on error.  The procedure returns
            TCL_PERMIT if a permit violation occurs.  Otherwise the procedure
            sleeps for the specified number of seconds and returns TCL_OK.
*/

int Agent_Sleep (Tcl_Interp *interp, double seconds)
{
    int code;
    AGENT_TCL *agent;
    struct timeval delay;

	/* assertions on the parameters */

    assert (interp != NULL);
    assert (seconds >= 0.0);

	/* AGENT structure */

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

	/* convert seconds to a timeval */

    delay = TimevalUtil::secondsToTimeval (seconds);

	/* sleep */

    if ((code = agent -> agentSleep (delay)) == AGENT_TIMEOUT) {
	return TCL_OK;
    }

	/* error so construct an error code and error message */

    Tcl_SetErrorCode (interp, (agent -> agentCodeToShortString(code)).value(), (char *) NULL);
    Tcl_SetResult (interp, agent -> agentCodeToLongString (code, (char *) NULL).value(), TCL_VOLATILE);
    return TCL_ERROR;
} 
