
#define NOIDEA_free 999999990
#define NOIDEA_first 999999991
#define NOIDEA_table 999999992
#define NOIDEA_root 999999993
#define NOIDEA_file 999999994
#define NOIDEA_dodo 999999998
#define NOIDEA_eran 999999999

typedef unsigned long int NOIDEA_id;

typedef struct NOIDEA_fs
{
	NOIDEA_id id;
	NOIDEA_id nfo;
	NOIDEA_id undo;
	NOIDEA_id redo;
	NOIDEA_id back;
	NOIDEA_id fore;
	NOIDEA_id last;
	NOIDEA_id next;
} NOIDEA_fs;

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

NOIDEA_fs * NOIDEA_get_node (NOIDEA_fs * noidea_table, NOIDEA_id noidea_numb)
/* internal function */
{
	return (NOIDEA_fs*)(((void*)noidea_table) + (noidea_numb * sizeof(NOIDEA_fs)));
}

/* will make the table in memory but will keep space for himself */
NOIDEA_fs * NOIDEA_build (int noidea_qty, int noidea_cluster, void * noidea_ptr)
{
	if ((noidea_cluster <= sizeof(NOIDEA_fs))||(noidea_ptr == 0)||(noidea_qty == 0))
	{	return 0;	}

	NOIDEA_fs * noidea_root_node = (NOIDEA_fs*)noidea_ptr;
	noidea_root_node->id = 0;
	noidea_root_node->nfo = NOIDEA_first;

	NOIDEA_fs * noidea_cluster_node;
	int noidea_table_clusters = ((noidea_qty * sizeof(NOIDEA_fs)) + sizeof(NOIDEA_fs)-1) /noidea_cluster;
	int noidea_cluster_id = 1;
	while (noidea_cluster_id < noidea_qty)
	{
		noidea_cluster_node = (NOIDEA_fs*)(noidea_ptr + (noidea_cluster_id * sizeof(NOIDEA_fs)));
		noidea_cluster_node->id = noidea_cluster_id;
		if (noidea_cluster_id <= noidea_table_clusters)
		{
			NOIDEA_fs * noidea_back_node;
			noidea_cluster_node->nfo = NOIDEA_table;

			noidea_cluster_node->back = noidea_root_node->back;
			noidea_cluster_node->fore = noidea_root_node->id;
			noidea_back_node = NOIDEA_get_node(noidea_root_node, noidea_root_node->back);
			noidea_root_node->back = noidea_cluster_node->id;
			noidea_back_node->fore = noidea_cluster_node->id;
			noidea_cluster_node->last = noidea_cluster_node->id;
			noidea_cluster_node->next = noidea_cluster_node->id;
			noidea_cluster_node->undo = noidea_cluster_node->id;
			noidea_cluster_node->redo = noidea_cluster_node->id;
			
		}
		else
		{
			NOIDEA_fs * noidea_undo_node;
			noidea_cluster_node->nfo = NOIDEA_free;

			noidea_cluster_node->redo = noidea_root_node->id;
			noidea_cluster_node->undo = noidea_root_node->undo;
			noidea_undo_node = NOIDEA_get_node(noidea_root_node, noidea_root_node->undo);
			noidea_root_node->undo = noidea_cluster_node->id;
			noidea_undo_node->redo = noidea_cluster_node->id;
			noidea_cluster_node->last = noidea_cluster_node->id;
			noidea_cluster_node->next = noidea_cluster_node->id;
			noidea_cluster_node->back = noidea_cluster_node->id;
			noidea_cluster_node->fore = noidea_cluster_node->id;
		}

		noidea_cluster_id += 1;
	}

	return noidea_root_node;
}

/* just in the case you build ure fs in ram 
   this will act has harddrive form */
void * NOIDEA_read (NOIDEA_fs * noidea_table, NOIDEA_id noidea_size, NOIDEA_id noidea_numb, void * noidea_dest)
{
	int noidea_down = noidea_size;
	while (noidea_down != 0)
	{
		*(char*)(noidea_dest + noidea_down) = *(char*)(((void*)noidea_table) + (noidea_numb * noidea_size) + noidea_down);
		noidea_down -= 1;
	}
	return noidea_dest;
}

/* just in the case you build ure fs in ram 
   this will act has harddrive form */
void * NOIDEA_write (NOIDEA_fs * noidea_table, NOIDEA_id noidea_size, NOIDEA_id noidea_numb, void * noidea_src)
{
	int noidea_down = noidea_size;
	while (noidea_down != 0)
	{
		*(char*)(((void*)noidea_table) + (noidea_numb * noidea_size) + noidea_down) = *(char*)(noidea_src + noidea_down);
		noidea_down -= 1;
	}
	return noidea_src;
}


