#ifndef ESYSTEM_OSX_H
#define ESYSTEM_OSX_H

#include "eutils-config.h"

#include "earray.h"
#include "efunc.h"
#include "einthashof.h"

class esystemTimer
{
 public:
  CFRunLoopTimerRef tmref;
  efunc callback;
  evararray data;
  double secs;
  double repeat;

  esystemTimer();
  ~esystemTimer();
};

class esystemCallbackArray;

class esystemCallback
{
 public:
  int lcount;
  esystemCallbackArray *cbarr;

  evararray readData;
  efunc readCallback;
  bool readEnabled;

  evararray writeData;
  efunc writeCallback;
  bool writeEnabled;

  esystemCallback(esystemCallbackArray *cbarr);
  ~esystemCallback();

  void enableReadWrite();
  void enableRead();
  void enableWrite();
  inline void enableAccept() { enableRead(); }
  void disableReadWrite();
  void disableRead();
  inline void disableAccept() { disableRead(); }
  void disableWrite();
  void remove();
  void release();
  void retain();
};

class esystemCallbackArray
{
 public:
  int writeCount;
  int readCount;

  int fd;
  CFRunLoopSourceRef source;
  ebasicarray<esystemCallback*> callbacks;

  esystemCallbackArray(int fd);
  virtual ~esystemCallbackArray();

  virtual void enableRead()=0;
  virtual void enableWrite()=0;
  virtual void disableRead()=0;
  virtual void disableWrite()=0;
//  virtual void remove();
};

class esystemFileCallbackArray : public esystemCallbackArray
{
 public:
  CFFileDescriptorRef fdref;

  esystemFileCallbackArray(int fd);
  ~esystemFileCallbackArray();

  virtual void enableRead();
  virtual void enableWrite();
  virtual void disableRead();
  virtual void disableWrite();
};

class esystemSocketCallbackArray : public esystemCallbackArray
{
 public:
  CFSocketRef sref;
  esystemSocketCallbackArray(int fd);
  ~esystemSocketCallbackArray();

  virtual void enableRead();
  virtual void enableWrite();
  virtual void disableRead();
  virtual void disableWrite();
};

class esystem
{
 public:
  einthashof<esystemCallbackArray> fdCallbacks;
  esystemCallback *waitcb;

//  earrayof<esystemTimer,long int> timers;

  estrarray getLocalAddresses();

  estr getExecutablePath() const;
  estr getHostname() const;
  int  getPID() const;

  int getTotalRam();
  int getFreeRam();
  int getBufferRam();

  long int getMemLimit();

  void setFrontProcess();

  esystemTimer* addTimer(const efunc& callback,const evararray& data,double secs,double repeat);

  static esystem *cursystem;
  ProcessSerialNumber PSN;

  esystem();

  void process();
  void run();

  static void handleTimerCallback(CFRunLoopTimerRef tmref, void *info);
  static void handleSocketCallback(CFSocketRef sref, CFSocketCallBackType callBackTypes, CFDataRef address, const void *data, void *info);
  static void handleFileCallback(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info);
  
  esystemCallback *addReadWriteCallback(int fd,const efunc& readCallback,const evararray& readData,const efunc& writeCallback,const evararray& writeData);
  esystemCallback *addReadCallback(int fd,const efunc& func,const evararray& data);
  esystemCallback *addWriteCallback(int fd,const efunc& func,const evararray& data);

  esystemCallback *addSocketReadWriteCallback(int fd,const efunc& readCallback,const evararray& readData,const efunc& writeCallback,const evararray& writeData);
  esystemCallback *addSocketReadCallback(int fd,const efunc& func,const evararray& data);
  esystemCallback *addSocketWriteCallback(int fd,const efunc& func,const evararray& data);
  inline esystemCallback *addSocketAcceptCallback(int fd,const efunc& func,const evararray& data){ return(addSocketReadCallback(fd,func,data)); }

  void wait(int fd=-1);  
  void waitSocket(int fd=-1);  
};

esystem& getSystem();

#endif

