//	Zinc Application Framework - Z_FILE.HPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#if !defined(Z_FILE_HPP)
#define Z_FILE_HPP
#include <z_list.hpp>

const ZafUInt16 ZAF_UNICODE_FLAG 			= 0x8000;

typedef unsigned short ZafFileMode;
const ZafFileMode ZAF_FILE_READ				= 0x0001;
const ZafFileMode ZAF_FILE_READWRITE		= 0x0002;
const ZafFileMode ZAF_FILE_CREATE			= 0x0004;
const ZafFileMode ZAF_FILE_OPENCREATE		= 0x0008;
const ZafFileMode ZAF_FILE_TEMPORARY		= 0x0010;
const ZafFileMode ZAF_FILE_BINARY			= 0x0020;
const ZafFileMode ZAF_FILE_TEXT				= 0x0040;
const ZafFileMode ZAF_FILE_DERIVED_ACCESS	= 0x0080;

enum ZafSeek
{
	ZAF_SEEK_START		= 0,
	ZAF_SEEK_CURRENT	= 1,
	ZAF_SEEK_END		= 2
};

typedef long ZafOffset;

const ZafIChar ZAF_DIRECTORY_SEPARATOR 		= '~';

typedef ZafUInt16 ZafFileAttribute;
const ZafFileAttribute ZAF_FATTRIB_NONE				= 0x0000;
const ZafFileAttribute ZAF_FATTRIB_DIRECTORY		= 0x0001;
const ZafFileAttribute ZAF_FATTRIB_READONLY			= 0x0002;

struct ZAF_EXPORT ZafFileInfoStruct
{
	const ZafIChar *name;
	ZafStringID stringID;
	ZafNumberID numberID;
	ZafOffset length;
	ZafFileAttribute attributes;

	// Used internally by the file system.
	void *internalHandle;

	bool Directory(void) { return ((attributes & ZAF_FATTRIB_DIRECTORY) ? true : false); }
	bool ReadOnly(void) { return ((attributes & ZAF_FATTRIB_READONLY) ? true : false); }
};

// --------------------------------------------------------------------------
// ----- ZafFile ------------------------------------------------------------
// --------------------------------------------------------------------------

class ZAF_EXPORT ZafFile : public ZafElement
{
public:
	virtual ~ZafFile(void);

	// --- status ---
	ZafError Error(void) const;
	ZafError SetError(ZafError error);

	// --- Modes ---
	// get
	bool BinaryMode(void) const;
	bool Create(void) const;
	bool DerivedAccess(void) const;
	bool OpenCreate(void) const;
	bool ReadOnly(void) const;
	bool ReadWrite(void) const;
	bool Temporary(void) const;
	bool TextMode(void) const;

	// --- Search functions ---
	virtual ZafOffset Length(void) const = 0;
	virtual int Seek(ZafOffset offset, ZafSeek location) = 0;
	virtual ZafOffset Tell(void) const = 0;

	// --- Read functions ---
	virtual int ReadData(void *buffer, int size) = 0;
	virtual int Read(ZafInt8 &value);
	virtual int Read(ZafUInt8 &value);
	virtual int Read(ZafInt16 &value);
	virtual int Read(ZafUInt16 &value);
	virtual int Read(ZafInt32 &value);
	virtual int Read(ZafUInt32 &value);
	virtual int Read(double &value);
	virtual int Read(ZafIChar *string, int length);
	virtual int Read(ZafIChar **string);
	virtual int Read(void *buffer, int size, int num);

	// The definition of ZAF_WORD_SIZE == 64 is the following:
	// 8 bit chars, 16 bit shorts, 32 bit ints, and 64 bit longs.
	// In this case, ZafInt32 is typedefed to int, rather than long, so
	// Read(int &value) is the same as Read(ZafInt32 &value).
#if ZAF_WORD_SIZE != 64
	int Read(int &value);
#endif

	// --- Write functions ---
	virtual int WriteData(const void *buffer, int size) = 0;
	virtual int Write(ZafInt8 value);
	virtual int Write(ZafUInt8 value);
	virtual int Write(ZafInt16 value);
	virtual int Write(ZafUInt16 value);
	virtual int Write(ZafInt32 value);
	virtual int Write(ZafUInt32 value);
	virtual int Write(double value);
	virtual int Write(const ZafIChar *string);
	virtual int Write(const void *buffer, int size, int num);

