#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "data.h"

//need a line delay of 5ms on a line feed

#define COVERED 4
#define TUNING tuning_standard_e
#define DEBUG 0

struct time_event* events_begin = NULL;
struct time_event* events_at = NULL;
unsigned long notes_total = 0;
unsigned long notes_skipped = 0;
unsigned long events_total = 0;
unsigned long events_skipped = 0;
char note_min = 100;
char note_max = 0;
int drop = 0;

const char str[] = TUNING;

struct time_event* setup(FILE*);
void display();
struct coord* getCoord(char,char);
void fillInNotes(struct time_event*);
void removeEmptyTimeEvents(struct time_event*);
void stats();

void stats()
{
	fflush(stdout);
	printf("%i events with %i notes\n\r", events_total, notes_total);
	printf("Note range\t= [%i,%i]\n\r", note_min,note_max);
	printf("Guitar range\t= [%i,%i]\n\r", str[0], str[5]);
	printf("Skipping %3.2f%% of the notes.\n\r", 100*(float)notes_skipped/notes_total);
	printf("Skipping %3.2f%% of the events.\n\r", 100*(float)events_skipped/events_total);
	fflush(stdout);
}

struct time_event* setup(FILE* fin)
{
	unsigned long start_time=0,last_time = (unsigned long)-1,tempo = 0;
	int len=0, stillgo = 1;
	char note=0;
	struct time_event* t = NULL;
	struct note_node* n = NULL;

/*
	file structure:
	
	tempo
	drop
	starttime	length	note
	.
	.
	.
	-1	-1	-1
*/

	char a[16], b[16], c[16];

	fscanf(fin, "%s", &a);
	tempo = strtoul(a, NULL, 10);
	
	fscanf(fin, "%s", &a);
	drop = atoi(a);

    while(stillgo)
	{
		fscanf(fin, "%s", &a);
		fscanf(fin, "%s", &b);
		fscanf(fin, "%s", &c);	
		stillgo = strcmp(a, "-1");

		if(!stillgo) 
		{
			break;
		}
		
		start_time = strtoul(a, NULL, 10);
		len=atoi(b);
		note=(char)atoi(c);

		note+=(drop*12);
		if(DEBUG) { printf("\n\rNote number %ld: %ld|%i|%i", notes_total, start_time,len,note); }

		notes_total++;
		if(note<note_min) { note_min = note; }
		if(note>note_max) { note_max = note; }
		n = (struct note_node*) malloc(sizeof(struct note_node) * 1);
		n->length = len;
		n->note = note;
		n->c = NULL;
		n->next = NULL;

		if(start_time != last_time)
		{
			events_total++;
			t = (struct time_event*) malloc(sizeof(struct time_event) * 1);
			t->start_time = start_time;
			t->node = n;
			t->next = NULL;
		
			if(events_begin==NULL)
			{
				events_begin = t;
			}
			else
			{
				fillInNotes(events_at);
				events_at->next = t;
			}

			events_at = t;
		}
		else
		{
			struct note_node* tmp = events_at->node;
			while(tmp->next)
			{
				tmp=tmp->next;
			}
			tmp->next = n;
		}
		last_time = start_time;
	}
	
	fillInNotes(events_at);
	removeEmptyTimeEvents(events_begin);

	return events_begin;
}

void display()
{
	struct note_node* a = NULL;

	events_at = events_begin;

	while(events_at)
	{
		printf("\n\rstart time=%ld\n\r", events_at->start_time);
		a = events_at->node;
		while(a)
		{
			printf("\t(%i,%i)", a->c->string, a->c->fret);
			a=a->next;
		} 
		events_at = events_at->next;
	}
	puts("\n\r");
	fflush(stdout);
}

struct coord* getCoord(char note,char min_str)
{
	struct coord* ret = (struct coord*) malloc(sizeof(struct coord)*1);
	char i, winner=0;

	for(i=min_str;i<6;i++)
	{
		if(str[i]<=note && note<=str[i]+COVERED)
		{
			ret->string = i;
			ret->fret = note-str[i];
			winner=1;
			break;
		}
	}

	if(!winner) { free(ret); ret=NULL; }
	return ret;
}

void fillInNotes(struct time_event* ptr)
{
	int strings_played[] = {0,0,0,0,0,0};
	struct note_node* nn = ptr->node;
	struct note_node* nn_prev = NULL;
	struct coord* tmp;
	struct note_node* freeme;
	char tmpstr = 0;

	if(!ptr) { return; }

	while(nn)
	{
		tmp = getCoord(nn->note, tmpstr);

		if(tmp)
		{
			if(strings_played[tmp->string])
			{
				tmpstr=(tmp->string+1);
				free(tmp);
				continue;
			}
			else
			{
				strings_played[tmp->string] = 1;
				nn->c = tmp;
			}
		}
		else
		{
			if(DEBUG) { printf("\n\r\tSkipping note %i played at time %i", nn->note, ptr->start_time); }
			notes_skipped++;
			if(nn_prev)
			{
				nn_prev->next = nn->next;
			}
			else
			{
				ptr->node = nn->next;
			}
			freeme = nn;
			nn=nn->next;
			free(freeme);
			tmpstr=0;
			continue;
		}
		tmpstr=0;
		nn_prev=nn;
		nn=nn->next;
	}
}

void removeEmptyTimeEvents(struct time_event* test_node)
{
	struct time_event* last_good_node = NULL;

	while(test_node)
	{
		if(!test_node->node)
		{
			events_skipped++;
			if(DEBUG) { printf("\n\r\tDeleting time event %i", test_node->start_time); }
			if(last_good_node)
			{
				last_good_node->next = test_node->next;
			}
			else
			{
				events_begin = test_node->next;
			}
			free(test_node);
		}
		else
		{
			last_good_node=test_node;
		}

		if(last_good_node)
		{
			test_node=last_good_node->next;
		}
		else
		{
			test_node=events_begin;
		}
	}
}

int main()
{
	FILE* fp = fopen("file.out", "r");
	events_begin = setup(fp);
	fclose(fp);

	stats();

	return 0;
}

