//Windows: Kompilera som vanligt.
//Linux: Kör `g++ -o betyg -DLINUX betyg.cpp`
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

//OS-specifika funktioner
#ifdef LINUX
#define clearScr()	system("clear")
//#define pauseKey()	system("read -s -n1 -p \"Tryck på valfri tangent för att fortsätta...\""); cin.ignore(1000, '\n')
#define pauseKey()	cout << "Tryck på [ENTER] för att fortsätta..."; cin.get()
#else
#define clearScr()	system("cls")
#define pauseKey()	system("pause")
#endif

//Tabellhuvud.
#define HEADER	"Kursnamn\tBetyg\tPoäng"
#define HEADER2	"========\t=====\t====="

//Filhuvud
#define FHEAD	"Kursnamn|Betyg|Poang"

struct Betyg {
	string kurs;
	short betyg; //betyget mäts i poäng. (-1, 0, 10, 15 eller 20 för IB, IG, G, VG respektive MVG)
	unsigned short poang;
};

short lasBetyg(istream& is, char endChar = '\n');
string skrivBetyg(short poang);
void skrivVarde(vector<Betyg> lista);
void mataIn(vector<Betyg>& lista);
void skrivUt(vector<Betyg> lista);
void redigeraBetyg(vector<Betyg>& lista, int position);
void taBortBetyg(vector<Betyg>& lista, int position);
int sok(vector<Betyg> lista);
void sortera(vector<Betyg>& lista);
void skrivTillFil(vector<Betyg> lista);
void lasFranFil(vector<Betyg>& lista);
void tom(vector<Betyg>& lista);

int main(void) {
	char filnamn[100];
	vector<Betyg> betygslista;
	short val;
	bool fortsatt = true;
	
	do {
		clearScr();
		cout << "MENY" << endl;
		cout << "1. Mata in nya betyg" << endl;
		cout << "2. Visa lista och jämförelsevärde" << endl;
		cout << "3. Redigera betyg" << endl;
		cout << "4. Ta bort betyg" << endl;
		cout << "5. Sök betyg" << endl;
		cout << "6. Sortera lista" << endl;
		cout << "7. Spara lista till fil" << endl;
		cout << "8. Läs in lista från fil" << endl;
		cout << "9. Töm lista" << endl;
		cout << "0. Avsluta" << endl;
		
		cout << endl << "Val: ";
		cin >> val;
		cin.ignore(1000, '\n');
		cout << endl;
		
		switch (val) {
			case 1:
				mataIn(betygslista);
				break;
			case 2:
				skrivUt(betygslista);
				break;
			case 3:
				redigeraBetyg(betygslista, sok(betygslista));
				break;
			case 4:
				taBortBetyg(betygslista, sok(betygslista));
				break;
			case 5:
				sok(betygslista);
				break;
			case 6:
				sortera(betygslista);
				break;
			case 7:
				skrivTillFil(betygslista);
				break;
			case 8:
				lasFranFil(betygslista);
				break;
			case 9:
				tom(betygslista);
				break;
			case 0:
				fortsatt = false;
				break;
			default:
				cout << "Felaktigt val!";
		}
		if (fortsatt) {
			cout << endl << endl;
			pauseKey();
		}
	} while (fortsatt);
	
	return 0;
}

short lasBetyg(istream& is, char endChar) {
	string inlas;
	short betyg = -2;
	
	do {
		getline(is, inlas, endChar);
		
		for (int i = 0; i < 3; i++) { //vi vill bara röra de tre första tecknen.
			inlas[i] = tolower(inlas[i]); //underlättar matchning senare
		}
		if ((inlas == "m") || (inlas == "mvg") || (inlas == "20")) {
			betyg = 20;
		} else if ((inlas == "v") || (inlas == "vg") || (inlas == "15")) {
			betyg = 15;
		} else if ((inlas == "g") || (inlas == "10")) {
			betyg = 10;
		} else if ((inlas == "i") || (inlas == "ig") || (inlas == "0")) {
			betyg = 0;
		} else if ((inlas == "-") || (inlas == "ib")) {
			betyg = -1;
		} else if (is == cin) {
			cout << "Felaktigt betyg. Försök igen: ";
		} else {
			betyg = -1;
		}
	} while (betyg == -2);
	
	return betyg;
}

string skrivBetyg(short betyg) {
	string namn;
	
	switch (betyg) {
		case 20:
			namn = "MVG";
			break;
		case 15:
			namn = "VG";
			break;
		case 10:
			namn = "G";
			break;
		case 0:
			namn = "IG";
			break;
		default:
			namn = "-";
	}
	
	return namn;
}

