#include "global.h"
#include "cmemory.h"
#include <process.h>
#include <stdlib.h>
#include <strsafe.h>

DWORD memorySize=0, maxMemorySize=0;

#ifdef _DEBUG
	//pocet alokacii pamate
	DWORD _mem_new_ = 0;//dynamicky pomocou operatora new
	DWORD _mem_alloc_ = 0;//pomocou funkcie malloc
	DWORD _mem_cmemory_ = 0;//pomoocu triedy CMemory
#endif

void *mallocx(size_t size)
{
#ifdef _DEBUG
	_mem_alloc_++;
#endif
	return malloc(size);
}

void freex(void* mem)
{
#ifdef _DEBUG
	if (!mem)
		::MessageBox(::GetActiveWindow(), "Pokus o uvoľnenie nulového pointera pomocou funkcie free", "freex", MB_ICONSTOP|MB_OK);
	_mem_alloc_--;
#endif
	free(mem);
}

char *CMemory::printstr(char *src, ...)
{

	va_list valist; va_start(valist, src);

	DWORD size = 10;
	while (true)
	{
		char *mem = _NEW(char[size]);
		HRESULT hr = StringCbVPrintf(mem, size, src, valist);
		if (SUCCEEDED(hr))
			return mem;
		if (hr == STRSAFE_E_INSUFFICIENT_BUFFER)
		{
			size += MEMORY_ALLOC_UNIT;//este vacsiu pamat potrebujeme
			_DELETE(mem);
		}
		else
			app.memory_error(size);
	}
}

void* CMemory::GetPointer()
{
	//return lockedMem;
	return mem;
}

void CMemory::ClearMemory()
{
	size = 0;
	//::ZeroMemory(lockedMem, allocsize);
	::ZeroMemory(mem, allocsize);
}

CMemory::CMemory()
{
//	if (!(mem = ::HeapAlloc(app.heap, HEAP_ZERO_MEMORY, MEMORY_ALLOC_UNIT)))
/*	if (app.mainWindow)
		if (app.mainWindow->GetOutputWindow())
			DEBUGPRINT("before");*/
	mem = mallocx(MEMORY_ALLOC_UNIT);
	
/*	if (app.mainWindow)
		if (app.mainWindow->GetOutputWindow())
			DEBUGPRINT("after");*/
/*	if (!(mem = ::GlobalAlloc(GHND, MEMORY_ALLOC_UNIT)))
	{
		app.memory_error(0);
	}

	if (!(lockedMem = ::GlobalLock(mem)))
	{
		::MessageBox(0, "GlobalLock", "CMemory::CMemory()", MB_OK);
		app.memory_error(0);
	}
*/
	::ZeroMemory(mem, MEMORY_ALLOC_UNIT);
	memorySize += MEMORY_ALLOC_UNIT;
	if (memorySize>maxMemorySize)
		maxMemorySize=memorySize;

	size = 0;
	allocsize = MEMORY_ALLOC_UNIT;
	//allocsize = ::HeapSize(app.heap, 0, mem);
	//allocsize = ::GlobalSize(mem);
#ifdef _DEBUG
	_mem_cmemory_++;
#endif
}

CMemory::~CMemory()
{
	if (mem)
	{
		/*if (!(::GlobalUnlock(mem)))
		{
			//globalunlock hodil 0 ale last error hodil tiez nulu. ????????
			if (::GetLastError())
			{
				::MessageBox(0, "GlobalUnlock", "CMemory::~CMemory", MB_ICONSTOP|MB_OK);
				app.memory_error(0);
			}
		}*/
		//if (!::HeapFree(app.heap, 0, mem))
		freex(mem);
/*		if (::GlobalFree(mem))
#ifdef _DEBUG
		{
			::GetLastError();
			::MessageBox(0, "GlobalFree", "CMemory::~CMemory", MB_ICONSTOP|MB_OK);
		}*/
#ifdef _DEBUG
		_mem_cmemory_--;
#else
		;
#endif
		memorySize -= allocsize;
	}
}

void CMemory::DeleteData()
{
	size = 0;
	//((char*)mem)[0] = 0;
}

int CMemory::AddData(void* data, DWORD sz)
{
	if (!sz)
		return size;

	if (sz == -1)
		sz = strlen((char*)data);

	if (size + sz>allocsize)
	{
		DWORD newallocsize = ((size+sz)/MEMORY_ALLOC_UNIT + 1)*MEMORY_ALLOC_UNIT;
		void * newmem;
		newmem = realloc(mem, newallocsize);
		::ZeroMemory(PBYTE(DWORD(newmem))+size,newallocsize-size);
		//if (!(newmem = GlobalReAlloc(mem, newallocsize, GMEM_MOVEABLE|GMEM_ZEROINIT)))
		/*if (!(newmem = HeapReAlloc(app.heap, HEAP_ZERO_MEMORY, mem, newallocsize)))//alokuj pamat
		{
			::GetLastError();
			//::HeapFree(app.heap, 0, mem);
			::GlobalUnlock(mem);
			::GlobalFree(mem);
#ifdef _DEBUG
			::MessageBox(0, "GlobalReAlloc", "CMemory::AddData", MB_ICONSTOP|MB_OK);
#endif
			app.memory_error(0);
		}*/
		memorySize = memorySize-allocsize;
		if (memorySize>maxMemorySize)
			maxMemorySize=memorySize;
		mem = newmem;
		/*if (!(lockedMem = ::GlobalLock(mem)))
		{
			::MessageBox(0, "GlobalLock", "CMemory::CMemory()", MB_OK);
			app.memory_error(0);
		}*/
		//allocsize = ::HeapSize(app.heap, 0, mem);//skutocna velkost alokovanej pamate
		//allocsize = ::GlobalSize(mem);
		allocsize = newallocsize;
		memorySize = memorySize+allocsize;
	}
	if (data) //len ak su data, tak skopiruj
		//::CopyMemory(PBYTE(DWORD(lockedMem)+size), data, sz);
		::CopyMemory(PBYTE(DWORD(mem)+size), data, sz);
	size+= sz;
	return (size-sz);
}

DWORD CMemory::GetSize()
{
	//vrati velkost realne pouzitej pamate
	return size;
}