//---------------------------------------------------------------------------
//	Video editor
//  2004 - 2007 Stanislav Sumec <sumec@fit.vutbr.cz>
//  Brno University of Technology
//  Faculty of Information Technology
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include <iostream>
#ifdef __BORLANDC__
#include <SyncObjs.hpp>
#endif
#pragma hdrstop
#include "WindowsMM.h"
#pragma package(smart_init)

#if !defined(_WIN32) && !defined(WIN32)
#define HGLOBAL
#define GlobalAlloc(Empty, Size) ((void*)(new char[Size]))
#define GlobalFree(Ptr) delete[] (char*)Ptr
#endif

//---------------------------------------------------------------------------
TWindowsMM::TWindowsMM()
{
#ifdef __BORLANDC__
	CS = new TCriticalSection();
#endif
}

//---------------------------------------------------------------------------
TWindowsMM::~TWindowsMM()
{
	if (!UsedBlocks.empty())
	{
#ifdef __BORLANDC__
		MessageBox(NULL, "Unallocated memory!", "Warning", MB_OK | MB_ICONWARNING);
#else
		std::cerr<<"Unallocated memory!"<<std::endl;
#endif
	}
	for (TBlocks::iterator i = FreeBlocks.begin(); i != FreeBlocks.end(); i++)
	{
		GlobalFree(HGLOBAL(i->Address));
	}
	for (TBlocks::iterator i = UsedBlocks.begin(); i != UsedBlocks.end(); i++)
	{
		GlobalFree(HGLOBAL(i->Address));
	}
#ifdef __BORLANDC__
	delete CS;
#endif
}

//---------------------------------------------------------------------------
void* TWindowsMM::GetMem(size_t Size)
{
#ifdef __BORLANDC__
	CS->Enter();
#endif
	for (TBlocks::iterator i = FreeBlocks.begin(); i != FreeBlocks.end(); i++)
	{
		if (i->Size == Size)
		{
			UsedBlocks.push_back(*i);
			FreeBlocks.erase(i);
			void *Address = UsedBlocks.back().Address;
#ifdef __BORLANDC__
			CS->Leave();
#endif
			return Address;
		}
	}
	TBlock Block;
	Block.Address = (void*)GlobalAlloc(GMEM_FIXED, Size);
	Block.Size = Size;
	UsedBlocks.push_back(Block);
#ifdef __BORLANDC__
	CS->Leave();
#endif
	return Block.Address;
}

//---------------------------------------------------------------------------
void TWindowsMM::FreeMem(void *Mem)
{
#ifdef __BORLANDC__
	CS->Enter();
#endif
	for (TBlocks::iterator i = UsedBlocks.begin(); i != UsedBlocks.end(); i++)
	{
		if (i->Address == Mem)
		{
			FreeBlocks.push_back(*i);
			UsedBlocks.erase(i);
			break;
		}
	}
#ifdef __BORLANDC__
	CS->Leave();
#endif
}

//---------------------------------------------------------------------------
void TWindowsMM::GC()
{
#ifdef __BORLANDC__
	CS->Enter();
#endif
	for (TBlocks::iterator i = FreeBlocks.begin(); i != FreeBlocks.end(); i++)
	{
		GlobalFree(HGLOBAL(i->Address));
	}
	FreeBlocks.clear();
#ifdef __BORLANDC__
	CS->Leave();
#endif
}

