#ifndef MOD_UTILITY_H
#define MOD_UTILITY_H
#include <sys/stat.h>
#include "riscos.h"
#include "fileswitch.h"
#include "heap.h"

class OS : public Module
{
private:
  void *pmem;

  FileSwitch fileswitch;

  // RISC OS environment variables
  volatile uint32_t environment[18][3];
  bool escape_state;
  int escape_key;
  bool xbit;
  char *cmd_line; // Program command line
  struct timeval os_start_time;

  typedef struct ticker_event
  {
    clock_t call_time;
    target_addr_t call_address;
    uint32_t r12;
    int delay;
  } ticker_event_t;

  vector<ticker_event_t> tickers;

  // Environment variable definitions
  typedef struct env_vars
  {
    int type;
    char *name;
    char *str_value; // For all other VarTypes
    int int_value; // VarType_Number
  } env_vars_t;

  vector<env_vars_t> environ_vars;
  void DelEnvironment (const char *name);
  void SetEnvironment (const char *name, int value);
  void SetEnvironment (const char *name, const char *value);

  // Directory handling (OS_GBPB 9-12)
  OSDir *dir;

  // Caching of file canonicalisation
  struct canonicalise
  {
    string from; // Original path
    string to;   // Canonicalised path
  };

  vector<struct canonicalise> clist;
  void Canonicalise (const char *from, string &to);

  // Keep a record of heaps that the user has initialised with OS_Heap.
  vector<Heap *> user_heaps;
  Heap *FindHeap (void *ptr);

  // Character input/output
  int GetKey (void) { return getchar (); }
  int InKey (int low, int high) { return -1; }
  void WriteCh (unsigned char ch) { putchar (ch); }
  void vdu (unsigned char ch); // VDU driver
  unsigned char vduq[12]; // Queue of VDU data waiting for processing
  int vducount; // Number of bytes in VDU queue.

  // Initialise the module world 
  void Initialise (void);

  inline void ConvertNameNumber (unsigned int val, const char *fmt);

  // The SWI commands
  void WriteC (void);
  void WriteS (void);
  void Write0 (void);
  void NewLine (void);
  void CLI (void);
  void ReadC (void);
  void Byte (void);
  void Word (void);
  void Args (void);
  void BGet (void);
  void BPut (void);
  void GBPB (void);
  void File (void);
  void Find (void);
  void GetEnv (void);
  void Exit (void);
  void IntOff (void);
  void IntOn (void);
  void SWI_Heap (void);
  void SWI_Module (void);
  void ReadVarVal (void);
  void SetVarVal (void);
  void FSControl (void);
  void BinaryToDecimal (void);
  void ReadEscapeState (void);
  void GenerateError (void);
  void ReadVduVariables (void);
  void UpCall (void);
  void ValidateAddress (void);
  void CallAfter (void);
  void CallEvery (void);
  void RemoveTickerEvent (void);
  void ChangeEnvironment (void);
  void ReadMonotonicTime (void);
  void WriteN (void);
  void ReadMemMapInfo (void);
  void ReadSysInfo (void);
  void ReadDynamicArea (void);
  void ChangeRedirection (void);
  void PlatformFeatures (void);
  void SynchroniseCodeAreas (void);
  void DynamicArea (void);

  void ConvertHex1 (void);
  void ConvertHex2 (void);
  void ConvertHex4 (void);
  void ConvertHex6 (void);
  void ConvertHex8 (void);
  void ConvertCardinal1 (void);
  void ConvertCardinal2 (void);
  void ConvertCardinal3 (void);
  void ConvertCardinal4 (void);
  void ConvertInteger1 (void);
  void ConvertInteger2 (void);
  void ConvertInteger3 (void);
  void ConvertInteger4 (void);

  void Debug (void);
public:
  char *module_name;
  int version_major;
  int version_minor;
  int swi_chunk_begin;
  int swi_chunk_end;

  OS (void) : Module ()
  {
    module_name = "UtilityModule";
    version_major = 3;
    version_minor = 70;
    swi_chunk_begin = 0;
    swi_chunk_end = 0x1ff;
    Initialise ();
  }
  virtual ~OS () {}

  unsigned int SWIChunkBegin (void) { return swi_chunk_begin; }
  unsigned int SWIChunkEnd (void) { return swi_chunk_end; }
  bool SWI (unsigned int swinum, bool xbit);
};

enum env_handlers
  {
    ENVH_MEMORYLIMIT = 0,
    ENVH_UNDEFINED_INSTRUCTION = 1,
    ENVH_PREFETCH_ABORT = 2,
    ENVH_DATA_ABORT = 3,
    ENVH_ADDRESS_EXCEPTION = 4,
    ENVH_OTHER_EXCEPTIONS = 5,
    ENVH_ERROR = 6,
    ENVH_CALLBACK = 7,
    ENVH_BREAKPOINT =8,
    ENVH_ESCAPE = 9,
    ENVH_EVENT = 10,
    ENVH_EXIT = 11,
    ENVH_UNUSED_SWI = 12,
    ENVH_EXCEPTION_REGISTERS = 13,
    ENVH_APPLICATION_SPACE = 14,
    ENVH_CAO = 15,
    ENVH_UPCALL = 16
  };
#endif