	// The definition of ZAF_WORD_SIZE == 64 is the following:
	// 8 bit chars, 16 bit shorts, 32 bit ints, and 64 bit longs.
	// In this case, ZafInt32 is typedefed to int, rather than long, so
	// Write(int &value) is the same as Write(ZafInt32 &value).
#if ZAF_WORD_SIZE != 64
	int Write(int value);
#endif

	// --- Operator overloads ---
	ZafFile &operator>>(ZafInt8 &value) { Read(value); return (*this); }
	ZafFile &operator>>(ZafUInt8 &value) { Read(value); return (*this); }
	ZafFile &operator>>(ZafInt16 &value) { Read(value); return (*this); }
	ZafFile &operator>>(ZafUInt16 &value) { Read(value); return (*this); }
	ZafFile &operator>>(ZafInt32 &value) { Read(value); return (*this); }
	ZafFile &operator>>(ZafUInt32 &value) { Read(value); return (*this); }
	ZafFile &operator>>(double &value) { Read(value); return (*this); }
	ZafFile &operator>>(ZafIChar *text) { Read(text, -1); return (*this); }
	ZafFile &operator>>(ZafIChar **text) { Read(text); return (*this); }

	// The definition of ZAF_WORD_SIZE == 64 is the following:
	// 8 bit chars, 16 bit shorts, 32 bit ints, and 64 bit longs.
	// In this case, ZafInt32 is typedefed to int, rather than long, so
	// >>(int &value) is the same as >>(ZafInt32 &value).
#if (ZAF_WORD_SIZE != 64)
	ZafFile &operator>>(int &value) { Read(value); return (*this); }
#endif

	ZafFile &operator<<(ZafInt8 value) { Write(value); return (*this); }
	ZafFile &operator<<(ZafUInt8 value) { Write(value); return (*this); }
	ZafFile &operator<<(ZafInt16 value) { Write(value); return (*this); }
	ZafFile &operator<<(ZafUInt16 value) { Write(value); return (*this); }
	ZafFile &operator<<(ZafInt32 value) { Write(value); return (*this); }
	ZafFile &operator<<(ZafUInt32 value) { Write(value); return (*this); }
	ZafFile &operator<<(double value) { Write(value); return (*this); }
	ZafFile &operator<<(const ZafIChar *text) { Write(text); return (*this); }

	// The definition of ZAF_WORD_SIZE == 64 is the following:
	// 8 bit chars, 16 bit shorts, 32 bit ints, and 64 bit longs.
	// In this case, ZafInt32 is typedefed to int, rather than long, so
	// <<(int &value) is the same as <<(ZafInt32 &value).
#if (ZAF_WORD_SIZE != 64)
	ZafFile &operator<<(int value) { Write(value); return (*this); }
#endif

protected:
	ZafError error;
	ZafFileMode mode;

	ZafFile(ZafFileMode mode);
};

// --- inline functions ---
inline bool ZafFile::BinaryMode(void) const { return ((mode & ZAF_FILE_BINARY) ? true : false); }
inline bool ZafFile::Create(void) const { return ((mode & ZAF_FILE_CREATE) ? true : false); }
inline bool ZafFile::DerivedAccess(void) const { return ((mode & ZAF_FILE_DERIVED_ACCESS) ? true : false); }
inline ZafError ZafFile::Error(void) const { return (error); }
inline bool ZafFile::OpenCreate(void) const { return ((mode & ZAF_FILE_OPENCREATE) ? true : false); }
inline bool ZafFile::ReadOnly(void) const { return ((mode & ZAF_FILE_READ) ? true : false); }
inline bool ZafFile::ReadWrite(void) const { return ((mode & ZAF_FILE_READWRITE) ? true : false); }
inline ZafError ZafFile::SetError(ZafError setError) { return (error = setError); }
inline bool ZafFile::Temporary(void) const { return ((mode & ZAF_FILE_TEMPORARY) ? true : false); }
inline bool ZafFile::TextMode(void) const { return ((mode & ZAF_FILE_TEXT) ? true : false); }

// --------------------------------------------------------------------------
// ----- ZafFileSystem ------------------------------------------------------
// --------------------------------------------------------------------------

