/**
 * File:		keskmineHinne.c
 * Author:		Rainer Liis
 * Created:		19.02.2018
 * Last edit:	20.02.2018
 *
 * Description: The program scans in the students and their grades, 
 * 				finds the best and the worst.
 */

#include <stdio.h> // print, scan
#include <string.h> // strcpy, strcmp
#include "struktuur.h" // holds the structs

// counts the rows in the file
int numberofRows ();

// scans in the data from the file
void readStudents (Stud *to_be_graded);

// filters out students with unapplicable grades
int sieve (Stud *to_be_graded, Filtered *applicable, int n, char DVW);

// sorts by name
void sortbyName (Filtered *applicable, int applicable_amount, char DVW);

// makes a sorted list
int list (Filtered *applicable, int , Avg *student_list, char DVW);

// calculates each student's average
void average (Avg *student_list, Filtered *applicable, int applicable_amount, int student_amount, char DVW);

// sorts by grade
void sortbyAverage (Avg *student_list, int student_amount, char DVW);

// determines who gets the money and who gets the bill
void money (Avg *student_list, int student_amount);

// outputs bills into file
void bill (Avg *student_list, int student_amount);

int main (void)
{
	char DVW; // var to hold the answer
	printf ("Print all or silent? [p/s]"); 

	do // only accepts s or p
	{
		scanf ("%c", &DVW); // determines whether functions print results or not
	} while (DVW != 'p' && DVW != 's');
	printf ("\n\n");

	int n;
	n = numberofRows(); // counts how many rows the file contains

	Stud to_be_graded[n]; // var to hold first scan results
	Filtered applicable[n]; // var to hold applicable 
	Avg student_list[n]; // var to hold each student and their avg grade
	int applicable_amount; // nr of applicable elements
	int student_amount; // nr of students

	readStudents(to_be_graded); 
	printf ("\n\n");

	applicable_amount = sieve (to_be_graded, applicable, n, DVW);

	sortbyName (applicable, applicable_amount, DVW);

	student_amount = list (applicable, applicable_amount, student_list, DVW);

	average (student_list, applicable, applicable_amount, student_amount, DVW);

	sortbyAverage (student_list, student_amount, DVW);

	money (student_list, student_amount);

	bill (student_list, student_amount);

	return 0;
}

int numberofRows()
{
	FILE *data;
	data = fopen ("andmed.txt", "r"); // opens the file

	int read = 0;
	int ch = 0;

	if (data == NULL) // if file doesn't exist, returns 0
	{
		return 0;
	}

// scans every character, if the char is '\n' then the counter counts up
	while ((ch = fgetc (data)) != EOF) 
	{
		if (ch == '\n')
		{
			read++;
		}
	}
	fclose (data); // closes the file

	return read; // returns the nr of rows
}

void readStudents (Stud *to_be_graded)
{
	FILE *data;
	data = fopen ("andmed.txt", "r"); // opens the file

	int i = 0;

	// reads in the data from the file
	while (fscanf (data, "%s %s %d", to_be_graded[i].name, to_be_graded[i].subj, &to_be_graded[i].grade) != EOF)
	{
		// prints the data to the screen
		printf ("%d. %s, %s, %d\n", i+1, to_be_graded[i].name, to_be_graded[i].subj, to_be_graded[i].grade);
		i++;
	}
	fclose (data); // closes the file
}

int sieve (Stud *to_be_graded, Filtered *applicable, int n, char DVW)
{
	int i;
	int j = 0;

	// if the grade is between 0 and 5, then copy row to applicable
	for (i = 0; i < n; i++)
	{
		if (to_be_graded[i].grade >= 0 && to_be_graded[i].grade <= 5)
		{
			strcpy (applicable[j].name, to_be_graded[i].name);
			applicable[j].grade = to_be_graded[i].grade;
			j++;
		}
	}

	// if the input character is p, it prints the result
	if (DVW == 112) // 112 is the ascii value of 'p'
	{
		for (i = 0; i < j; i++)
		{
			printf ("%d, %s, %d\n", i+1, applicable[i].name, applicable[i].grade);
		}
		printf ("\n\n");
	}

	return j; // returns nr of applicable rows
}

void sortbyName (Filtered *applicable, int applicable_amount, char DVW)
{
	int i;
	int j;
	Filtered temp;

	// sorts applicable alphabetically
	for (i = 0; i < applicable_amount; i++)
	{
		for (j = 1; j < applicable_amount; j++)
		{
			if (strcmp (applicable[j-1].name, applicable[j].name) > 0)
			{
				temp.grade = applicable[j-1].grade;
				strcpy (temp.name, applicable[j-1].name);
				applicable[j-1].grade = applicable[j].grade;
				strcpy (applicable[j-1].name, applicable[j].name);
				applicable[j].grade = temp.grade;
				strcpy (applicable[j].name, temp.name);
			}
		}
	}

	// if the input character is p, it prints the result
	if (DVW == 112) // 112 is the ascii value of 'p'
	{
		for (i = 0; i < applicable_amount; i++)
		{
			printf ("%d, %s, %d\n", i+1, applicable[i].name, applicable[i].grade);
		}
		printf ("\n\n");
	}

}

