#include <curses.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#define HSIZE 60
#define LENGTH 75
#define WIDTH 10
#define STARTX 1
#define STARTY 5
#define STATUSX 1
#define STATUSY 25

#define KEY_F1 265

int print_menu();
void print_byebye();
void create_test_string();
void print_time(time_t startt, time_t endt, int mistakes);
void print_in_middle(int startx, int starty, int width, char *string, WINDOW *win);

char *groups[] = {  "`123456" ,
					"7890-="  ,
					"~!@#$%^" ,
					"&*()_+"  ,
					"<>?" 	  , 	 
					",./\\"	  ,
					"asdfg",
					"jkl;'",
					"qwer",
					"uiop",
					"tyur",
					"zxcv",
					"bnm",
				  };
int n_groups;

int main()
{	int choice, i;
	char *test_array;
	int ch = KEY_F1;
	int mistakes;
	int x, y;
	time_t start_t, end_t;
	WINDOW *typing_win;
	char string[80];
	
	string[0] = '\0';
						
	initscr();
	cbreak();
	noecho();
	keypad(stdscr, TRUE);
	intrflush(stdscr, FALSE);
	
	srandom(time(NULL));
	n_groups = sizeof(groups) / sizeof(char *);
	test_array = (char *)calloc(HSIZE + 1, sizeof(char));
	
	while(1)
	{		
		if(ch == KEY_F1)
		{	choice = print_menu();
			choice -= 1;
			if(choice == n_groups)
			{	print_byebye();
				free(test_array);
				endwin();
				exit(0);
			}
		}
		clear();
		strcpy(string, "Typing window");
		print_in_middle(STARTX, STARTY - 2, LENGTH, string, NULL);
		attron(A_REVERSE);
		mvprintw(STATUSY, STATUSX, "Press F1 to Main Menu");
		refresh();
		attroff(A_REVERSE);

		create_test_string(test_array, choice);
		typing_win = newwin(WIDTH, LENGTH, STARTY, STARTX);
		keypad(typing_win, TRUE);
		intrflush(typing_win, FALSE);
		box(typing_win, 0, 0);
	
		x = 1;
		y = 1;
		mvwprintw(typing_win, y, x, "%s", test_array);
		wrefresh(typing_win);
		y += 1;
	
		mistakes = 0;
		i = 0;
		time(&start_t);
		wmove(typing_win, y, x);
		wrefresh(typing_win);
		ch = 0;
		while(ch != KEY_F1 && i != HSIZE + 1)
		{	ch = wgetch(typing_win);
			mvwprintw(typing_win, y, x, "%c", ch);
			wrefresh(typing_win);
			++x;
			if(ch == test_array[i])
			{	++i;
				continue;
			}
			else
			{	++mistakes;
				++i;
			}
		}
	
		time(&end_t);
		print_time(start_t, end_t, mistakes);
	}
	free(test_array);
	endwin();
	return 0;
}
		

int print_menu()
{	int choice, i;
	
	choice = 0;
	while(1)
	{	clear();
		printw("\n\n");
		print_in_middle(1, 1, 0, "* * *   Welcome to typing practice (Version 1.0) * * * ", NULL);
		printw("\n\n\n");
		for(i = 0;i <= n_groups - 1; ++i)
			printw("\t%3d: \tPractice %s\n", i + 1, groups[i]);
		printw("\t%3d: \tExit\n", i + 1);
	
		printw("\n\n\tChoice: ");
		refresh();
		echo();
		scanw("%d", &choice);
		noecho();
	
		if(choice >= 1 && choice <= n_groups + 1)
			break;
		else
		{	attron(A_REVERSE);
			mvprintw(STATUSY, STATUSX, "Wrong choice\tPress any key to continue");
			attroff(A_REVERSE);
			getch();
		}
	}
	return choice;
}

void create_test_string(char *test_array, int choice)
{	int i, index, length;
	
	length = strlen(groups[choice]);
	for(i = 0;i <= HSIZE - 1; ++i)
	{	if(i%5 == 0)
			test_array[i] = ' ';
		else
		{	index = (int)(random() % length);
			test_array[i] = groups[choice][index];
		}
	}
	test_array[i] = '\0';
}	
	
void print_byebye()
{	printw("\n");
	print_in_middle(0,0,0,"Thank you for using my typing tutor\n", NULL);
	print_in_middle(0,0,0,"Bye Bye ! ! !\n", NULL);
	refresh();
}
		
void print_time(time_t start_t, time_t end_t, int mistakes)
{	long int diff;
	int h,m,s;
	float wpm;

	diff = end_t - start_t;
	wpm = ((HSIZE / 5)/(double)diff)*60;

	h = (int)(diff / 3600);
    diff -= h * 3600;
	m = (int)(diff / 60);
	diff -= m * 60;
	s = (int)diff; 
	
	attron(A_REVERSE);
	mvprintw(STATUSY, STATUSX, "Mistakes made : %d time taken: %d:%d:%d WPM : %.2f    Press any Key to continue", mistakes, h, m, s, wpm);
	attroff(A_REVERSE);

	refresh();
	getch();

}

/* ---------------------------------------------------------------- *
 * startx = 0 means at present x 									*
 * starty = 0 means at present y									*
 * win = NULL means take stdscr 									*
 * ---------------------------------------------------------------- */

void print_in_middle(int startx, int starty, int width, char *string, WINDOW *win)
{	int length, x, y;
	float temp;
	
	if(win == NULL)
		win = stdscr;
	getyx(win, y, x);
	if(startx != 0)
		x = startx;
	if(starty != 0)
		y = starty;
	if(width == 0)
		width = 80;

	length = strlen(string);
	temp = (width - length)/ 2;
	x = startx + (int)temp;	
	mvwprintw(win, y, x, "%s", string);
	refresh();
}