void skrivVarde(vector<Betyg> lista) {
	int t_betyg = 0, t_poang = 0;
	double varde, vfull;
	
	for (int i = 0; i < lista.size(); i++) {
		if (lista.at(i).betyg >= 0) { //uteslut IB
			t_betyg += lista.at(i).betyg * lista.at(i).poang;
			t_poang += lista.at(i).poang;
		}
	}
	
	if ((t_betyg != 0) && (t_poang != 0)) {
		vfull = double(t_betyg) / t_poang; //räkna ut...
		varde = vfull * 10; //...och avrunda...
		varde += 0.5; //(korrekt avrundning.)
		varde = double(int(varde)) / 10; //...till en decimal. ugh.
	} else {
		varde = 0;
		vfull = 0;
	}
	
	cout << varde << (varde == int(varde) ? ".0" : "") << " (" << vfull << ")";
}

void mataIn(vector<Betyg>& lista){
	Betyg inmat;
	
	cout << "Mata in betyg, avsluta med # (som kursnamn)." << endl;
	cout << "(Betyg matas in som 'MVG', 'M' eller '20'. VERSALER/gemener kvittar. Skriv '-' för IB.)" << endl << endl;
	cout << "Kursnamn: ";
	getline(cin, inmat.kurs);
	while (inmat.kurs != "#") {
		cout << "Betyg: ";
		inmat.betyg = lasBetyg(cin);
		cout << "Kurspoäng: ";
		cin >> inmat.poang;
		cin.ignore(1000, '\n');
		lista.push_back(inmat);
		cout << endl;
		cout << "Kursnamn: ";
		getline(cin, inmat.kurs);
	}
	cout << endl << "Inmatning färdig.";
}

void skrivUt(vector<Betyg> lista) {
	clearScr();
	cout << HEADER << endl << HEADER2 << endl;
	if (lista.empty()) {
		cout << "Listan är tom!";
	} else {
		for (int i = 0; i < lista.size(); i++) {
			cout << lista.at(i).kurs << (lista.at(i).kurs.length() < 8 ? "\t" : "") << '\t' << skrivBetyg(lista.at(i).betyg) << '\t' << lista.at(i).poang << endl;
		}
		cout << endl << "Jämförelsevärde: ";
		skrivVarde(lista);
	}
}

void redigeraBetyg(vector<Betyg>& lista, int position) {
	if (position != -1) {
		char svar;
		
		cout << endl << endl << "Vill du redigera detta betyg (j/n)? ";
		cin >> svar;
		cin.ignore(1000, '\n');
		cout << endl;
		if (tolower(svar) == 'j') { //tolower() för att matcha både j och J.
			vector<Betyg>::iterator it = lista.begin() + position;
			do {
				cout << "Vad vill du ändra?" << endl;
				cout << "1. Kursnamn" << endl;
				cout << "2. Betyg" << endl;
				cout << "3. Poäng" << endl;
				cout << "4. Ingenting (Gå tillbaka)" << endl;
				cout << endl << "Val: ";
				cin >> svar;
				cin.ignore(1000, '\n');
				cout << endl;
				
				if (svar != '4') {
					cout << "Mata in ny betyginformation." << endl;
					cout << "(Betyg matas in som 'MVG', 'M' eller '20'. VERSALER/gemener kvittar. Skriv '-' för IB.)" << endl << endl;
				}
				switch (svar) {
					case '1':
						cout << "Nytt kursnamn: ";
						getline(cin, (*it).kurs);
						break;
					case '2':
						cout << "Nytt betyg: ";
						(*it).betyg = lasBetyg(cin);
						break;
					case '3':
						cout << "Ny kurspoäng: ";
						cin >> (*it).poang;
						cin.ignore(1000, '\n');
					case '4':
						break;
					default:
						cout << "Felaktigt val!" << endl;
				}
				if (svar != '4') {
					cout << endl << "Vill du ändra mer (j/n)? ";
					cin >> svar;
					cin.ignore(1000, '\n');
					cout << endl;
				}
			} while (tolower(svar) == 'j');
			cout << "Betyg redigerat.";
		} else {
			cout << "Operationen avbruten";
		}
	} //felutskrift tar sok() hand om.
}