//===============================================================================================
//===============================================================================================
//===============================================================================================
//===============================================================================================
/*lack option for cluster 0*/
NOIDEA_id NOIDEA_push (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_file ,NOIDEA_id noidea_eran)
{
	if ((noidea_table == 0)||(noidea_eran == 0))
	{	return 0;	}
	NOIDEA_fs * noidea_out_file;
	if (noidea_file != 0)
	{											
		NOIDEA_fs * noidea_new_undo = NOIDEA_get_node (noidea_table, noidea_file);
		if ((noidea_new_undo->nfo != NOIDEA_root)&&(noidea_new_undo->nfo != NOIDEA_file))
		{	return 0;	}

		NOIDEA_fs * noidea_new_file = NOIDEA_get_node (noidea_table, noidea_eran);
		if (noidea_new_file->nfo != NOIDEA_eran)
		{	return 0;	}

		NOIDEA_fs * noidea_redo_node = NOIDEA_get_node (noidea_table, noidea_new_undo->redo);

		if (noidea_new_undo->last == noidea_new_undo->id)
		{
			noidea_new_file->last = noidea_new_file->id;
			noidea_new_file->next = noidea_new_file->id;
		}
		else
		{
			noidea_new_file->last = noidea_new_undo->last;
			noidea_new_file->next = noidea_new_undo->next;
			NOIDEA_fs * noidea_last_node = NOIDEA_get_node (noidea_table, noidea_new_file->last);
			NOIDEA_fs * noidea_next_node = NOIDEA_get_node (noidea_table, noidea_new_file->next);
			noidea_last_node->next = noidea_new_file->id;
			noidea_next_node->last = noidea_new_file->id;
		}

		if (noidea_new_undo->back == noidea_new_undo->id)
		{
			noidea_new_file->back = noidea_new_file->id;
			noidea_new_file->fore = noidea_new_file->id;
		}
		else
		{
			noidea_new_file->back = noidea_new_undo->back;
			noidea_new_file->fore = noidea_new_undo->fore;
			NOIDEA_fs * noidea_back_node = NOIDEA_get_node (noidea_table, noidea_new_file->back);
			NOIDEA_fs * noidea_fore_node = NOIDEA_get_node (noidea_table, noidea_new_file->fore);
			noidea_back_node->fore = noidea_new_file->id;
			noidea_fore_node->back = noidea_new_file->id;
		}

		noidea_new_undo->last = noidea_new_undo->id;
		noidea_new_undo->next = noidea_new_undo->id;
		noidea_new_undo->back = noidea_new_undo->id;
		noidea_new_undo->fore = noidea_new_undo->id;

		noidea_redo_node->undo = noidea_new_file->id;
		noidea_new_undo->redo = noidea_new_file->id;
		noidea_new_file->undo = noidea_new_undo->id;
		noidea_new_file->redo = noidea_redo_node->id;
		noidea_new_file->nfo = noidea_new_undo->nfo;
		noidea_new_undo->nfo = NOIDEA_dodo;

		noidea_out_file = noidea_new_file;
	}
	else
	{
		NOIDEA_fs * noidea_root_file = NOIDEA_get_node (noidea_table, 0);
		if (noidea_root_file->nfo != NOIDEA_first)
		{	return 0;	}
		NOIDEA_fs * noidea_undo_file = NOIDEA_get_node (noidea_table, noidea_root_file->undo);
		if (noidea_undo_file->nfo != NOIDEA_free)
		{	return 0;	}
		NOIDEA_fs * noidea_new_undo = NOIDEA_get_node (noidea_table, noidea_eran);
		if (noidea_new_undo->nfo != NOIDEA_eran)
		{	return 0;	}

		noidea_new_undo->redo = noidea_root_file->id;
		noidea_new_undo->undo = noidea_undo_file->id;
		noidea_undo_file->redo = noidea_new_undo->id;
		noidea_root_file->undo = noidea_new_undo->id;
		noidea_new_undo->nfo = NOIDEA_free;

		noidea_out_file = noidea_root_file;
	}
	return noidea_out_file->id;
}

/* pop cluster from file if there is a redo to replace it
   useful if you undo the file cluster and want to keep it
   somewhere, then the first redo will take place */
