#include <types.h>
#include <stdio.h>
#include "heap.h"
#include "mmio.h"
#include "emu.h"
#include "R4300i.h"

int CurrentSize;
int OrderOk;
N64Event N64EventArray[EVENT_HEAP_SIZE];

extern "C"
{
    ulong N64EventArray1Ptr;        // Pre-calced pointer to N64EventArray[1].Time
};

void EventHeapInsert(__int64 TheEventTime, void (_cdecl *TheEventAction)(void))
{

//char str[60];
//sprintf(str,"HeapAdd: %ld = EventTime, %d = HeapSize",TheEventTime,CurrentSize);
//Log(TYPE_WRITE, str, 0);

	if (TheEventTime < c0reg.Count)
		TheEventTime = c0reg.Count;

	CurrentSize++;
	N64EventArray[CurrentSize].Time = TheEventTime;
	N64EventArray[CurrentSize].Action = TheEventAction;

	if(TheEventTime > N64EventArray[CurrentSize/2].Time)	
		return;

	//Percolate up
	int Hole = CurrentSize;
	if(CurrentSize>EVENT_HEAP_SIZE)
	{
		//MessageBox(NULL,"N64 Event Heap too small.","DEATH",MB_OK);
		return;
	}
	for(; TheEventTime<N64EventArray[Hole/2].Time; Hole/=2)
	{
		N64EventArray[Hole]=N64EventArray[Hole/2];
	}
	N64EventArray[Hole].Time=TheEventTime;
	N64EventArray[Hole].Action=TheEventAction;
}


__int64 EventHeapFindMinTime()
{
	return N64EventArray[1].Time;
}

void *EventHeapFindMinAction()		//Return the action for top of heap
{
	return N64EventArray[1].Action;
}

void EventHeapDeleteMin()
{
	if(CurrentSize==0)
	{
		return;
	}
	N64EventArray[1] = N64EventArray[CurrentSize--];
	EventHeapPercolateDown(1);
}

void EventHeapDeleteAction(void (_cdecl *TheEventAction)(void))      //Remove Event with a certain action
{
	for(int i=1; i<=CurrentSize;i++)
	{
		if(N64EventArray[i].Action==TheEventAction)
		{
			N64EventArray[i]=N64EventArray[CurrentSize--];
			EventHeapPercolateDown(i);
			return;
		}	
	}
}

void EventHeapDeleteTime(__int64 TheEventTime)      //Remove Event with a certain time
{
	for(int i=1; i<=CurrentSize;i++)
	{
		if(N64EventArray[i].Time==TheEventTime)
		{
			N64EventArray[i]=N64EventArray[CurrentSize--];
			EventHeapPercolateDown(i);
			return;
		}	
	}
}

int EventHeapIsEmpty()
{
	if(CurrentSize == 0)
		return 1;
	else
		return 0;
}

int EventHeapIsFull()
{
	if(CurrentSize == EVENT_HEAP_SIZE)
		return 1;
	else
		return 0;
}

void EventHeapMakeEmpty()
{
	CurrentSize = 0;
	OrderOk = 1;
}

void EventHeapToss(N64Event X)
{
	CurrentSize++;
	if(CurrentSize>EVENT_HEAP_SIZE)
	{
		//MessageBox(NULL,"N64 Event Heap too small.","DEATH",MB_OK);
		return;
	}
	N64EventArray[CurrentSize] = X;
	if(X.Time < N64EventArray[CurrentSize/2].Time)
		OrderOk=0;
}

void EventHeapPercolateDown(int Hole)
{
	int Child;
	N64Event Tmp;
	Tmp = N64EventArray[Hole];
	for(; Hole*2<=CurrentSize; Hole = Child)
	{
		Child = Hole*2;
		if(Child++ <= CurrentSize && N64EventArray[Child + 1].Time < N64EventArray[Child].Time)
			Child++;
		if(Child <= CurrentSize)
		{
			if(N64EventArray[Child].Time < Tmp.Time)
				N64EventArray[Hole] = N64EventArray[Child];
			else if(N64EventArray[Child].Time == Tmp.Time)
				N64EventArray[Child].Time+=0x100;
			else
				break;
		}
	}
	N64EventArray[Hole] = Tmp;
}

void EventHeapFixHeap(void)
{
	for(int i = CurrentSize / 2; i>0; i--)
		EventHeapPercolateDown(i);
	OrderOk = 1;
}

void InitEventHeap()
{
	CurrentSize = 0;  // let the non-event stay in the heap forever..
	N64EventArray[0].Time = 0x0000000000000000;  //Sentinel
    N64EventArray1Ptr = (ulong)&N64EventArray[1].Time;
}

//----------------------------------------------------------------------------------------------------------------------

