#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define VERSION_NUMBER "v21"
#define COMMENTED_LINE '#'
#define WORD_SEPARATOR "|"
#define BUFFER_SIZE 100

//	To do list:
//	Add white space trimming to questions and answers
//	"    1st question	|	 1st answer 	\n"
//	gives "1st question\0" and "1st answer\0"

struct word_pair
{
	int total_words;
	char **word;
};
int *shuffleDeck(int deck_size, int deck_offset)
{
	int *deck;
	int unique;
	int i, j;

	deck = malloc(deck_size * sizeof(int));
	srandom(time(NULL));
	i = 0;
	while (i<deck_size)
	{
		deck[i] = (random() % deck_size) + deck_offset;
		unique = 1;
		for (j=0; j<i; j++)
		{
			if (deck[j] == deck[i])
			{
				unique = 0;
				break;
			}
		}
		if (0 != unique)
		{
			i++;
		}
	}
	return deck;
}
int *chooseAnswers(int deck_size,  int total_answers, int answer_offset, int correct_answer)
{
	int *answers;
	int answer_position;
	int unique;
	int i, j;

	if (total_answers > deck_size)
	{
		return NULL;
	}
	answers = malloc(total_answers * sizeof(int));
	srandom(time(NULL));
	answer_position = random() % total_answers;
	answers[answer_position] = correct_answer;
	i = 0;
	while (i < total_answers)
	{
		if (i == answer_position)
		{
			i++;
		}
		else
		{
			answers[i] = (random() % (deck_size)) + answer_offset;
			unique = 1;
			for (j=0; j<i; j++)
			{
				if (answers[j] == answers[i])
				{
					unique = 0;
				}
			}
			if (unique != 0)
			{
				i++;
			}
		}
	}
	return answers;
}
void mainGame(struct word_pair **main_list, int deck_size,
		int total_sides, int question_side, int answer_side)
{
	if ((NULL == main_list) || (0 == deck_size) || (0 == total_sides)
			|| (question_side >= total_sides) || (answer_side >= total_sides))
	{
		printf("# main_game: invalidarguments %d %d %d %d\n",
				deck_size, total_sides, question_side, answer_side);
		return;
	}

	struct word_pair *current_card;
	int *question_order, *answer_choices;
	int current_question;
	int current_answer;
	int questions_remaining;
	int user_answer;
	int invalid_input;
	int i, j;
	char input[16], *temp;

	for (i=0; i < deck_size; i++)
	{
		if(NULL == main_list[i])
		{
			printf("# main_game: entry %d in main_list invalid\n", i);
			return;
		}
	}
	question_order = shuffleDeck(deck_size, 0);
	questions_remaining = deck_size;
	j = deck_size;
	while (questions_remaining > 0)
	{
		if (0 == j)
		{
			j = deck_size;
		}
		j--;
		current_question = question_order[j];
		answer_choices = chooseAnswers(deck_size, 8, 0, current_question);
		current_card = main_list[current_question];
		//	print question
		printf("                                   -- %s", current_card->word[question_side]);
		for (i=0; i<8; i++)
		{
			if (0 == (i % 4))
			{
				printf("\n");
			}
			current_answer = answer_choices[i];
			current_card = main_list[current_answer];
			//	print answer
			printf("  %d. %15s ", (i+1), current_card->word[answer_side]);
		}
		printf("\n");
		do
		{
			invalid_input = 0;
			printf("                                          ");
			fgets(input, 16, stdin);
			if ((temp = strchr(input, '\r')))
			{
				*temp = '\0';
			}
			if ((temp = strchr(input, '\n')))
			{
				*temp = '\0';
			}
			user_answer = atoi(input) - 1;
			if ('q' == input[0])
			{
				questions_remaining = 0;
			}
			else if ('p' == input[0])
			{
				printf("                                      # Passed\n\n");
			}
			else if ((0 <= user_answer) && (user_answer <= 7))
			{
				user_answer = answer_choices[user_answer];
				if (user_answer == current_question)
				{
					printf("                                   *** Correct ***\n\n");
					questions_remaining--;
				}
				else
				{
					printf("                                   xxxx Wrong xxxx\n\n");
				}
			}
			else
			{
				printf("# Invalid input\n");
				invalid_input = 1;
			}
		}
		while (1 == invalid_input);
	}
	free(question_order);
	free(answer_choices);
	return;
}






