//
// File: debug.h
// Debugger interface file
// F.J. Alberti
// Last Modified: 21/05/2001
//

#ifndef _DEBUG_H_
#define _DEBUG_H_

#if defined(SCOL_RELEASE_DEVELOPER)
#define SCOL_DEBUGGER_AWARE
#endif

#ifdef __cplusplus
extern "C" {
#endif

#include "base.h"      // future types.h
#include "macros.h"
#include "mmemory.h"


// Debugger protocol version
#define DEBUG_PROTOCOL_VERSION      "1.01b"
// Debugger package name
#define DEBUG_PACKAGE_NAME          "debug "DEBUG_PROTOCOL_VERSION".pkg" 
// Standard debugger address
#define DEBUG_STANDARD_ADDRESS      ":1201"  // local, port 1201
// Ressource address key in 'usm.ini'
#define DEBUG_RESSOURCE_FILE_KEY    "debugger-url"
// Standard machine name
#define DEBUG_STANDARD_CLIENT_NAME  "SCOL Client"
// DBGSyncRead() buffer size for debugger messages
#define DEBUG_BUFFER_SIZE           16384
// Block size for sending long buffers (including files)
#define DEBUG_BLOCK_SIZE            512

// Debugger-related error
#define MERRDEBUG              -13


// Debugger agent runtime information
#define DBG_SIZE               3
#define DBG_OFFCHN             0    // debug channel
#define DBG_BRKPTS             1    // list of active breakpoints
#define DBG_PTRS               2    // list of "locked" heap pointers

#define DBG_PTR_SIZE           3
#define DBG_PTR_VAL            0    // SCOL pointer value
#define DBG_PTR_ID             1    // heap pointer id
#define DBG_PTR_NEXT           2    // next pointer in list

#define DBG_BRKPT_SIZE         6
#define DBG_BRKPT_PB           0    // shorthand pointer to function PB
#define DBG_BRKPT_ID           1    // unique breakpoint id
#define DBG_BRKPT_CHNID        2    // channel id
#define DBG_BRKPT_PKGID        3    // package id
#define DBG_BRKPT_FUNID        4    // function id
#define DBG_BRKPT_NEXT         5    // next breakpoint in list


typedef enum {
  kVMUnknown      = 0x00,   // Only used for initialisation purposes
  kVMIdle         = 0x01,   // VM idle (not in the interpreter loop)
  kVMRunning      = 0x02,   // VM interpreting bytecodes
  kVMIssuedBreak  = 0x04,   // Break requested
  kVMSuspended    = 0x08,   // VM suspended execution
  kVMIssuedResume = 0x10,   // Resume requested */
  kVMIssuedKill   = 0x20,   // Debugger requests termination
  kVMKilled       = 0x40    // VM "killed" by debugger
} VMState;


// Break source type
typedef enum {
  kBrksrcUndefined,         // Only used for initialisation purposes
  kBrksrcUserBreak,         // Call to 'break'
  kBrksrcUserAssert,        // Call to 'assert'
  kBrksrcTraceFunction,     // Interpreter executed 'break' instruction (trace mode)
  kBrksrcBreakpoint,        // Function breakpoint
  kBrksrcDebugger,          // Debugging server request
  kBrksrcTraceScript        // At script line (trace mode)
} Brksrc;


// Control action codes
typedef enum {
  kActionBreak     = 0x01,
  kActionResume    = 0x02,
  kActionStep      = 0x04,
  kActionStepInto  = 0x08,
  kActionStepOut   = 0x10,
  kActionKill      = 0x20
  // List other action codes of interest here
} DBGAction;


typedef enum {
  kEvalBefore,
  kEvalAfter
} DBGEvalTime;


typedef struct {
  VMState   currState;     // current debugging state
  VMState   lastState;     // state before last break
  int       sock;          // debugging socket
  char      addr[1024];    // debugging server URL
//  DbgTrace  trace;         // trace mode (deactivated, shallow or deep)
  char      script[16384]; // contents of last script executed
  uint      scriptBegLine; // (use SpanText class!)
  uint      scriptBegOff;  // (use SpanText class!)
  uint      scriptEndLine; // (use SpanText class!)
  uint      scriptEndOff;  // (use SpanText class!)
//  int       traceFrame;    // trace frame (used to implement Step Into and Step Out)
  Brksrc    brksrc;        // source of last break
} DBGClient;


// Unique object counters
extern uint chnID;
extern uint pkgID;
extern uint varID;


/*
// Structure DBGClient will be substituted by Debugger class
class Debugger {
public:
  Debugger();                                    // DBGInit (static part)
  
  // Notifiers
  void notifyState();
  void notifyCallStackPushed();
  void notifyCallStackPopped();
  void notifyChannelOpened();
  void notifyChannelClosed();
  void notifyPackageLoaded();
  void notifyPackageRemoved();
  void notifyAssertionViolated(const char* assertion);
  void notifyScriptOpened(const char* script);
  void echo();

  // Requesters
  void requestBreak(Brksrc brksrc);              // DBGRequestBreak

protected:
  void linkTo(mmachine m);
  void init();                                   // DBGInit (dynamic part)
  void connect();                                // DBGOpenChannel
  void disconnect();                             // DBGCloseChannel
  void register();                               // DBGRegisterClient
  void send(unsigned int nargs, char* fmt);      // DBGSendMessage

private:
  mmachine _m;
};
*/

// The debugger client instance
extern DBGClient debug;


int  DBGInit(mmachine m);
#if defined(SCOL_DEBUGGER_AWARE)
SEWORD DBGChannel(mmachine m);
int  DBGHandleBreak(mmachine m);
void DBGSetState(VMState state);
int  DBGServiceDebugger(mmachine m);
void DBGRequestBreak(mmachine m, Brksrc brksrc);
int  DBGEcho(mmachine m);
void DBGCloseChannel(mmachine m);
// Notifiers
int DBGNotifyCallStackPushed(mmachine m);
int DBGNotifyCallStackPopped(mmachine m);
int DBGNotifyChannelOpened(mmachine m);
int DBGNotifyChannelClosed(mmachine m);
int DBGNotifyPackageLoaded(mmachine m);
int DBGNotifyPackageRemoved(mmachine m);
int DBGNotifyAssertionViolated(mmachine m, char* assertion);
int DBGNotifyScriptOpened(mmachine m, const char* script);
#endif
int  SCOLloadDebug(mmachine m);

#ifdef __cplusplus
}
#endif

#endif // debug.h