/*
Author:	Martin RobinSon
Project:	No Idea
Idea:		Provide maximum functionnality to the standar ANSI C while using no librairy
			by browsing wikipédia computer science we can see multiple possibility in
			programming that C does not support
How:		By building all necessary logic that is up to the user to add interface
			C syntax provide unsafe memory mannipulation and array , we can exploit
			these way to create all that does not depend on file timer data...
*/

/*
File:			noidea.node.c
Function:	provide node based function
Idea:			double linked array can give mutable list of object.
Purpose:		enable mutability in std ANSI C
Feature:		mutable list of node
				count based function execution (Real-Time concurency when used with timer)
				number based function execution (event)
Function list:
				NOIDEA_create()	constructor , create sentinel , or node
				NOIDEA_destroy()	destructor
				NOIDEA_loop()		give next node and advance ptr
				NOIDEA_rev()		give back node and return ptr
				NOIDEA_schedule()	create counted callback , sentinel or node
				NOIDEA_reschedule() change value in a callback
				NOIDEA_cancel()	remove node callback and give back ptr
				NOIDEA_do()			give count and will execute all issue

*/


/*http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29*/
/*http://en.wikipedia.org/wiki/Free_list*/

#define NULE 0
#define MULE 8888

#define NOIDEA_RT 7777
#define NOIDEA_EVENT 6666

//================================================================================
//================================================================================
//================================================================================

/*http://en.wikipedia.org/wiki/Linked_list*/


typedef struct NOIDEA_node
{
	void * pack;
	struct NOIDEA_node * sentinel;
	struct NOIDEA_node * last;
	struct NOIDEA_node * next;
} NOIDEA_node;

NOIDEA_node * NOIDEA_create (NOIDEA_node * noidea_src, void * noidea_pack, void * noidea_ptr)
{
	if (noidea_ptr == 0)
	{	return 0;	}

	NOIDEA_node * noidea_nud = (NOIDEA_node*) noidea_ptr;
	noidea_nud->pack = noidea_pack;

	if (noidea_src != 0)
	{
		noidea_nud->sentinel = noidea_src->sentinel;
		noidea_nud->last = noidea_src;
		noidea_nud->next = noidea_src->next;
		noidea_nud->last->next = noidea_nud;
		noidea_nud->next->last = noidea_nud;
	}
	else
	{
		noidea_nud->sentinel = noidea_nud;
		noidea_nud->last = noidea_nud;
		noidea_nud->next = noidea_nud;
	}

	return noidea_nud;
}

void * NOIDEA_destroy (NOIDEA_node * noidea_nud)
{
	NOIDEA_node * noidea_src = noidea_nud->sentinel;
	if ((noidea_src == 0)||(noidea_nud == 0))
	{	return;		}

	if (noidea_src == noidea_nud)
	{
		//you shouldnt destroy sentinel if array is not empty
			if (noidea_src != noidea_src->next)
			{
				return;
			}
	}

	noidea_nud->last->next = noidea_nud->next;
	noidea_nud->next->last = noidea_nud->last;

	noidea_nud->pack = 0;
	noidea_nud->last = 0;
	noidea_nud->next = 0;

	return (void*) noidea_nud;	//return ptr in case of alloc/free
}

void * NOIDEA_loop (NOIDEA_node * noidea_src)
/* all node will move around noidea_src */
/* so its sure that youll get them all */
{
	NOIDEA_node * noidea_nud = noidea_src->next;

	noidea_src->last->next = noidea_src->next;
	noidea_src->next->last = noidea_src->last;

	noidea_nud->next->last = noidea_src;
	noidea_src->next = noidea_nud->next;

	noidea_nud->next = noidea_src;
	noidea_src->last = noidea_nud;


	return noidea_nud->pack;
}

void * NOIDEA_rev (NOIDEA_node * noidea_src)
/* all node will move around REVERSE noidea_src */
/* so its sure that youll get them all */
{
	NOIDEA_node * noidea_nud = noidea_src->last;

	noidea_src->next->last = noidea_src->last;
	noidea_src->last->next = noidea_src->next;

	noidea_nud->last->next = noidea_src;
	noidea_src->last = noidea_nud->last;

	noidea_nud->last = noidea_src;
	noidea_src->next = noidea_nud;


	return noidea_nud->pack;
}