int list (Filtered *applicable, int applicable_amount, Avg *student_list, char DVW)
{
	int i;
	int j = 0;

	// makes a list where each name appears once
	for (i = 0; i < applicable_amount; i++)
	{
		if (strcmp (applicable[i-1].name, applicable[i].name) != 0)
		{
			strcpy (student_list[j].name, applicable[i].name);
			j++;
		}
	}

	// if the input character is p, it prints the result
	if (DVW == 112) // 112 is the ascii value of 'p'
	{
		for (i = 0; i < j; i++)
		{
			printf ("%d, %s\n", i+1, student_list[i].name);
		}
		printf ("\n\n");
	}

	return j; // returns the nr of students
}

void average (Avg *student_list, Filtered *applicable, int applicable_amount, int student_amount, char DVW)
{
	int i;
	int j;
	int counter = 0;

	// calculates the average of each student
	for (i = 0; i < student_amount; i++)
	{
		for (j = 0; j < applicable_amount; j++)
		{
			if (strcmp (student_list[i].name, applicable[j].name) == 0)
			{
				student_list[i].grade += applicable[j].grade;
				counter++;
			}
		}
		student_list[i].average = (float)student_list[i].grade / (float) counter;
		counter = 0;
	}

	// if the input character is p, it prints the result
	if (DVW == 112) // 112 is the ascii value of 'p'
	{
		for (i = 0; i < student_amount; i++)
		{
			printf ("%d,  %s,  %d,  %f\n", i+1, student_list[i].name, student_list[i].grade, student_list[i].average);
		}
		printf ("\n\n");
	}

}

void sortbyAverage (Avg *student_list, int student_amount, char DVW)
{
	int i, j;
	Avg temp;

	// sorts list by average grade
	for (i = 0; i < student_amount; i++)
	{
		for (j = 1; j < student_amount; j++)
		{
			if (student_list[j-1].average < student_list[j].average)
			{
				temp = student_list[j-1];
				student_list[j-1] = student_list[j];
				student_list[j] = temp;
			}
		}
	}

	// if the input character is p, it prints the result
	if (DVW == 112) // 112 is the ascii value of 'p'
	{
		for (i = 0; i < student_amount; i++)
		{
			printf ("%d, %s, %f\n", i+1, student_list[i].name, student_list[i].average);
		}
		printf ("\n\n");
	}

}

void money (Avg *student_list, int student_amount)
{
	int i;
	int counter = 0;

	// prints the first 3 names
	printf ("The money goes to: \n");
	for (i = 0; i < 3; i++)
	{
		printf ("%s, with an average of: %f\n", student_list[i].name, student_list[i].average);
	}
	counter = i;

	// checks if the 4th person from the top has the same average as the 3rd,
	// if that is true, also prints the 4th student's info and then the 5th and so on
	do
	{
		if (student_list[counter].average == student_list[2].average)
		{
			printf ("%s, with an average of: %f\n", student_list[counter].name, student_list[counter].average);
			counter++;
		}
		else
		{
			break;// stops the loop, if there is a difference in the average grade
		};
	} while (student_list[i].average == student_list[2].average);
	printf ("\n\n");

}

void bill (Avg *student_list, int student_amount)
{
	int counter = student_amount - 4;
	int i;

	FILE *output;
	output = fopen ("bill.txt", "w"); // opens the output file

	// prints the last 3 people from student_list to the output file
	printf ("The bills go to: \n");
	fprintf (output, "The bills go to: \n");
	for (i = student_amount - 3; i < student_amount; i++)
	{
		printf ("%s, with an average of: %f\n", student_list[i].name, student_list[i].average);
		fprintf (output, "%s, with an average of: %.2f\n", student_list[i].name, student_list[i].average);
	}

	// checks if the 4th person from the bottom has the same average as the 3rd,
	// if that is true, also prints the 4th student's info and then the 5th and so on
	do
	{
		if (student_list[counter].average == student_list[i - 3].average)
		{
			printf ("%s, with an average of: %f\n", student_list[counter].name, student_list[counter].average);
			fprintf (output, "%s, with an average of: %f\n", student_list[counter].name, student_list[counter].average);
			counter--;
		}
		else
		{
			break; // stops the loop, if there is a difference in the average grade
		};
	} while (student_list[counter].average == student_list[i - 3].average);

	fclose (output); // closes the file
}