/* Agent Tcl
   Bob Gray
   26 January 1997

   agentPermit.h

   This file defines the class Permit. 

   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.
*/

#ifndef _AGENT_PERMIT_H
#define _AGENT_PERMIT_H

#ifndef NO_PRAGMAS
#pragma interface
#endif

#ifndef _PLAT_PORTING_H
#include "platPorting.h"	// struct timeval
#endif
#ifndef _PLAT_SIZES_H
#include "platSizes.h"   	// UINT_32
#endif
#ifndef _TRUEFALSE_H
#include "truefalse.h"   	// BOOLEAN 
#endif

/*
 * permit
 */

class Permit 
{
    friend class PermitPacker; 
    friend class PermitUnpacker;

	// flags that indicate which limits are set */

    int flags; 
	
	// limits on wall-time, cpu-time, jumps, children and parent-child depth */
 
    struct timeval wall; 
    struct timeval cpu; 
    UINT_32 jumps;
    UINT_32 children;
    UINT_32 depth;

public:

    enum PermitFlags {
	e_PERMIT_WALL		= 0x1,
	e_PERMIT_CPU		= 0x2,
	e_PERMIT_JUMPS		= 0x4,
	e_PERMIT_CHILDREN	= 0x8,
	e_PERMIT_DEPTH		= 0x10
    };

        // constructors
  
    Permit (void):
	flags (0)
    {
	// empty
    }

    Permit (const Permit &permit):
	flags (permit.flags),
	wall (permit.wall),
	cpu (permit.cpu),
	jumps (permit.jumps),
	children (permit.children),
	depth (permit.depth)
    {
	// empty
    }

	// assignment operator
    
    Permit& operator= (const Permit &permit) {

	if (this != &permit) {
	    flags    = permit.flags;
	    wall     = permit.wall;
	    cpu      = permit.cpu;
	    jumps    = permit.jumps;
	    children = permit.children;
	    depth    = permit.depth;
	}

	return *this;
    }

	// destructor

   ~Permit () {
	// empty
    }

	// merge in a permit or add a permit

    void merge (const Permit &permit);  
    void add (const Permit &permit);

	// set the permit to the minimum of two permits

    void setToMinimum (const Permit &first, const Permit &second);

	// empty out the permit

    void empty (void) {
	flags = 0;
    }

	// see if a limit is set in this permit 

    BOOLEAN haveAll (void) const {
	return (flags == (e_PERMIT_WALL | e_PERMIT_CPU | e_PERMIT_JUMPS | e_PERMIT_CHILDREN | e_PERMIT_DEPTH)) ? e_TRUE : e_FALSE;

    }
    BOOLEAN haveWallLimit (void) const {
	return (flags & e_PERMIT_WALL) ? e_TRUE : e_FALSE;
    }

    BOOLEAN haveCpuLimit (void) const {
	return (flags & e_PERMIT_CPU) ? e_TRUE : e_FALSE;
    }

    BOOLEAN haveJumpLimit (void) const {
	return (flags & e_PERMIT_JUMPS) ? e_TRUE : e_FALSE;
    }

    BOOLEAN haveChildrenLimit (void) const {
	return (flags & e_PERMIT_CHILDREN) ? e_TRUE : e_FALSE;
    }

    BOOLEAN haveDepthLimit (void) const {
	return (flags & e_PERMIT_DEPTH) ? e_TRUE : e_FALSE;
    }

	// get and set routines

    struct timeval getWallLimit (void) const {
	return (wall);
    }

    struct timeval getCpuLimit (void) const {
	return (cpu);
    }

    UINT_32 getJumpLimit (void) const {
	return (jumps);
    }

    UINT_32 getChildrenLimit (void) const {
	return (children);
    }

    UINT_32 getDepthLimit (void) const {
	return (depth);
    }

    void setWallLimit (struct timeval p_wall) {
	flags |= e_PERMIT_WALL;
	wall = p_wall;
    }

    void setCpuLimit (struct timeval p_cpu) {
	flags |= e_PERMIT_CPU;
	cpu = p_cpu;
    }

    void setJumpLimit (UINT_32 p_jumps) {
	flags |= e_PERMIT_JUMPS;
	jumps = p_jumps;
    }

    void setChildrenLimit (UINT_32 p_children) {
	flags |= e_PERMIT_CHILDREN;
	children = p_children;
    }

    void setDepthLimit (UINT_32 p_depth) {
	flags |= e_PERMIT_DEPTH;
	depth = p_depth;
    }
};

/*
 * Iterators that pack and unpack a Permit -- we use iterators since
 * eventually we want to be able to pack the Permit in fixed-size chunks
 * so that we can overlap the packing and transmission process
 */

class PermitPacker
{
    Permit &m_permit;    // Permit that we are packing into a byte stream

public:

	// constructor

    PermitPacker (Permit &permit):
	m_permit (permit)
    {
	// empty
    }
	
	// get the packed size of the permit 

    UINT_32 getPackedSize (void);

	// pack the permit into the buffer 

    char *pack (char *buffer);
};

class PermitUnpacker
{
    Permit &m_permit;

public:

	// constructor and destructor

    PermitUnpacker (Permit &permit):
	m_permit (permit)
    {
	// empty
    }

	// unpack from a buffer

    char *unpack (char *buffer, char *endBuffer);
};

/*
 * Iterators that pack and unpack a timeval -- we use iterators since
 * eventually we want to be able to pack the timeval in fixed-size chunks
 * so that we can overlap the packing and transmission process
 */

#ifdef FIX_LATER

/* 
 * TimevalPacker and TimevalUnpacker should be moved into a more logical place
 */

#endif

class TimevalPacker
{
    struct timeval &m_tv;
 
public:

    TimevalPacker (struct timeval& tv):
	m_tv (tv)
    {
	// empty
    }

    UINT_32 getPackedSize(void) {
	return (2 * sizeof(UINT_32));
    }

    char *pack (char *buffer);
};

class TimevalUnpacker
{
    struct timeval &m_tv;
 
public:

    TimevalUnpacker (struct timeval& tv):
	m_tv (tv)
    {
	// empty
    }

    char *unpack (char *buffer, char *endBuffer);
};

#endif