//================================================================================
//================================================================================
//================================================================================



typedef struct NOIDEA_agenda
{
	//int type;	//identify type of node
	NOIDEA_node * node;		//the node that list it
	signed long int wait;		//interval between call
	void (*func)(void);		//function to call
	signed long int till;		//wait till to execute
	signed long int idle;		//time left before execute
	signed long int loop;		//value that end loop
} NOIDEA_agenda;


NOIDEA_node * NOIDEA_schedule (NOIDEA_node * noidea_sentinel, void (*noidea_func)(void), signed long int noidea_wait ,void * noidea_ptr)
{
	if (noidea_sentinel != noidea_sentinel->sentinel)
	{
		//noidea_sentinel = noidea_sentinel->sentinel;
	}
	NOIDEA_agenda * noidea_now = (NOIDEA_agenda*) noidea_ptr;
	NOIDEA_node * noidea_node_now = NOIDEA_create(noidea_sentinel,noidea_now,noidea_ptr + sizeof(NOIDEA_agenda));
	noidea_now->node = noidea_node_now;
	noidea_now->func = noidea_func;
	noidea_now->wait = noidea_wait;
	return noidea_node_now;
}

NOIDEA_node * NOIDEA_reschedule (NOIDEA_node * noidea_what, signed long int noidea_wait)
{
	NOIDEA_node * noidea_sentinel = noidea_what->sentinel;
	if ((noidea_sentinel == 0) || (noidea_what == 0))
	{
		return 0;
	}
	NOIDEA_agenda * noidea_today = (NOIDEA_agenda*)noidea_sentinel->pack;
	NOIDEA_agenda * noidea_now = (NOIDEA_agenda*)noidea_what->pack;

	signed long int noidea_till = noidea_now->till - noidea_now->wait + noidea_wait;
	signed long int noidea_idle = noidea_now->till - noidea_now->idle + noidea_till;

	noidea_now->wait = noidea_wait;
	noidea_now->idle = noidea_idle;
	noidea_now->till = noidea_till;

	return noidea_what;
}

void * NOIDEA_cancel (NOIDEA_node * noidea_node_now)
{
	NOIDEA_node * noidea_node_today = noidea_node_now->sentinel;
	NOIDEA_agenda * noidea_now = noidea_node_now->pack;
	noidea_now->wait = 0;
	noidea_now->func = 0;
	noidea_now->idle = 0;
	noidea_now->till = 0;
	noidea_now->loop = 0;
	noidea_now->node = 0;
	noidea_node_now = NOIDEA_destroy (noidea_node_now);

	return ((void*)noidea_now);
}

signed long int NOIDEA_do (NOIDEA_node * noidea_sentinel, signed long int noidea_time)
{
	if (noidea_sentinel != noidea_sentinel->sentinel)
	{
		noidea_sentinel = noidea_sentinel->sentinel;
	}
	NOIDEA_agenda * noidea_today = (NOIDEA_agenda*)noidea_sentinel->pack;
	NOIDEA_agenda * noidea_now;
	noidea_today->loop += 1;
	noidea_today->idle = noidea_today->wait;
	int noidea_yet = 0;
	while (noidea_yet != 1)
	{

		noidea_now = NOIDEA_loop(noidea_sentinel);
			if (noidea_now->loop == noidea_today->loop)
			{
				noidea_yet = 1;
			}
			

			if (noidea_now->till == 0)
			{
				noidea_now->till = noidea_time + noidea_now->wait;
			}
			if (noidea_now->till <= noidea_time)
			{
				noidea_now->till = noidea_time + noidea_now->wait;
				noidea_now->idle = 0;
				noidea_now->func();
				noidea_yet = 1;
			}
			else
			{
				noidea_now->idle = noidea_now->till - noidea_time;
				noidea_now->loop = noidea_today->loop;
			}
			if (noidea_now->idle < noidea_today->idle)
			{
				noidea_today->idle = noidea_now->idle;
			}
	}
	return noidea_today->idle;
}

//================================================================================
//================================================================================
//================================================================================


//================================================================================
//================================================================================
//================================================================================
