#include <classes/DOS/files.h>

#include <exec/memory.h>
#include <string.h>

#pragma -
#include <pragma/dos_lib.h>
#include <pragma/exec_lib.h>
#pragma +

InfoDataC::InfoDataC()
	: DosObjectC(~0,AllocMem(sizeof(struct InfoData),MEMF_CLEAR))
{
}

InfoDataC::~InfoDataC()
{
	FreeMem(object(),sizeof(struct InfoData));
}

InfoDataC &InfoDataC::operator= (const InfoDataC &s)
{
	if (this != &s)
	{
		if (only())
		{
			FreeMem(object(),sizeof(struct InfoData));
		};
		DosObjectC::operator=(s);
	};
	return *this;
}

// *************************************************************


PathStringC::PathStringC(LONG initsize)
	: StringC()
{
	setBufferSize(initsize);
}

PathStringC::PathStringC(const STRPTR s)
	: StringC(s)
{
}

PathStringC::PathStringC(const PathStringC &s)
	: StringC(s)
{
}

PathStringC::~PathStringC()
{
}

PathStringC &PathStringC::operator= (const PathStringC &s)
{
	if (this != &s)
	{
		StringC::operator= (s);
	};
	return *this;
}

VOID PathStringC::setPath(STRPTR path)
{
	StringC::operator= (path);
}

VOID PathStringC::addPart(STRPTR add)
{
	if (add)
	{
		for(;;) {
			if ((BOOL) AddPart((STRPTR) buffer.buffer(),add,bufsize()))
			{
				len = strlen((STRPTR) buffer.buffer());
				return;
			};
			doubleBuffer();
		};
	};
}

VOID PathStringC::addSuffix(STRPTR suffix)
{
	if (suffix)
	{
		ULONG l = strlen(suffix) + strlen(path());
		for(;;) {
			if (l < bufsize())
			{
				strcat(path(),suffix);
				len += strlen(suffix);
				return;
			};
			doubleBuffer();
		};
	};
}

STRPTR PathStringC::filePart() const
{
	return (STRPTR) FilePart((STRPTR) this);
}

VOID PathStringC::cutBeforeFilePart()
{
	STRPTR pp = FilePart((STRPTR) this);
	if (pp)
	{
		strcpy((STRPTR) buffer.buffer(),pp);
		len = strlen((STRPTR) buffer.buffer());
	};
}

VOID PathStringC::cutBehindPathPart()
{
	STRPTR pp = PathPart((STRPTR) buffer.buffer());
	if (pp)
	{
		*pp = '\0';
		len = strlen((STRPTR) buffer.buffer());
	};
}

VOID PathStringC::cutSuffix()
{
	STRPTR pp = FilePart((STRPTR) buffer.buffer());
	if (pp)
	{
		LONG i = strlen(pp);
		while (i >= 0 && pp[i] != '.')
			i--;
		if (i >= 0)
			pp[i] = 0;
		len = strlen((STRPTR) buffer.buffer());
	};
}

// *************************************************************

FileLockC::FileLockC()
{
	filelock = NULL;
}

FileLockC::FileLockC(const FileLockC &s)
{
	if (s.filelock)
	{
		filelock = DupLock(s.filelock);
	}
	else
		filelock = NULL;
}

FileLockC::FileLockC(BPTR lock)
{
	if (lock)
		filelock = DupLock(lock);
	else
		filelock = NULL;
}

FileLockC::~FileLockC()
{
	unlock();
}

FileLockC &FileLockC::operator= (const FileLockC &s)
{
	if (this != &s)
	{
		if (filelock)
		{
			UnLock(filelock);
			filelock = NULL;
		};
		if (s.filelock)
		{
			filelock = DupLock(s.filelock);
		};
	};
	return *this;
}

BOOL FileLockC::lock(STRPTR name, LONG mode)
{
	if (!filelock)
	{
		filelock = Lock(name,mode);
 		return filelock != NULL;
	};
	return FALSE;
}

BOOL FileLockC::duplicate(FileLockC &fromLock)
{
	if (!filelock && fromLock.filelock)
	{
		filelock = DupLock(fromLock.filelock);
		return filelock != NULL;
	};
	return FALSE;
}

BOOL FileLockC::duplicate(FileHandleC &fromHandle)
{
	if (!filelock && fromHandle.handle())
	{
		filelock = DupLockFromFH(fromHandle.handle());
		return filelock != NULL;
	};
	return FALSE;
}

