/*
	Twilight Prophecy 3D/Multimedia SDK
	A multi-platform development system for virtual reality and multimedia.

	Copyright (C) 1997-2001 by Twilight 3D Finland Oy Ltd.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

	Please read the file LICENSE.TXT for additional details.


	source:
		memorystream implementation

	revision history:
		Mar/19/2001 - Jukka Liimatta - initial revision
*/
#include <prcore/prcore.hpp>
using namespace prcore;



MemoryStream::MemoryStream()
: mOffset(0), mSize(0), mMaxSize(0), mData(NULL)
{
}


MemoryStream::MemoryStream(int size)
: mOffset(0), mSize(size), mMaxSize(size), mData(NULL)
{
	mData = new uint8[ size ];
}


MemoryStream::MemoryStream(uint8* data, int size)
: mOffset(0), mSize(size), mMaxSize(size), mData(data)
{
}


MemoryStream::MemoryStream(const char* filename)
: mOffset(0), mSize(0), mMaxSize(0), mData(NULL)
{
	FileStream file(filename);

	mSize = file.GetSize();
	mMaxSize = mSize;
	mData = new uint8[ mSize ];
	file.Read(mData,mSize);
}


MemoryStream::~MemoryStream()
{
	if ( mData )
		delete[] mData;
}


int MemoryStream::Seek(int delta, SeekMode mode)
{
	switch( mode )
	{
		case START:		mOffset = delta; break;
		case CURRENT:	mOffset += delta; break;
		case END:		mOffset = mSize - delta; break;
	}
	return mOffset;
}


int MemoryStream::Read(void* target, int bytes)
{
	int overflow = mOffset + bytes - mSize;//todo
	if ( overflow > 0 )
	{
		bytes -= overflow;
		if ( bytes < 1 ) 
			return 0;
	}

	memcpy(target,mData+mOffset,bytes);
	mOffset += bytes;
	return bytes;
}


int MemoryStream::Write(const void* source, int bytes)
{
	if ( bytes < 1 )
		return 0;

	// overflow?
	if ( (mOffset+bytes) > mMaxSize )
	{
		int size = (int)(mMaxSize * 1.25 + bytes);
		uint8* data = new uint8[ size ];

		if ( mData )
		{
			memcpy(data,mData,mSize);
			delete[] mData;
		}

		mMaxSize = size;
		mData = data;
	}

	// append source data
	memcpy(mData+mOffset,source,bytes);
	mOffset += bytes;

	// adjust size
	if ( mOffset > mSize )
		mSize = mOffset;

	return bytes;
}


int MemoryStream::GetOffset() const
{
	return mOffset;
}


int MemoryStream::GetSize() const
{
	return mSize;
}


bool MemoryStream::IsOpen() const
{
	return true;
}


bool MemoryStream::IsEOS() const
{
	return mOffset >= mSize;
}


uint8* MemoryStream::GetData() const
{
	return mData;
}