void clean_and_trim_text(char *target)
{
	int i, j;
	int trim;
//	int target_length = strlen(target) + 1;

	for (i=0, j=0; (target[i] != '\0') && (0==j); i++)
	{
		if (target[i] == WORD_SERPARATOR)
		{
			trim = 1;
			target[j] = target[i];
			j++;
		}
		else if (target[i] > ' ')
		{
			trim = 0;
			target[j] = target[i];
			j++;
		}
	}
	if (j)
	{
		for (; target[i] != '\0'; i++)
		{
			if (target[i] == WORD_SERPARATOR)	// '|'
			{
				if (trim)
				{
					target[j-1] = target[i];
				}
				else if (0 == trim)
				{
					target[j] = target[i];
					j++;
					trim = 1;
				}
			}
			else if (target[i] > ' ')
			{
				trim = 0;
				target[j] = target[i];
				j++;
			}
			else if (0 == trim)
			{
				trim = 1;
				target[j] = ' ';
				j++;
			}
		}
		j--;
		if (target[j] != ' ')
		{
			j++;
		}
	}
	target[j] = '\0';
}
char **clean_line(char *const *line_to_clean, int total_segments, int current_number)
{
	char **temp_array;
	char **final_array;
	char *char_index;
	int i;
	
	if ((NULL == line_to_clean) || (0 == total_segments))
	{
		return NULL;
	}
	for (i=0; i<total_segments; i++)
	{
		if (!line_to_clean[i])
		{
			return NULL;
		}
	}
	temp_array = malloc(sizeof(char*)*total_segments);
	if (NULL == temp_array)
	{
		return NULL;
	}
	final_array = malloc(sizeof(char*)*total_segments);
	if (NULL == final_array)
	{
		return NULL;
	}
	for (i=0; i<total_card_sides; i++)
	{
		temp_array[i] = line_to_clean[i];
		final_array[i] = line_to_clean[i];
	}
	for (i=0; i<total_card_sides; i++)
	{// change everything to white spaces with strchr
		index = temp_array[i];
		while (*index <= ' ')
		{
			index++;
		}
		temp_array[i] = index;
	}
	for (i=0; i<total_card_sides; i++)
	{
		if ('\0' == *(string_to_clean[i]))
		{
			asprintf(&(final_array[i]),
					"Word %d %d is blank",
					current_line, i);
			printf(" %s,", current_pair->word[0]);
			fflush(stdout);
		}
		else
		{
			final_array = strndup(line_to_clean, BUFFER_SIZE);
			printf(" %s,", current_pair->word[0]);
			fflush(stdout);
		}
	}
	return final_array;
}
char **parse_line(char *string_to_split, int total_segments)
{
	/* take buffer, split it, return pointer to array of segments or null if empty */
	char *buffer, *index, **final_array;
	int i;

	if ((NULL == string_to_split) || (total_segments <= 0))
	{
		printf("# parse_line: invalid arguments\n");
		fflush(stdout);
		return NULL;
	}
	final_array = malloc(sizeof(char*)*total_segments);
	if (NULL == final_array)
	{
		printf("# parse_line: malloc failed\n");
		fflush(stdout);
		return NULL;
	}
	buffer = strndup(string_to_split, BUFFER_SIZE);
	if (NULL == buffer)
	{
		printf("# parse_line: strdup failed\n");
		fflush(stdout);
		free(final_array);
		return NULL;
	}
	if ((index = strchr(buffer, '\r')))
	{
		*index = '\0';
	}
	if ((index = strchr(buffer, '\n')))
	{
		*index = '\0';
	}
	index = buffer;
	for (i=0; i<total_segments; i++)
	{
		if (NULL == index)
		{
			printf("# parse_line: word %d is empty", i);
			fflush(stdout);
			final_array[i] = strrchr(buffer, '\0'); // = NULL;
		}
		else
		{
			final_array[i] = strsep(&index, WORD_SEPARATOR);
			if ('\0' == *(final_array[i]))	// (0 == strlen(final_array[i]))
			{
				printf("# parse_line: word %d is empty", i);
				fflush(stdout);
				final_array[i] = strrchr(buffer, '\0'); // = NULL;
			}
		}
	}
	return final_array;
}
int load_deck(struct word_pair ***final_word_pair_list, int total_card_sides)
{
	struct word_pair *current_pair, **temp, **word_pair_list;
	int total_word_pairs;
	int loop_count, i;
	FILE *file_pointer;
	char filename[] = "example.txt";
	char buffer[BUFFER_SIZE];
	char **parse_output, **clean_output;

//	card_side = malloc(number_of_card_sides*sizeof(char*))
	printf("Opening file %s\n", filename);
	fflush(stdout);
	file_pointer = fopen(filename, "r");
	if (NULL == file_pointer)
	{
		printf("# load_deck: Could not open file %s\n", filename);
		fflush(stdout);
		return 0;
	}
	total_word_pairs = 0;
	word_pair_list = NULL;
	loop_count = 0;
	while (NULL != (fgets(buffer, BUFFER_SIZE, file_pointer)))
	{
		loop_count++;
		printf("Reading line %d\n", loop_count);
		fflush(stdout);
		if (COMMENTED_LINE == buffer[0])
		{
			printf("# load_deck: commented line\n");
			fflush(stdout);
		}
		else if (('\r' == buffer[0]) || ('\0' == buffer[0]) || ('\n' == buffer[0]))
		{
			printf("# load_deck: empty line\n");
			fflush(stdout);
		}
		else
		{
			total_word_pairs++;
			parse_output = parse_line(buffer, total_card_sides);
			if (NULL == parse_output)
			{
				total_word_pairs--;
				printf("# load_deck: parse_output is NULL for line %d\n", loop_count);
				fflush(stdout);
			}
			else
			{
				current_pair = malloc(sizeof(struct word_pair));
				if (NULL == current_pair)
				{
					total_word_pairs--;
					printf("# load_deck: current_pair is NULL for line %d\n", loop_count);
					fflush(stdout);
					free(parse_output[0]);
					free(parse_output[1]);
					free(parse_output);
				}
				else
				{
					temp = realloc(word_pair_list, total_word_pairs*sizeof(struct word_pair **));
					if (NULL == temp)
					{
						total_word_pairs--;
						printf("# load_deck: temp is NULL for line %d\n", loop_count);
						fflush(stdout);
						free(parse_output[0]);
						free(parse_output[1]);
						free(parse_output);
						free(current_pair);
					}
					else
					{
						word_pair_list = temp;
						word_pair_list[total_word_pairs - 1] = current_pair;
						clean_output = clean_line(parse_output, total_card_sides, total_word_pairs);
						if (NULL == clean_output)
						{
							printf("# load_deck: line could not be cleaned\n");
							fflush(stdout);
							current_pair->total_words = total_card_sides * -1;
							current_pair->word = parse_output;
						}
						else
						{
							printf(";\n");
							fflush(stdout);
							current_pair->total_words = total_card_sides;
							free(parse_output);
						}
					}
				}
			}
		}
	}
	printf("Reached End Of File\n");
	fflush(stdout);
	fclose(file_pointer);
	*final_word_pair_list = word_pair_list;		// this line is lazy
	return total_word_pairs;
}
void empty_all(struct word_pair **card_deck, int total_word_pairs)
{
	int i, j;

	for(i=0; i<total_word_pairs; i++)
	{
		printf("Card: %-4d with %d sides:\n", i, word_pair_list[i]->total_words);
		fflush(stdout);
		if (word_pair_list[i]->total_words > 0)
		{
			for (j=0; j<word_pair_list[i]->total_words; j++)
			{
				printf("Side %d: %-17s ", j, word_pair_list[i]->word[j]);
				fflush(stdout);
				free(word_pair_list[i]->word[j]);
			}
		}
		else
		{
			word_pair_list[i]->total_words *= -1;
			for (j=0; j<word_pair_list[i]->total_words; j++)
			{
				printf("Side %d: %-17s ", j, word_pair_list[i]->word[j]);
				fflush(stdout);
			}
			free(word_pair_list[i]->word[0]);
		}
		free(word_pair_list[i]->word);
		printf(" freed\n");
		fflush(stdout);
		free(word_pair_list[i]);
	}
}
int main()
{
	struct word_pair **word_pair_list;
	int total_word_pairs = 0;
	int total_card_sides = 2;

	printf("\nCommand line vocabulary flash cards " VERSION_NUMBER "\n\n");
	fflush(stdout);
	total_word_pairs = load_deck(&word_pair_list, total_card_sides);
//	mainGame(word_pair_list, total_word_pairs, total_card_sides, 0, 1);

	printf("Cleaning up\n");
	fflush(stdout);
	empty_all(word_pair_list, total_word_pairs);
	free(word_pair_list);

	printf("Exiting\n");
	return 0;
}
