/*==LICENSE==*

CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011  Cyan Worlds, Inc.

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 3 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, see <http://www.gnu.org/licenses/>.

You can contact Cyan Worlds, Inc. by email legal@cyan.com
 or by snail mail at:
      Cyan Worlds, Inc.
      14617 N Newport Hwy
      Mead, WA   99021

*==LICENSE==*/
#include "plStreamLogger.h"
#include "hsExceptions.h"

#ifdef STREAM_LOGGER

//
// Base Stream Logger
//

void plStreamLogger::LogEntry(plGenericType::Types type, unsigned int size, void* value, const char* desc)
{
	if (fList)
	{
		plGenericVar var(desc);
		var.Value().SetVar(type,size,value);
		Event e(Event::kValue,size,var);
		fList->push_back(e);
		fEntryWaiting = false;
	}
}

void plStreamLogger::ILogEntryWaiting()
{
	fEntryWaiting = true;
}

bool plStreamLogger::IsLogEntryWaiting()
{
	return fEntryWaiting;
}

//
// Read-Only Logging Stream
//

void hsReadOnlyLoggingStream::LogStringString(const char* s)
{
	if (fList)
	{
		plGenericVar var;

		var.SetName(s);
		fList->push_back(Event(Event::kString,0,var));
	}
}

void hsReadOnlyLoggingStream::LogSubStreamStart(const char* desc)
{
	if (fList)
	{
		plGenericVar var;
		if (!fDescStack.empty())
		{
			var.SetName(fDescStack.front().c_str());
			fDescStack.pop_front();
		}
		else
			var.SetName(desc);
		fList->push_back(Event(Event::kSubStart,0,var));
	}
}

void hsReadOnlyLoggingStream::LogSubStreamEnd()
{
	if (fList)
	{
		plGenericVar var;
		fList->push_back(Event(Event::kSubEnd,0,var));
	}
}

void hsReadOnlyLoggingStream::LogSubStreamPushDesc(const char* desc)
{
	fDescStack.push_back(std::string(desc));
}

void hsReadOnlyLoggingStream::Rewind()
{
	hsThrow( "can't rewind a logging stream");
}

void hsReadOnlyLoggingStream::FastFwd()
{
	hsThrow( "can't fast forward a logging stream");
}

void hsReadOnlyLoggingStream::SetPosition(UInt32 position)
{
	hsThrow( "can't set position on a logging stream");
}

void hsReadOnlyLoggingStream::Skip(UInt32 deltaByteCount)
{
	hsReadOnlyStream::Skip(deltaByteCount);
	if (deltaByteCount > 0 && !IsLogEntryWaiting())
	{
		LogEntry(plGenericType::kNone,deltaByteCount,nil,"Unknown Skip");
	}
}

UInt32 hsReadOnlyLoggingStream::Read(UInt32 byteCount, void * buffer)
{
	UInt32 ret = hsReadOnlyStream::Read(byteCount,buffer);
	if (ret > 0 && !IsLogEntryWaiting())
	{
		LogEntry(plGenericType::kNone,byteCount,nil,"Unknown Read");
	}

	return ret;
}


void hsReadOnlyLoggingStream::LogSkip(UInt32 deltaByteCount, const char* desc)
{
	ILogEntryWaiting();
	Skip(deltaByteCount);
	if (deltaByteCount > 0)
	{
		LogEntry(plGenericType::kNone,deltaByteCount,nil,desc);
	}
}

UInt32 hsReadOnlyLoggingStream::LogRead(UInt32 byteCount, void * buffer, const char* desc)
{
	ILogEntryWaiting();
	UInt32 ret = Read(byteCount,buffer);
	if (ret > 0)
	{
		LogEntry(plGenericType::kNone,byteCount,nil,desc);
	}

	return ret;
}
char *hsReadOnlyLoggingStream::LogReadSafeString()
{
	LogSubStreamStart("push me");
	UInt16 numChars; 
	LogReadSwap(&numChars,"NumChars");

	numChars &= ~0xf000; // XXX: remove when hsStream no longer does this.
	if (numChars > 0)
	{		
		char *name = TRACKED_NEW char[numChars+1];
		ILogEntryWaiting();
		UInt32 ret = Read(numChars, name);
		name[numChars] = '\0';
		if (ret > 0)
		{
			LogEntry(plGenericType::kString,ret,name,"Value");
		}
		LogSubStreamEnd();
		return name;
	}
	LogSubStreamEnd();
	return nil;
}

char *hsReadOnlyLoggingStream::LogReadSafeStringLong()
{
	LogSubStreamStart("push me");
	UInt32 numChars; 
	LogReadSwap(&numChars,"NumChars");
	if (numChars > 0)
	{
		char *name = TRACKED_NEW char[numChars+1];
		ILogEntryWaiting();
		UInt32 ret = Read(numChars, name);
		name[numChars] = '\0';
		if (ret > 0)
		{
			LogEntry(plGenericType::kString,ret,name,"Value");
		}
		LogSubStreamEnd();
		return name;
	}
	LogSubStreamEnd();
	return nil;
}
#endif