NOIDEA_id NOIDEA_pop (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_file)
{
	if (noidea_table == 0)
	{	return 0;	}

	NOIDEA_fs * noidea_new_eran;
	if (noidea_file == 0)
	{
		NOIDEA_fs * noidea_root_node = NOIDEA_get_node (noidea_table, 0);
		noidea_new_eran = NOIDEA_get_node(noidea_table, noidea_root_node->undo);
		NOIDEA_fs * noidea_new_undo = NOIDEA_get_node(noidea_table, noidea_new_eran->undo);
		noidea_root_node->undo = noidea_new_undo->id;
		noidea_new_undo->redo = noidea_root_node->id;
		noidea_new_eran->undo = noidea_new_eran->id;
		noidea_new_eran->redo = noidea_new_eran->id;
		noidea_new_eran->nfo = NOIDEA_eran;
	}
	else
	{
		noidea_new_eran = NOIDEA_get_node (noidea_table, noidea_file);
		if ((noidea_new_eran->undo != noidea_new_eran->id)||(noidea_new_eran->redo != noidea_new_eran->id))
		{
			NOIDEA_fs * noidea_back_file = NOIDEA_get_node (noidea_table, noidea_new_eran->back);
			NOIDEA_fs * noidea_fore_file = NOIDEA_get_node (noidea_table, noidea_new_eran->fore);
			NOIDEA_fs * noidea_last_file = NOIDEA_get_node (noidea_table, noidea_new_eran->last);
			NOIDEA_fs * noidea_next_file = NOIDEA_get_node (noidea_table, noidea_new_eran->next);
			NOIDEA_fs * noidea_new_file = NOIDEA_get_node (noidea_table, noidea_new_eran->redo);
			NOIDEA_fs * noidea_new_undo = NOIDEA_get_node (noidea_table, noidea_new_eran->undo);
			noidea_new_file->nfo = noidea_new_eran->nfo;
			noidea_new_file->undo = noidea_new_undo->id;
			noidea_new_undo->redo = noidea_new_file->id;
			noidea_back_file->fore = noidea_new_file->id;
			noidea_fore_file->back = noidea_new_file->id;
			noidea_new_file->back = noidea_back_file->id;
			noidea_new_file->fore = noidea_fore_file->id;
			noidea_last_file->next = noidea_new_file->id;
			noidea_next_file->last = noidea_new_file->id;
			noidea_new_file->last = noidea_last_file->id;
			noidea_new_file->next = noidea_next_file->id;
			noidea_new_eran->undo = noidea_new_eran->id;
			noidea_new_eran->redo = noidea_new_eran->id;
			noidea_new_eran->back = noidea_new_eran->id;
			noidea_new_eran->fore = noidea_new_eran->id;
			noidea_new_eran->last = noidea_new_eran->id;
			noidea_new_eran->next = noidea_new_eran->id;
			noidea_new_eran->nfo = NOIDEA_eran;
				/*debug debug debug*/
				//noidea_new_eran = noidea_new_file;
		}
		else
		{
			noidea_new_eran = 0;
		}
	}
	return noidea_new_eran->id;
}

/*  */
NOIDEA_id NOIDEA_undo (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_file)
{
	if ((noidea_table == 0)||(noidea_file == 0))
	{	return 0;	}

	NOIDEA_fs * noidea_file_node = NOIDEA_get_node (noidea_table, noidea_file);
	NOIDEA_fs * noidea_undo_node = NOIDEA_get_node (noidea_table, noidea_file_node->undo);
	return noidea_undo_node->id;
}

NOIDEA_id NOIDEA_redo (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_file)
{
	if ((noidea_table == 0)||(noidea_file == 0))
	{	return 0;	}

	NOIDEA_fs * noidea_file_node = NOIDEA_get_node (noidea_table, noidea_file);
	NOIDEA_fs * noidea_redo_node = NOIDEA_get_node (noidea_table, noidea_file_node->redo);
	return noidea_redo_node->id;
}

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

/* will make new file from any eran cluster */
NOIDEA_id NOIDEA_mk (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_eran)
{
	if ((noidea_table == 0)||(noidea_eran == 0))
	{	return 0;	}

	NOIDEA_fs * noidea_new_file = NOIDEA_get_node (noidea_table, noidea_eran);
	if (noidea_new_file->nfo != NOIDEA_eran)
	{	return 0;	}

	NOIDEA_fs * noidea_root_file = NOIDEA_get_node (noidea_table, 0);
	NOIDEA_fs * noidea_last_file = NOIDEA_get_node (noidea_table, noidea_root_file->last);
	noidea_new_file->last = noidea_last_file->id;
	noidea_new_file->next = noidea_root_file->id;
	noidea_last_file->next = noidea_new_file->id;
	noidea_root_file->last = noidea_new_file->id;
	noidea_new_file->nfo = NOIDEA_root;

	return noidea_new_file->id;
}