class ZAF_EXPORT ZafFileSystem : public ZafElement
{
public:
	static ZafIChar *rootDirectoryName;
	static ZafIChar *parentDirectoryName;
	static ZafIChar *currentDirectoryName;

	ZafFileSystem(void);
	virtual ~ZafFileSystem(void);

	// --- Directory Members ---
	virtual int ChDir(const ZafIChar *newPath,
		ZafStringID stringID = ZAF_NULLP(ZafIChar), ZafNumberID numberID = 0) = 0;
	virtual int FindFirst(ZafFileInfoStruct &fileInfo, const ZafIChar *searchName,
		ZafStringID stringID = ZAF_NULLP(ZafIChar), ZafNumberID numberID = 0) = 0;
	virtual int FindNext(ZafFileInfoStruct &fileInfo, const ZafIChar *searchName,
		ZafStringID stringID = ZAF_NULLP(ZafIChar), ZafNumberID numberID = 0) = 0;
	virtual int FindClose(ZafFileInfoStruct &fileInfo) = 0;
	virtual int GetCWD(ZafIChar *pathName, int pathLength) = 0;
	virtual int MkDir(const ZafIChar *pathName,
		ZafStringID stringID = ZAF_NULLP(ZafIChar), ZafNumberID numberID = 0) = 0;
	virtual int RmDir(const ZafIChar *pathName, bool deleteContents = false) = 0;

	// --- File Members ---
	virtual void Close(ZafFile *file) = 0;
	virtual ZafFile *Open(const ZafIChar *fileName, const ZafFileMode mode,
		ZafStringID stringID = ZAF_NULLP(ZafIChar), ZafNumberID numberID = 0) = 0;
	virtual int Remove(const ZafIChar *name) = 0;
	virtual int Rename(const ZafIChar *oldName, const ZafIChar *newName,
		ZafStringID stringID = ZAF_NULLP(ZafIChar), ZafNumberID numberID = 0) = 0;

	// --- Attributes & data access ---
	// get
	ZafError Error(void) const;
	// set
	ZafError SetError(ZafError error);

protected:
	// --- General class members ---
	ZafError error;
};

// --- inline functions ---
inline ZafError ZafFileSystem::Error(void) const { return (error); }
inline ZafError ZafFileSystem::SetError(ZafError setError) { return (error = setError); }

// --------------------------------------------------------------------------
// ----- ZafPathElement & ZafPath -------------------------------------------
// --------------------------------------------------------------------------

class ZAF_EXPORT ZafPathElement : public ZafElement
{
public:
	ZafPathElement(const ZafIChar *path, int length = -1);

	// --- Attributes & data access ---
	// get
	const ZafIChar *Path(void) const;
	// set
	ZafError SetPath(const ZafIChar *path, int length = -1);

	// --- Element members ---
	ZafPathElement *Next(void) const { return((ZafPathElement *)next); }
	ZafPathElement *Previous(void) const { return((ZafPathElement *)previous); }

protected:
	ZafIChar path[ZAF_MAXPATHLEN];
};

class ZAF_EXPORT ZafPath : public ZafList
{
public:
	ZafPath(const ZafIChar *pwd, bool getCwd);
	bool Load(const ZafIChar *envname);

	// --- List members ---
	virtual ZafPathElement *Add(ZafPathElement *object, ZafPathElement *position = ZAF_NULLP(ZafPathElement));
	ZafPathElement *Current(void) const { return((ZafPathElement *)current); }
	ZafPathElement *First(void) const { return((ZafPathElement *)first); }
	ZafPathElement *Get(int index) { return((ZafPathElement *)ZafList::Get(index)); }
	ZafPathElement *Last(void) const { return((ZafPathElement *)last); }
	virtual ZafPathElement *Subtract(ZafPathElement *object);

	ZafPath &operator+(ZafPathElement *object) { Add(object); return(*this); }
	ZafPath &operator-(ZafPathElement *object) { Subtract(object); return(*this); }
	ZafPathElement *operator()(int index) { return((ZafPathElement *)ZafList::Get(index)); }
};

// --- inline functions ---
inline const ZafIChar *ZafPathElement::Path(void) const { return (path); }

// --- global variable declarations ---
#if defined(USE_ZAF_SEARCH_PATH)
extern ZAF_EXPORT ZafPath *zafSearchPath;
#endif

#endif // Z_FILE_HPP

