/*

LMEM v0.03

TODO: Lots more error checking... :)  (ie. SOME)
TODO: Better main array than fixed 1024 entry one :)

LMEM v0.03

Added type:
  Heap

LMEM v0.02

Supported types:
  Lookup

LOOKUP

Stores DWORDS which can be accessed by handle.
Can be used to assign handles which can be associated with moveable data structures.


*/

#ifndef __INCLUDE_LMEM003
#define __INCLUDE_LMEM003

#include <windows.h>



//---- FUNCTION PROTOS & TYPES (Stuff to go in header) -----------------------//

typedef DWORD LMEM_HANDLE;

typedef LMEM_HANDLE LMEM_LOOKUP_HANDLE;
typedef LMEM_HANDLE LMEM_HEAP_HANDLE;

#define LMEM_ERROR -1



//---- DATA ------------------------------------------------------------------//

HANDLE lmem_heap;

LPVOID lmem_item_p[1024];



//---- MAIN FUNCTIONS (Pivate) -----------------------------------------------//

LPVOID LMem_GetPtr(LMEM_HANDLE h) {
  return lmem_item_p[h];
}

void LMem_SetPtr(LMEM_HANDLE h, LPVOID p) {
  lmem_item_p[h] = p;
}

LMEM_HANDLE LMem_AllocHandle() {
  int i;
  for(i=0; i<1024 && lmem_item_p[i]; i++);
  lmem_item_p[i] = (LPVOID)0xFFFFFFFF;
  if(i == 1024) i = LMEM_ERROR;
  return i;
}

void LMem_FreeHandle(LMEM_HANDLE h) {
  lmem_item_p[h] = NULL;
}



//---- LMEM_LOOKUP -----------------------------------------------------------//

typedef struct {
  DWORD handle, value;
} LMEM_LOOKUP_NODE, *LMEM_LOOKUP_PNODE;

typedef struct {
  UINT num, size;
  UINT g_alloc, g_free;
  LMEM_LOOKUP_NODE pair[1];
} LMEM_LOOKUP_HEADER, *LMEM_LOOKUP_PHEADER;



LMEM_HANDLE LMem_Lookup_Create() {
  UINT g_alloc = 256, g_free = 512;
  LMEM_LOOKUP_PHEADER p;
  LMEM_HANDLE h;
  int i;

  h = LMem_AllocHandle();

  p = (LMEM_LOOKUP_PHEADER)HeapAlloc(lmem_heap, 0, g_alloc*sizeof(LMEM_LOOKUP_NODE)+sizeof(LMEM_LOOKUP_HEADER));

  p->num = 0;
  p->g_alloc = g_alloc;
  p->size = p->g_alloc;
  p->g_free = g_free;

  for(i=0; i<p->size; i++) p->pair[i].handle = -1;

  LMem_SetPtr(h, p);
  return h;
}



void LMem_Lookup_Destroy(LMEM_HANDLE h) {
  HeapFree(lmem_heap, 0, LMem_GetPtr(h));
  LMem_FreeHandle(h);
}



LMEM_LOOKUP_HANDLE LMem_Lookup_Alloc(LMEM_HANDLE lookup, DWORD value) {

  LMEM_LOOKUP_PHEADER p = (LMEM_LOOKUP_PHEADER)LMem_GetPtr(lookup);
  int i, j;

  for(i=0; i<p->size && p->pair[i].handle != -1; i++);

  if(i >= p->size) {
    p->size += p->g_alloc;
    p = (LMEM_LOOKUP_PHEADER)HeapReAlloc(lmem_heap, 0, (LPVOID)p, p->size*sizeof(LMEM_LOOKUP_NODE)+sizeof(LMEM_LOOKUP_HEADER));
    LMem_SetPtr(lookup, p);
    for(j=i; j<p->size; j++) p->pair[j].handle = -1;
  }

  p->pair[i].handle = i;
  p->pair[i].value = value;

  return i;
}



void LMem_Lookup_Set(LMEM_HANDLE lookup, LMEM_LOOKUP_HANDLE item, DWORD value) {
  LMEM_LOOKUP_PHEADER p = (LMEM_LOOKUP_PHEADER)LMem_GetPtr(lookup);
  p->pair[item].value = value;
}



DWORD LMem_Lookup_Get(LMEM_HANDLE lookup, LMEM_LOOKUP_HANDLE item) {
  LMEM_LOOKUP_PHEADER p = (LMEM_LOOKUP_PHEADER)LMem_GetPtr(lookup);
  return p->pair[item].value;
}



LMem_Lookup_Free(LMEM_HANDLE lookup, LMEM_LOOKUP_HANDLE item) {
  LMEM_LOOKUP_PHEADER p = (LMEM_LOOKUP_PHEADER)LMem_GetPtr(lookup);
  p->pair[item].handle = -1;
}



//---- LMEM_HEAP -------------------------------------------------------------//

LMEM_HANDLE LMem_Heap_Create() {
  return LMem_Lookup_Create();
}



void LMem_Heap_Destroy(LMEM_HANDLE h) {
  int i;
  LMEM_LOOKUP_PHEADER p = (LMEM_LOOKUP_PHEADER)LMem_GetPtr(h);

  for(i=0; i<p->size; i++)
    if(p->pair[i].handle != -1)
      HeapFree(lmem_heap, 0, (LPVOID)p->pair[i].value);
  
  LMem_Lookup_Destroy(h);
}



LPVOID LMem_Heap_GetPtr(LMEM_HANDLE heap, LMEM_HEAP_HANDLE item) {
  return (LPVOID)LMem_Lookup_Get(heap, item);
}



LMEM_HEAP_HANDLE LMem_Heap_Alloc(LMEM_HANDLE heap, UINT size) {
  LPVOID p;
  p = HeapAlloc(lmem_heap, 0, size);
  return LMem_Lookup_Alloc(heap, (DWORD)p);
}



LPVOID LMem_Heap_ReAlloc(LMEM_HANDLE heap, LMEM_HEAP_HANDLE item, UINT size) {
  LPVOID p = LMem_Heap_GetPtr(heap, item);
  p = HeapReAlloc(lmem_heap, 0, p, size);
  LMem_Lookup_Set(heap, item, (DWORD)p);
  return p;
}



void LMem_Heap_Free(LMEM_HANDLE heap, LMEM_HEAP_HANDLE item) {
  LPVOID p = LMem_Heap_GetPtr(heap, item);
  HeapFree(lmem_heap, 0, p);
  LMem_Lookup_Free(heap, item);
}



//---- INITIALISATION --------------------------------------------------------//

/*
BOOL LMem_Startup();
BOOL LMem_Shutdown();
*/



//---- Data

int lmem_startup_count = 0;



//---- LMem_Startup

BOOL LMem_Startup() {
  int i;

  if(!lmem_startup_count) {
    for(i=0; i<1024; i++) lmem_item_p[i] = NULL;
    lmem_heap = GetProcessHeap();
  }

  lmem_startup_count++;
  return TRUE;
}



//---- LMem_Shutdown

//  TODO: Free any blocks which are still allocated

BOOL LMem_Shutdown() {
  if(!lmem_startup_count) return TRUE;
  lmem_startup_count--;
  return (lmem_startup_count == 0);
}



//---- END OF CODE -----------------------------------------------------------//

#endif



