// OAL: OS Abstraction Layer
#ifndef __OAL_H__
#define __OAL_H__
#include "Common.h"
#include "DateTime.h"
#include "Signal.h"
#if defined(HAVE_SEMAPHORE_H)
#include <semaphore.h>
#endif

#if defined(HAVE_WINDOWS_H)
#define ecvt _ecvt
#define fcvt _fcvt
#define gcvt _gcvt
#endif

namespace AScript {

class StringList;

namespace OAL {

class FileStat;

//-----------------------------------------------------------------------------
// generic functions
//-----------------------------------------------------------------------------
DLLDECLARE extern const char FileSeparatorWin;
DLLDECLARE extern const char FileSeparatorUnix;
DLLDECLARE extern const char FileSeparator;

DLLDECLARE String MakeAbsPath(char chSeparator, const char *fileName, const char *dirName = NULL);
DLLDECLARE String &JoinPathName(char chSeparator, String &pathName, const char *name);
DLLDECLARE String &JoinPathName(char chSeparator, String &pathName, const char *name, size_t len);

inline String &JoinPathName(String &pathName, const char *name) {
	return JoinPathName(OAL::FileSeparator, pathName, name);
}

inline String &JoinPathName(String &pathName, const char *name, size_t len) {
	return JoinPathName(OAL::FileSeparator, pathName, name, len);
}

DLLDECLARE String GetEnv(const char *name);
DLLDECLARE void PutEnv(const char *name, const char *value);
DLLDECLARE void Rename(const char *src, const char *dst);
DLLDECLARE void Remove(const char *pathName);
DLLDECLARE bool MakeDir(const char *pathName, bool recursiveFlag);
DLLDECLARE bool ChangeCurDir(const char *pathName);
DLLDECLARE String GetCurDir();
DLLDECLARE void Sleep(Number delay);
DLLDECLARE Number GetTickTime();
DLLDECLARE DateTime GetCurDateTime(bool utcFlag = false);
#if defined(HAVE_WINDOWS_H)
DLLDECLARE DateTime ToDateTime(const SYSTEMTIME &st);
DLLDECLARE DateTime ToDateTime(const FILETIME &ft, bool utcFlag = false);
static inline bool IsPathSeparator(char ch) { return ch == ';'; }
#else
DLLDECLARE DateTime ToDateTime(const struct tm &tm);
DLLDECLARE DateTime ToDateTime(time_t t, bool utcFlag = false);
static inline bool IsPathSeparator(char ch) { return ch == ';' || ch == ':'; }
#endif
DLLDECLARE String GetBaseDir();
DLLDECLARE String GetDataDir();
DLLDECLARE String GetLibDir();
DLLDECLARE String GetExecutable();
DLLDECLARE void SetupModulePath(StringList &strList);
DLLDECLARE void SetupExecutablePath();

//-----------------------------------------------------------------------------
// DynamicLibrary
//-----------------------------------------------------------------------------
class DLLDECLARE DynamicLibrary {
private:
#if defined(HAVE_WINDOWS_H)
	HMODULE _hModule;
#elif defined(HAVE_LIBDL)
	void *_hLibrary;
#endif
public:
	DynamicLibrary();
	bool Open(Signal sig, const char *pathName);
	void *GetEntry(Signal sig, const char *name);
};

//-----------------------------------------------------------------------------
// Memory
//-----------------------------------------------------------------------------
class DLLDECLARE Memory {
private:
	size_t _bytes;
	char *_buff;
public:
	inline Memory(const Memory &memory) :
								_bytes(memory._bytes), _buff(NULL) {
		::memcpy(Allocate(_bytes), memory.GetPointer(), _bytes);
	}
	Memory(size_t bytes = 0);
	~Memory();
	inline size_t GetSize() const { return _bytes; }
	void *Allocate(size_t bytes);
	void *Resize(size_t bytes, size_t bytesToCopy);
	void Free();
	void *GetPointer(size_t offset = 0) const;
};

//-----------------------------------------------------------------------------
// Thread
//-----------------------------------------------------------------------------
class DLLDECLARE Thread {
public:
	void Start();
	virtual void Run() = 0;
};

//-----------------------------------------------------------------------------
// Semaphore
//-----------------------------------------------------------------------------
class DLLDECLARE Semaphore {
private:
#if defined(HAVE_WINDOWS_H)
	HANDLE _hMutex;
#elif defined(HAVE_SEMAPHORE_H)
	sem_t _sem;
#endif
public:
	Semaphore();
	~Semaphore();
	void Wait();
	void Release();
};

//-----------------------------------------------------------------------------
// Event
//-----------------------------------------------------------------------------
class DLLDECLARE Event {
private:
#if defined(HAVE_WINDOWS_H)
	HANDLE _hEvent;
#else
#endif
public:
	Event();
	~Event();
	void Wait();
	void Notify();
};

}
}

#endif
