/*#io
docCopyright("Steve Dekorte", 2002)
docLicense("BSD revised")
*/

#ifndef IOSTATE_DEFINED 
#define IOSTATE_DEFINED 1

#define SIOSYMBOL(stringConstant) IoState_symbolWithCString_(self, stringConstant)

#define IOASSERT(value, message) \
  if (!(value)) \
  { IoState_error_(IOSTATE, m, "Io Assertion '%s'", message); }

/*#define IOSTATE ((IoState *)(self->tag->state))*/
#define IOSTATE ((IoState *)(self->state))

#define IONIL(self) (IOSTATE->ioNil)
#define ISNIL(self) (self == IOSTATE->ioNil)

#include "Queue.h"
#include "Stack.h"
#include "Hash.h"
#include "MainArgs.h"
#include "Scheduler.h"
#include "IoObject_struct.h"
#include "IoSeq.h"
#include "IoObjectGroup.h"
#include "IoVersion.h"
#include "IoStore.h"
#include "IoCoroutine.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct IoState IoState;

#include "IoState_callbacks.h"

typedef IoObject *(IoStateProtoFunc)(void *);

struct IoState
{
    Hash *primitiveProtos;

    SkipDBM *sdbm;
    SkipDB *symbols;

    // coroutines
	
    Scheduler *scheduler; 
    IoObject *objectProto;
    IoObject *mainCoroutine;	  // the object that represents the main "thread"
    IoObject *currentCoroutine; // the object whose coroutine is active 
    Stack *currentIoStack;      // quick access to current coro's retain stack 

    // quick access objects 
	
    IoSymbol *activateString;
    IoSymbol *cloneString;
    IoSymbol *CompilerString;
    IoSymbol *debugString;
    IoSymbol *debugParserString;
    IoSymbol *equalEqualString;
    IoSymbol *forwardString;
    IoSymbol *initString;
    IoSymbol *objectString;
    IoSymbol *parentString;
    IoSymbol *selfString;
    IoSymbol *setSlotString;
    IoSymbol *callString;
    IoSymbol *updateSlotString;
    
    IoObject *setSlotBlock;
    IoObject *localsUpdateSlotCFunc;
    IoObject *localsProto;

    IoMessage *initMessage;
    IoMessage *compareMessage;
    IoMessage *nilMessage;
    IoMessage *printMessage;
    IoMessage *runMessage;
    IoMessage *mainMessage;

    // singletons
    IoObject *ioNil;
    IoObject *ioTrue;
    IoObject *ioFalse;

    // garbage collector 
    IoObject *lobby;
    List *retainedValues;

    int collectorPauseCount;
    //size_t sweepSize; // number of objects until next sweep 

    IoObjectGroup *blackGroup;
    IoObjectGroup *grayGroup;
    IoObjectGroup *whiteGroup;
    IoObjectGroup *freeGroup;
    
    unsigned int currentBlackColor;
    unsigned int currentWhiteColor;

    size_t sweepsPerGeneration;
    size_t sweepsSinceLastGeneration;
    
    size_t newValueCount;             // count of values added since last mark phase 
    size_t newValueCountToUpdate;     // do a mark when reached 
    size_t newValueSinceSweepCount;   // count of values added since last sweep phase
    size_t allocsPerSweep;            // do a sweep when reached 
    size_t lastReferencedObjectCount; // number of referenced objects (after sweep) 

    // weaklinks
	
    Hash *valueToWeakLink;
    //Stack *collectedWeakLinks;

    // recycling 
	
    List *recycledObjects;
    List *recycledObjectsSansSlots;

    MainArgs *mainArgs;

    // current execution state 
	
    int stopStatus;
    void *returnValue;

    // embedding
	
    void *callbackContext;
    IoStateBindingsInitCallback *bindingsInitCallback;
    IoStatePrintCallback        *printCallback;
    IoStateExceptionCallback    *exceptionCallback;
    IoStateExitCallback         *exitCallback;
    IoStateActiveCoroCallback   *activeCoroCallback;
    IoStateThreadLockCallback   *threadLockCallback;
    IoStateThreadUnlockCallback *threadUnlockCallback;

    // persistence
	
    IoStore *store; 
    int isCleaningUp; // set to 1 when IoState_free is called 
    int debugCollector;
    IoObject *debugger;
    IoMessage *vmWillSendMessage;

    // SandBox limits 
	
    int messageCountLimit;
    int messageCount;
    double timeLimit;
    double endTime;
	
    // tail calls
	
    IoMessage *tailCallMessage;
    int isExiting;
    int exitResult;
};

#define IOSUCCESS(self) IOTRUE(self)
#define ISSUCCESS(self) ISTRUE(self)

#define IOFAILURE(self) IOFALSE(self)
#define ISFAILURE(self) ISFALSE(self)

inline IoObject *IOBOOL(const IoObject *const self, const int b);

#define IOSTATE_STRUCT_DEFINED

// setup

IoState *IoState_new(void);
void IoState_init(IoState *self);

// setup tags 

void IoState_registerProtoWithFunc_(IoState *self, IoObject *proto, IoStateProtoFunc *func);
IoObject *IoState_protoWithInitFunction_(IoState *self, IoStateProtoFunc *func);
IoObject *IoState_protoWithName_(IoState *self, const char *name);

void IoState_free(IoState *self);
IoObject *IoState_lobby(IoState *self);
void IoState_setLobby_(IoState *self, IoObject *obj);

// command line 

void IoState_argc_argv_(IoState *st, int argc, const char *argv[]);
/*int IoState_main(IoState *self, int argc, const char **argv);*/

// store

IoStore *IoState_store(IoState *self);

void IoState_runCLI(IoState *self);

#include "IoState_coros.h"
#include "IoState_collector.h"
#include "IoState_debug.h"
#include "IoState_eval.h"
#include "IoState_symbols.h"
#include "IoState_exceptions.h"
#include "IoState_inline.h"

#ifdef __cplusplus
}
#endif
#endif