VOID FileLockC::unlock()
{
	if (filelock)
	{
		UnLock(filelock);
		filelock = NULL;
	};
}

BOOL FileLockC::changeMode(ULONG mode)
{
	if (filelock)
	{
		return ChangeMode(CHANGE_LOCK,filelock,mode);
	};
	return FALSE;
}

BOOL FileLockC::sameDevice(FileLockC &other) const
{
	if (filelock && other.filelock)
	{
		return SameDevice(filelock,other.filelock);
	};
	return FALSE;
}

BOOL FileLockC::sameLock(FileLockC &other) const
{
	if (filelock && other.filelock)
	{
		return SameLock(filelock,other.filelock);
	};
	return FALSE;
}

BOOL FileLockC::nameOfLock(STRPTR buffer, LONG length) const
{
	if (filelock)
	{
		return NameFromLock(filelock,buffer,length);
	};
	return FALSE;
}

BOOL FileLockC::nameOfLock(PathStringC &ps) const
{
	if (filelock)
	{
		for (;;) {
			if (NameFromLock(filelock,ps.path(),ps.bufsize()))
			{
				ps.shrinkBuffer();
				return TRUE;
			};
			if (IoErr() != ERROR_LINE_TOO_LONG)
				return FALSE;
			ps.doubleBuffer();
		};
	};
	return FALSE;
}

BOOL FileLockC::examine(struct FileInfoBlock *fib) const
{
	if (filelock && fib)
	{
		return (BOOL) Examine(filelock,fib);
	};
	return FALSE;
}

BOOL FileLockC::examine(class FileInfoBlockC &fib) const
{
	if (filelock)
	{
		return (BOOL) Examine(filelock,fib.object());
	};
	return FALSE;
}

BOOL FileLockC::info(struct InfoData *id) const
{
	if (filelock && id)
	{
		return (BOOL) Info(filelock,id);
	};
	return FALSE;
}

BOOL FileLockC::info(class InfoDataC &id) const
{
	if (filelock)
	{
		return (BOOL) Info(filelock,id.object());
	};
	return FALSE;
}

LONG FileLockC::ioErr()
{
	return IoErr();
}

// *************************************************************

DirLockC::DirLockC()
	: FileLockC()
{
}

DirLockC::DirLockC(BPTR lock)
	: FileLockC(lock)
{
}

BOOL DirLockC::create(STRPTR name)
{
	if (!filelock)
	{
		filelock = CreateDir(name);
		return filelock != NULL;
	};
	return FALSE;
}

BOOL DirLockC::parentOf(FileLockC &lock)
{
	if (!filelock && lock.filelock)
	{
		filelock = ParentDir(lock.filelock);
		if (filelock)
			return TRUE;
		return ioErr() == 0;
	};
	return FALSE;
}

BOOL DirLockC::parentOf(class FileHandleC &handle)
{
	if (!filelock && handle.handle())
	{
		filelock = ParentOfFH(handle.handle());
		if (filelock)
			return TRUE;
		return ioErr() == 0;
	};
	return FALSE;
}

BOOL DirLockC::fromCurrent()
{
	if (!filelock)
	{
		filelock = Lock("",SHARED_LOCK);
		return filelock != NULL;
	};
	return FALSE;
}

BOOL DirLockC::fromBootvolume()
{
	if (!filelock)
	{
		filelock = DupLock(NULL);
		return filelock != NULL;
	};
	return FALSE;
}

BOOL DirLockC::fromProgramDir()
{
	if (!filelock)
	{
		filelock = DupLock(GetProgramDir());
		return filelock != NULL;
	};
	return FALSE;
}