void taBortBetyg(vector<Betyg>& lista, int position) {
	if (position != -1) {
		char svar;
		
		cout << endl << endl << "Vill du verkligen ta bort detta betyg ur listan (j/n)? ";
		cin >> svar;
		cin.ignore(1000, '\n');
		cout << endl;
		if (tolower(svar) == 'j') { //tolower() för att matcha både j och J.
			vector<Betyg>::iterator it = lista.begin() + position;
			lista.erase(it);
			cout << "Betyg borttaget.";
		} else {
			cout << "Operationen avbruten";
		}
	} //felutskrift tar sok() hand om.
}

int sok(vector<Betyg> lista) {
	int pos = -1;
	
	if (!lista.empty()) {
		string varde;
		
		cout << "Kursnamn: ";
		getline(cin, varde);
		cout << endl;
		
		for (int i = 0; (i < lista.size()) && (pos == -1); i++) {
			if (lista.at(i).kurs == varde) {
				pos = i;
			}
		}
		
		if (pos != -1) {
			cout << HEADER << endl << HEADER2 << endl;
			cout << lista.at(pos).kurs << (lista.at(pos).kurs.length() < 8 ? "\t" : "") << '\t' << skrivBetyg(lista.at(pos).betyg) << '\t' << lista.at(pos).poang;
		} else {
			cout << "Kursen hittades inte i listan!";
		}
	} else {
		cout << "Listan är tom!";
	}
	
	return pos;
}

void sortera(vector<Betyg>& lista) {
	if (!lista.empty()) {
		vector<Betyg>::iterator it1, it2;
		
		cout << "Sorterar.";
		for (it1 = lista.begin() + 1; it1 != lista.end(); it1++) {
			it2 = lista.begin();
			while ((it2 != it1) && ((*it2).kurs < (*it1).kurs)) {
				it2++;
			}
			lista.insert(it2,*it1);
			it2 = it1;
			lista.erase(++it2);
			cout << '.';
		}
		cout << " Färdig." << endl << endl;
		cout << "Listan är nu sorterad efter kursnamn.";
	} else {
		cout << "Listan är tom!";
	}
}

void skrivTillFil(vector<Betyg> lista){
	if (!lista.empty()) {
		char filnamn[100];
		ofstream utFil;
	
		cout << "Filnamn att skriva till (max 99 tecken): ";
		cin.get(filnamn, 100);
		cin.ignore(1000, '\n');
		cout << endl;

		utFil.open(filnamn);

		if (utFil) {
			cout << "Skriver till fil";
			utFil << FHEAD;
			for (int i = 0; i < lista.size(); i++) {
				utFil << endl << lista.at(i).kurs << '|' << skrivBetyg(lista.at(i).betyg) << '|' << lista.at(i).poang;
				cout << '.';
			}
			cout << " Färdig.";
			utFil.close();
		} else {
			cout << "Kunde inte öppna '" << filnamn << "' för skrivning!";
		}
	} else {
		cout << "Listan är tom!";
	}
}

void lasFranFil(vector<Betyg>& lista) {
	char filnamn[100], svar;
	ifstream inFil;
	string header;
	Betyg inlas;

	cout << "Filnamn att läsa in från (max 99 tecken): ";
	cin.get(filnamn, 100);
	cin.ignore(1000, '\n');
	cout << endl;

	inFil.open(filnamn);

	if (inFil) {
		getline(inFil, header);
		if (header == FHEAD) {
			if (!lista.empty()) {
				cout << "Vill du tömma din aktuella lista innan inläsning (j/n)? ";
				cin >> svar;
				cin.ignore(1000, '\n');
				cout << endl;
				if (svar == 'j') { //tolower() för att matcha både j och J.
					lista.clear();
					cout << "Listan tömd." << endl << endl;
				}
			}
			cout << "Läser från fil";
			while (getline(inFil, inlas.kurs, '|')) {
				inlas.betyg = lasBetyg(inFil, '|');
				inFil >> inlas.poang;
				inFil.ignore(1000, '\n'); //behövs på grund av getline().
				lista.push_back(inlas);
				cout << '.';
			}
			cout << " Färdig.";
		} else {
			cout << "Filen är inte skapad av detta programmet!";
		}
		inFil.close();
	} else {
		cout << "Kunde inte öppna '" << filnamn << "' för läsning!";
	}
}

void tom(vector<Betyg>& lista) {
	if (!lista.empty()) {
		char svar;
		
		cout << "Vill du verkligen tömma listan (j/n)? ";
		cin >> svar;
		cin.ignore(1000, '\n');
		cout << endl;
		if (tolower(svar) == 'j') { //tolower() för att matcha både j och J.
			lista.clear();
			cout << "Listan tömd.";
		} else {
			cout << "Operationen avbruten";
		}
	} else {
		cout << "Listan är redan tom!";
	}
}


