/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


		#include "io_archive/io_archive.h"
		#include "log/log.h"

		using namespace GS::IO;


//------------------------------------------------------------------------------
uint			Archive::GetCaps() const
{	return CanSeek | CanRead | IsCaseSensitive;		}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
Handle			*Archive::Open(const char *uri, Mode mode)
{
	if	(mode == ModeRead)
		if	(ArchiveEntry *e = archive.Exists(uri))
		{
			AutoPtr <ArchiveHandle> h(new ArchiveHandle(this));
			if	(!h->data.Allocate(e->length) || !archive.FileRead(uri, (void *)h->data.c_ptr()))
				return NULL;
			return h.Detach();
		}
	return NULL;
}
void			Archive::Close(Handle *) {}
bool			Archive::Delete(const char *) { return false; }

size_t			Archive::Tell(Handle *h)
{
	if	(ArchiveHandle *_h = (ArchiveHandle *)h)
		return _h->cursor;
	return (size_t)-1;	
}
size_t			Archive::Seek(Handle *h, ptrdiff_t offset, SeekRef seek_ref)
{
	if	(ArchiveHandle *_h = (ArchiveHandle *)h)
	{
		switch (seek_ref)
		{
			case SeekStart:
				_h->cursor = Types::Clamp <ptrdiff_t> (offset, 0, _h->data.GetSize());
				break;
			case SeekCurrent:
				_h->cursor = Types::Clamp <ptrdiff_t> (_h->cursor + offset, 0, _h->data.GetSize());
				break;
			case SeekEnd:
				_h->cursor = Types::Clamp <ptrdiff_t> (_h->data.GetSize() - offset, 0, _h->data.GetSize());
				break;
		}
		return _h->cursor;
	}
	return (size_t)-1;
}

size_t			Archive::Read(Handle *h, void *ptr, size_t size)
{
	size_t	read_size = 0;
	if	(ArchiveHandle *_h = (ArchiveHandle *)h)
	{
		read_size = Types::Min <ptrdiff_t> (size, _h->data.GetSize() - _h->cursor);
		GS::Memory::Copy(ptr, &_h->data[(int)_h->cursor], read_size);
		_h->cursor += read_size;
	}
	return read_size;
}
size_t			Archive::Write(Handle *, const void *, size_t size)
{	return 0;	}
//------------------------------------------------------------------------------

Archive::Archive(const char *uri, const char *index_uri)
{
	if	((connected = archive.OpenRead(uri, index_uri)) == false)
		__LOG_E__ << "Failed to connect filesystem to archive '" << uri << "'.\n";
}