BOOL DirLockC::exAll(struct ExAllControl *eac,
	APTR buffer, ULONG bufsize, ULONG type)
{
	if (filelock && eac)
	{
		return (BOOL) ExAll(filelock,(struct ExAllData *) buffer,
			bufsize,type,eac);
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return FALSE;
}

BOOL DirLockC::exAll(ExAllControlC &eac,
	APTR buffer, ULONG bufsize, ULONG type)
{
	if (filelock)
	{
		return (BOOL) ExAll(filelock,(struct ExAllData *) buffer,
			bufsize,type,eac.object());
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return FALSE;
}

VOID DirLockC::exAllEnd(struct ExAllControl *eac,
	APTR buffer, ULONG bufsize, ULONG type)
{
	if (filelock && eac)
	{
		ExAllEnd(filelock,(struct ExAllData *) buffer,
			bufsize,type,eac);
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
}

VOID DirLockC::exAllEnd(ExAllControlC &eac,
	APTR buffer, ULONG bufsize, ULONG type)
{
	if (filelock)
	{
		ExAllEnd(filelock,(struct ExAllData *) buffer,
			bufsize,type,eac.object());
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
}

BOOL DirLockC::exNext(struct FileInfoBlock *fib)
{
	if (filelock && fib)
	{
		return (BOOL) ExNext(filelock,fib);
	};
	return FALSE;
}

BOOL DirLockC::exNext(FileInfoBlockC &fib)
{
	if (filelock)
	{
		return (BOOL) ExNext(filelock,fib.object());
	};
	return FALSE;
}

// *************************************************************

CurrentDirC::CurrentDirC()
{
	BPTR fl = Lock("",SHARED_LOCK);
	if (fl)
	{
		filelock = CurrentDir(fl);
	};
}

CurrentDirC::CurrentDirC(STRPTR name)
{
	BPTR fl;
	if (name)
		fl = Lock(name,SHARED_LOCK)
	else
		fl = Lock("",SHARED_LOCK);
	if (fl)
	{
		filelock = CurrentDir(fl);
	};
}

CurrentDirC::~CurrentDirC()
{
	if (filelock)
		UnLock(CurrentDir(filelock));
}

BOOL CurrentDirC::makeCurrent(DirLockC &s)
{
	BPTR fl;
	if (s.lock() && filelock)
	{
		if (fl = DupLock(s.lock()))
		{
			UnLock(CurrentDir(fl));
			return TRUE;
		};
	};
	return FALSE;
}

// *************************************************************

FileHandleC::FileHandleC()
{
	filehandle = NULL;
}

FileHandleC::FileHandleC(const FileHandleC &s)
{
	BPTR fl;
	filehandle = NULL;
	if (s.filehandle)
	{
		if (fl = DupLockFromFH(s.filehandle))
		{
			if (!(filehandle = OpenFromLock(fl)))
			{
				UnLock(fl);
			};
		};
	};
}

FileHandleC::~FileHandleC()
{
	close();
}

FileHandleC &FileHandleC::operator= (const FileHandleC &s)
{
	if (this != &s)
	{
		BPTR fl;
		close();
		filehandle = NULL;
		if (s.filehandle)
		{
			if (fl = DupLockFromFH(s.filehandle))
			{
				if (!(filehandle = OpenFromLock(fl)))
				{
					UnLock(fl);
				};
			};
		};
	};
	return *this;
}

BOOL FileHandleC::open(STRPTR name, LONG mode)
{
	if (!filehandle)
	{
		filehandle = Open(name,mode);
		return filehandle != NULL;
	};
	return FALSE;
}

BOOL FileHandleC::open(FileLockC &lock)
{
	if (!filehandle && lock.isLocked())
	{
		BPTR fl;
		if (fl = DupLock(lock.lock()))
		{
			if (!(filehandle = OpenFromLock(fl)))
			{
				UnLock(fl);
			};
			return filehandle != NULL;
		};
	};
	return FALSE;
}

BOOL FileHandleC::close()
{
	if (filehandle)
	{
		BOOL retval;
		retval = Close(filehandle);
		filehandle = NULL;
		return retval;
	};
	return FALSE;
}

BOOL FileHandleC::changeMode(ULONG mode)
{
	if (filehandle)
	{
		return (BOOL) ChangeMode(CHANGE_FH,filehandle,mode);
	};
	return FALSE;
}

LONG FileHandleC::read(APTR buffer, LONG length)
{
	if (filehandle)
	{
		return Read(filehandle,buffer,length);
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return -1;
}

LONG FileHandleC::write(APTR buffer, LONG length)
{
	if (filehandle)
	{
		return Write(filehandle,buffer,length);
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return -1;
}

LONG FileHandleC::seek(LONG position, LONG mode)
{
	if (filehandle)
	{
		Seek(filehandle,position,mode);
	};
	SetIoErr(ERROR_SEEK_ERROR);
	return -1;
}

BOOL FileHandleC::eof()
{
	if (filehandle)
	{
		ULONG s = Seek(filehandle,0,OFFSET_CURRENT);
		if (examine(fib))
		{
			if (fib.object()->fib_DirEntryType == ST_FILE ||
				fib.object()->fib_DirEntryType == ST_LINKFILE)
			{
				return s == fib.object()->fib_Size;
			};
		};
	};
	return FALSE;
}

LONG FileHandleC::fGetC()
{
	if (filehandle)
	{
		return FGetC(filehandle);
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return -1;
}

BOOL FileHandleC::fGets(STRPTR s, ULONG len)
{
	if (filehandle)
	{
		return FGets(filehandle,s,len) != NULL;

	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return FALSE;
}

BOOL FileHandleC::fPutC(ULONG c)
{
	if (filehandle)
	{
		return FPutC(filehandle,c) != -1;
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return FALSE;
}

BOOL FileHandleC::fPuts(STRPTR s)
{
	if (filehandle)
	{
		return (BOOL) !FPuts(filehandle,s);
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return FALSE;
}

ULONG FileHandleC::fRead(APTR buffer, ULONG len, ULONG blocks)
{
	if (filehandle)
	{
		return FRead(filehandle,buffer,len,blocks);
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return 0;
}

ULONG FileHandleC::fWrite(APTR buffer, ULONG len, ULONG blocks)
{
	if (filehandle)
	{
		return FWrite(filehandle,buffer,len,blocks);
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return 0;
}

LONG FileHandleC::fPrintF(STRPTR s, LONG *args)
{
	if (filehandle)
	{
		return VFPrintf(filehandle, s, args);
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return -1;
}

LONG FileHandleC::fPrintF(STRPTR s, ...)
{
	if (filehandle)
	{
		return VFPrintf(filehandle, s, (LONG *) (((ULONG) &s) + 4));
	};
	SetIoErr(ERROR_REQUIRED_ARG_MISSING);
	return -1;
}

VOID FileHandleC::fWriteF(STRPTR s, LONG *args)
{
	if (filehandle)
	{
		VFWritef(filehandle, s, args);
	};
}

VOID FileHandleC::fWriteF(STRPTR s, ...)
{
	if (filehandle)
	{
		VFWritef(filehandle, s, (LONG *) (((ULONG) &s) + 4));
	};
}

VOID FileHandleC::unGetC(LONG c)
{
	if (filehandle)
	{
		UnGetC(filehandle,c);
	};
}

BOOL FileHandleC::flush()
{
	if (filehandle)
	{
		return Flush(filehandle);
	};
	return FALSE;
}

BOOL FileHandleC::setVBuf(APTR buffer, LONG mode, LONG bufsize)
{
	if (filehandle)
	{
		return !((BOOL) SetVBuf(filehandle,(char *) buffer, mode, bufsize));
	};
	return FALSE;
}

BOOL FileHandleC::waitForChar(ULONG micros)
{
	if (filehandle)
	{
		return WaitForChar(filehandle,micros);
	};
	return FALSE;
}

BOOL FileHandleC::isInteractive()
{
	if (filehandle)
	{
		return IsInteractive(filehandle);
	};
	return FALSE;
}

BOOL FileHandleC::nameOfHandle(STRPTR buffer, LONG length) const
{
	if (filehandle)
	{
		return NameFromFH(filehandle, buffer, length);
	};
	return FALSE;
}

BOOL FileHandleC::nameOfHandle(PathStringC &ps) const
{
	if (filehandle)
	{
		for (;;) {
			if (NameFromFH(filehandle, ps.path(),ps.bufsize()))
			{
				ps.shrinkBuffer();
				return TRUE;
			};
			if (IoErr() != ERROR_LINE_TOO_LONG)
				return FALSE;
			ps.doubleBuffer();
		};
	};
	return FALSE;
}

BOOL FileHandleC::examine(struct FileInfoBlock *fib) const
{
	if (filehandle && fib)
	{
		return (BOOL) ExamineFH(filehandle,fib);
	};
	return FALSE;
}

BOOL FileHandleC::examine(class FileInfoBlockC &fib) const
{
	if (filehandle)
	{
		return (BOOL) ExamineFH(filehandle,fib.object());
	};
	return FALSE;
}

LONG FileHandleC::setSize(LONG offset, LONG mode)
{
	if (filehandle)
	{
		return SetFileSize(filehandle,offset,mode);
	};
	return -1;
}

// *************************************************************

InputHandleC::InputHandleC()
{
	filehandle = Input();
}

InputHandleC::~InputHandleC()
{
	close();
}

BOOL InputHandleC::close()
{
	filehandle = NULL;
	return FALSE;
}

// *************************************************************

OutputHandleC::OutputHandleC()
{
	filehandle = Output();
}

OutputHandleC::~OutputHandleC()
{
	close();
}

BOOL OutputHandleC::close()
{
	filehandle = NULL;
	return FALSE;
};

// *************************************************************