/* remove root of a file if there is no undo or next node */
NOIDEA_id NOIDEA_rm (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_root)
{
	if ((noidea_table == 0)||(noidea_root == 0))
	{	return 0;	}

	NOIDEA_fs * noidea_old_node = NOIDEA_get_node (noidea_table, noidea_root);
	if ((noidea_old_node->undo != noidea_old_node->id)||(noidea_old_node->back != noidea_old_node->id))
	{	return 0;	}

	NOIDEA_fs * noidea_last_node = NOIDEA_get_node (noidea_table, noidea_old_node->last);
	NOIDEA_fs * noidea_next_node = NOIDEA_get_node (noidea_table, noidea_old_node->next);
	noidea_last_node->next = noidea_next_node->id;
	noidea_next_node->last = noidea_last_node->id;
	noidea_old_node->last = noidea_old_node->id;
	noidea_old_node->next = noidea_old_node->id;
	noidea_old_node->nfo = NOIDEA_eran;

	return noidea_old_node->id;
}

NOIDEA_id NOIDEA_add (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_root ,NOIDEA_id noidea_eran)
{
	if ((noidea_table == 0)||(noidea_root == 0)||(noidea_eran == 0))
	{	return 0;	}

	NOIDEA_fs * noidea_new_back = NOIDEA_get_node (noidea_table, noidea_eran);
	if (noidea_new_back->nfo != NOIDEA_eran)
	{	return 0;	}

	NOIDEA_fs * noidea_root_node = NOIDEA_get_node (noidea_table, noidea_root);
	if (noidea_root_node->nfo != NOIDEA_root)
	{	return 0;	}

	NOIDEA_fs * noidea_old_back = NOIDEA_get_node (noidea_table, noidea_root_node->back);
	noidea_old_back->fore = noidea_new_back->id;
	noidea_root_node->back = noidea_new_back->id;
	noidea_new_back->back = noidea_old_back->id;
	noidea_new_back->fore = noidea_root_node->id;
	noidea_new_back->nfo = NOIDEA_file;

	return noidea_root_node->id;
}

NOIDEA_id NOIDEA_sub (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_root)
{
	if ((noidea_table == 0)||(noidea_root == 0))
	{	return 0;	}

	NOIDEA_fs * noidea_root_node = NOIDEA_get_node (noidea_table, noidea_root);
	if (noidea_root_node->nfo != NOIDEA_root)
	{	return 0;	}

	NOIDEA_fs * noidea_new_eran = NOIDEA_get_node (noidea_table, noidea_root_node->back);
	if ((noidea_new_eran->nfo != NOIDEA_file)||(noidea_root_node->undo != noidea_root_node->id))
	{	return 0;	}

	NOIDEA_fs * noidea_new_back = NOIDEA_get_node (noidea_table, noidea_new_eran->back);
	noidea_new_back->fore = noidea_root_node->id;
	noidea_root_node->back = noidea_new_back->id;
	noidea_new_eran->back = noidea_new_eran->id;
	noidea_new_eran->fore = noidea_new_eran->id;
	noidea_new_eran->nfo = NOIDEA_eran;

	return noidea_new_eran->id;
}
//===============================================================================================
//===============================================================================================
//===============================================================================================
//===============================================================================================

NOIDEA_id NOIDEA_fore (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_file)
{
	if ((noidea_table == 0)||(noidea_file == 0))
	{	return 0;	}

	NOIDEA_fs * noidea_file_node = NOIDEA_get_node (noidea_table, noidea_file);
	NOIDEA_fs * noidea_fore_node = NOIDEA_get_node (noidea_table, noidea_file_node->fore);

	return noidea_fore_node->id;
}

NOIDEA_id NOIDEA_back (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_file)
{
	if ((noidea_table == 0)||(noidea_file == 0))
	{	return 0;	}

	NOIDEA_fs * noidea_file_node = NOIDEA_get_node (noidea_table, noidea_file);
	NOIDEA_fs * noidea_back_node = NOIDEA_get_node (noidea_table, noidea_file_node->back);

	return noidea_back_node->id;
}

NOIDEA_id NOIDEA_next (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_root)
{
	if (noidea_table == 0)
	{	return 0;	}

	NOIDEA_fs * noidea_file_node = NOIDEA_get_node (noidea_table, noidea_root);
	NOIDEA_fs * noidea_next_node = NOIDEA_get_node (noidea_table, noidea_file_node->next);

	return noidea_next_node->id;
}

NOIDEA_id NOIDEA_last (NOIDEA_fs * noidea_table ,NOIDEA_id noidea_root)
{
	if (noidea_table == 0)
	{	return 0;	}

	NOIDEA_fs * noidea_file_node = NOIDEA_get_node (noidea_table, noidea_root);
	NOIDEA_fs * noidea_last_node = NOIDEA_get_node (noidea_table, noidea_file_node->last);

	return noidea_last_node->id;
}

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