//Main Program
#include <iomanip>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <conio.h>

#include "lista_polje.h"
//#include "lista_pokazivac.h"

using namespace std;
tlista *pom_lista = new tlista;

//dodatna funkcija
void unesi(char *znakovni_niz)
{
	cin.getline(znakovni_niz, 100);
	if (cin.gcount()==1)
	  	 cin.getline (znakovni_niz,100);
};

//dodatna funckcija
void s_ispis (tgame igra) {
	cout << "-----------------------------------" << endl;
	cout << "Sifra: " << igra.sifra << endl;
	cout << "Naziv: " << igra.naziv << endl;
	cout << "Proizvodjac: " << igra.proizvodjac << endl;
	cout << "Zanr: " << igra.zanr << endl;
	cout << "Podzanr: " << igra.podzanr << endl;
	cout << "PEGI: " << igra.pegi << endl;
	cout << "-----------------------------------" << endl;
}

//dodatna funckcija
int broj_igara (tlista *lista) {
	int counter = 0;
	vrijed i = firstL(lista);
	while (i != endL(lista)) {
		counter++;	
		i = nextL(i,lista);
	}
	return counter;
}

//generiranje alfanumericke sifre
void generate (char *znakovi) {
	char alfaniz [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
	for (int i = 0; i < 6; i++) {
		znakovi[i] = alfaniz[rand() % (strlen(alfaniz)-1)];
	}
	znakovi[6] = '\0';
}

//merge sort - spajanje elemenata
void merge (tgame *polje, int beg1, int end1, int beg2, int end2){
	int i = 0, l = beg1, k;
	tgame sorted[100];
	while (beg1 <= end1 && beg2 <= end2) {
		if (strcmp(polje[beg1].sifra, polje[beg2].sifra) < 0)
			sorted[i++] = polje[beg1++];
		else
			sorted[i++] = polje[beg2++];
	}
	while (beg1 <= end1)
		sorted[i++] = polje[beg1++];
	while (beg2 <= end2)
		sorted[i++] = polje[beg2++];
	for (k = 0; k < i; k++)
		polje[l++] = sorted[k];
}

//merge sort - dijeljenje niza do pojedinacnih elemenata		
void sort (tgame *polje, int beg, int end) {
	if (beg < end) {
		int mid = (beg + end) / 2;
		sort(polje,beg,mid);
		sort(polje,mid+1,end);
		merge(polje,beg,mid,mid+1,end);
	}
}

//ispis sortiranog polja uzlazno prema sifri
void sort_ispis(tlista *lista) {
	int broji = 0;
	tgame polje[100];
	
	vrijed i = firstL(lista);
	while (i != endL(lista)) {
		polje[broji++] = retrieveL(i,lista);
		i = nextL(i,lista);
	}
	
	sort (polje, 0, broji-1);
	
	//ispis sortiranog polja (NAPOMENA: polje se moglo natrag prebaciti u listu i zatim 
	//normalno ispisati iz gl.programa -> to zahtijeva ponovno brisanje elemenata liste)
	int brojac = 0;
	for (int j = 0; j < broji; j++) {
		cout << ++brojac << ". igra" << endl;
		cout << "---------------------------------" << endl;
		cout << "Sifra: " << polje[j].sifra << endl;
		cout << "Naziv: " << polje[j].naziv << endl;
		cout << "Zanr: " << polje[j].zanr << endl;
		cout << "PEGI: " << polje[j].pegi << endl;
		cout << "---------------------------------" << endl;
		cout << endl;			
	}
}

//unošenje igara u bazu podataka
int unos(tlista *lista) {
	tgame element;
	cout << "Unesite zanr igre: ";
	unesi(element.zanr);
	cout << "Unesite podzanr igre: ";
	unesi(element.podzanr);
	generate(element.sifra);
	cout << "Izgenerirana sifra: " << element.sifra << endl;
	cout << "Unesite naziv igre: ";
	unesi(element.naziv);
	cout << "Unesite proizvodjaca igre: ";
	unesi(element.proizvodjac);
	do {
		cout << "Unesite PEGI oznaku: ";
		cin >> element.pegi;
		if (element.pegi != 3 && element.pegi != 7 &&
			element.pegi != 12 && element.pegi != 16 &&
			element.pegi != 18)
				cout << "Neispravan unos PEGI oznake" << endl;
	} while (element.pegi != 3 && element.pegi != 7 &&
			element.pegi != 12 && element.pegi != 16 &&
			element.pegi != 18);
	cout << endl;
	if (insertL(element,endL(lista),lista) == 1)
		return 1;
	else
		return 0;
}

//binarno pretraživanje
void bsearch (tgame *polje, int beg, int end, char kljuc [100]) {
	if 	(end-beg <= 0)
		if (beg == end && strcmp(polje[beg].zanr, kljuc) == 0)
			insertL(polje[beg],endL(pom_lista),pom_lista);
		else
			return;
	else {
		int mid = (beg+end) / 2;
		if (strcmp(polje[mid].zanr, kljuc) > 0)
			return bsearch(polje,beg,mid-1,kljuc);
		if (strcmp(polje[mid].zanr, kljuc) == 0) {
			insertL(polje[mid],endL(pom_lista),pom_lista);
			while (beg <= end) { //dodatno u binsearchu
				if ((strcmp(polje[beg].zanr, kljuc) == 0) && beg != mid)
					insertL(polje[beg],endL(pom_lista),pom_lista);
				beg++;
			}
			return;
		}
		if (strcmp(polje[mid].zanr, kljuc) < 0)
			return bsearch(polje,mid+1,end,kljuc);
	}
}

//ispis strateških igara
void strategy(tlista *lista) {
	int brojac = 0;
	int br_strat = 0;
	initL(pom_lista);
	int counter = broj_igara(lista);
	tgame *pom = new tgame [counter];
	vrijed i = firstL(lista);
	int j = 0;
	while ( i != endL(lista)) {
		pom[j++] = retrieveL(i,lista);
		i = nextL(i,lista);
	}

	for (int k = 1; k < counter; k++) {
		int l = k-1;
		tgame pom1 = pom[k];
		while (l >= 0 && strcmp(pom[l].zanr, pom1.zanr) > 0)
			pom[l+1] = pom[l--];
		pom[l+1] = pom1;
	}
	
	char kljuc[100];
	strcpy(kljuc,"Strategija");
	
	bsearch(pom,0,counter-1,kljuc);
	i = firstL(pom_lista);
	if (i == endL(pom_lista))
		cout << "Ne postoji niti jedna strateska igra u bazi" << endl;
	else {
		while ( i != endL(pom_lista)) {
			cout << ++brojac << ". igra" << endl;
			s_ispis(retrieveL(i,pom_lista));
			i = nextL (i,lista);
			br_strat++;
			cout << endl;
		}
		cout << "Broj strateskih igara: " << br_strat << endl;
		delete [] pom;
		deleteallL(pom_lista);
	}
}

//brisanje igara prema šifri
int brisi_sifra(tlista *lista) {
	char odabir;
	tgame igra;
	char sifra[6];
	cout << "Popis postojecih sifri: " << endl;
	for (vrijed i = firstL(lista); i != endL(lista); i = nextL(i,lista)) {
		igra = retrieveL(i,lista);
		cout << "-->" << igra.sifra << endl;
	}
	cout << endl;
	cout << "Unesite sifru koju zelite izbrisati: ";
	do {
		unesi(sifra);
	if(strlen(sifra) < 6 || strlen(sifra) > 6)
		cout << "Sifra mora imati tocno 6 znakova. Ponovni unos: ";
	} while (strlen(sifra) < 6 || strlen(sifra) > 6);
	vrijed i = locateL(sifra,lista);
	if (i != endL (lista)) {
		igra = retrieveL(i,lista);
		s_ispis(igra);
		cout << "Zelite li potvrditi brisanje zapisa(d/n): ";
		cin >> odabir;
		if (odabir == 'd') {
			deleteL(i,lista);
			return 1;
		}
		return 0;
	}
	else
		return 0;
}

//brisanje igara sa određenom pegi oznakom
int brisi_pegi(tlista *lista) {
	int pegi, provjera = 0;;
	tgame igra;
	vrijed iduci;
	cout << "Unesite PEGI oznaku(3,7,12,16,18): ";
	cin >> pegi;
	if (pegi != 3 && pegi != 7 && pegi != 12 && pegi != 16 && pegi != 18)
		return 0;
	vrijed i = firstL(lista);
	while (i != endL(lista)) {
		igra = retrieveL(i,lista);
		iduci = nextL(i,lista);
		if (igra.pegi == pegi) {
			deleteL(i,lista);
			provjera = 1;
			i = firstL(lista);
		}
		else
			i = iduci;
	}
	if (provjera == 1)
		return 1;
	else
		return 0;	
}

int main() {
	srand(time(0)); //za funkciju generate (generiranje alfanumerickoga koda od 6 znakova)
	initL(lista); //inicijalizacija prazne liste
	int izbor;
	do {
		
		//glavni izbornik
		system("cls");
		cout << "*********************IZBORNIK*********************" << endl;
		cout << "1. Unos podataka o racunalnoj igri" << endl;
		cout << "2. Ispis igara prema sifri (pomocu MergeSorta)" << endl;
		cout << "3. Strateske racunalne igre(pomocu BSearcha)" << endl;
		cout << "4. Brisanje igara (prema sifriI)" << endl;
		cout << "5. Brisanje svih igara sa odredjenom PEGI oznakom" << endl;
		cout << "9. Izlaz iz programa" << endl;
		cout << "**************************************************" << endl;
		cout << "Unesite mogucnost: "; cin >> izbor;
		cout << endl;
		
		switch (izbor) { //switch grananje s obzirom na odabranu mogucnost, tj. koju funkciju smo pokrenuli
			case 1:
				if(unos(lista) == 1)
					cout << "ZAPIS JE USPJESNO DODAN!" << endl;
				else
					cout << "DODAVANJE ZAPISA NIJE USPJELO!" << endl;
				cout << endl;
				cout << "Vracanje u izbornik - ENTER ";
				getch();
				break;	
			
			case 2:
				cout << "****SORTIRANI ISPIS POLJA****" << endl;
				sort_ispis(lista);
				cout << endl;
				cout << "Vracanje u izbornik - ENTER ";
				getch();
				break;
			
			case 3:
				cout << "****ISPIS STRATESKIH IGARA****" << endl;
				strategy (lista);
				cout << endl;
				cout << "Vracanje u izbornik - ENTER ";
				getch();
				break;
				
			case 4:
				cout << "****BRISANJE PO SIFRI****" << endl;
				if (brisi_sifra(lista) == 1)
					cout << "BRISANJE USPJESNO!" << endl;
				else
					cout << "BRISANJE NEUSPJESNO!" << endl;
				cout << endl;
				cout << "Vracanje u izbornik - ENTER ";
				getch();
				break;
			
			case 5:
				cout << "****BRISANJE PO PEGI OZNACI****" << endl;
				if (brisi_pegi(lista) == 1)
					cout << "BRISANJE USPJESNO" << endl;
				else {
					cout << "BRISANJE NEUSPJESNO!" << endl;
					cout << "POGRESAN PEGI ILI NEPOSTOJI ZAPIS SA PEGI OZNAKOM!" << endl;
				}
				cout << endl;
				cout << "Vracanje u izbornik - ENTER ";
				getch();
				break;
		}
	} while (izbor != 9);
	
	return 0;
}