#include "main_window.h"

bool MainWindow::saveChangesBeforeProceeding(QString parentFunction, bool close)
{
	if (current_db_open && this->isWindowModified()) {
		switch (QMessageBox::information(this, parentFunction, tr("Save changes before proceeding?"), tr("&Save"), tr("&Discard"), tr("Cancel"), 0, 2)) {
			case 0: // Save
				current_db_open = false;
				save(); if (close) {closeDB();}; return false;
				break;
			case 1: // Discard
				current_db_open = false;
				if (close) {closeDB();}; return false;
				break;
			case 2: // Cancel
				return true;
				break;
		}
	} else if (current_db_open && (!this->isWindowModified())) {
		if (close) {closeDB();}; return false;
	}
	return false;
}

void MainWindow::newDB()
{
    this->setEnabled(false);
    // Save changes before proceeding?
    bool cancelled = saveChangesBeforeProceeding(tr("New database"), true);
    if (cancelled) { this->setEnabled(true); return; }
    // Creating database -------------------------------------------------------
    bool ok;
    QString db_name = QInputDialog::getText(this, tr("New database"), tr("Database name:"), QLineEdit::Normal, tr("Untitled database"), &ok);
    QString saveDBName;
    if (!ok) { this->setEnabled(true); return; }
    if (!db_name.isEmpty()) {
		saveDBName = QFileDialog::getSaveFileName(this, tr("Create database file"), tr("%1.itdb").arg(db_name), tr("iTest databases (*.itdb)"));
    } else {
		saveDBName = QFileDialog::getSaveFileName(this, tr("Create database file"), tr("untitled.itdb"), tr("iTest databases (*.itdb)"));
    }
    QFile file(saveDBName);
    if (!file.open(QFile::WriteOnly | QFile::Text)) 
    {
		QMessageBox::critical(this, tr("Create database file"), tr("Cannot write file %1:\n%2.").arg(saveDBName).arg(file.errorString()));
		this->setWindowTitle(tr("iTest - Database Editor"));
		this->setEnabled(true); return;
    }
	setProgress(10); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    QTextStream sfile(&file);
	sfile.setCodec("CP 1250");
	sfile << "[ITEST_VERSION]\n" << ver << endl;
	sfile << "[ITEST_DB_VERSION]\n" << db_ver << endl;
	sfile << "[DB_NAME]\n" << db_name << endl;
	sfile << "[DB_DATE]\n" << endl;
	sfile << "[DB_DATE_ULSD]\ntrue" << endl;
	sfile << "[DB_COMMENTS]\n" << endl;
	sfile << "[DB_QNUM]\n0" << endl;
	sfile << "[DB_SNUM]\n0" << endl;
	sfile << "[DB_FLAGS]" << endl;
	sfile << "--------------------\n";
	for (int i = 0; i < 20; ++i) {sfile << "[DB_F" << i << "]\n" << endl;}
	sfile << "[DB_FLAGS_END]";
	setProgress(50); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // APPLY
    enableAll(); clearAll();
    DBIDatabaseNameLineEdit->setText( db_name );
    current_db_file = saveDBName;
    current_db_name = db_name;
    current_db_open = true;
    addRecent(saveDBName);
    this->setWindowTitle(tr("%1[*] - iTest - Database Editor").arg(current_db_name));
    this->setWindowModified(false);
    statusBar()->showMessage(tr("Ready"), 10000);
    setProgress(100); setProgress(-1); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    actionEdit_questions->setChecked(true);
    actionUse_last_save_date->setChecked(true);
    DBIUseLastSaveDateCheckBox->setChecked(true);
    DBIDateEdit->setDateTime(QDateTime::currentDateTime());
    DBIDateEdit->setEnabled(false);
	setPage(actionEdit_questions);
    this->setEnabled(true);
    // -------------------------------------------------------------------------
}

void MainWindow::save() { saveDB(current_db_file); }

void MainWindow::saveAs()
{
    QString db_name = DBIDatabaseNameLineEdit->text();
    QString saveDBName = QFileDialog::getSaveFileName(this, tr("Save database"), QString("%1.itdb").arg(db_name), tr("iTest databases (*.itdb)"));
    if (!saveDBName.isNull() || saveDBName.isEmpty()) { addRecent(saveDBName); saveDB(saveDBName); }
}

void MainWindow::saveDB(QString db_file_name)
{
    this->setEnabled(false); qApp->processEvents();
    // Gather info
    QString db_name = DBIDatabaseNameLineEdit->text();
    QString use_last_save_date; QString db_date;
    if (actionUse_last_save_date->isChecked()) {
		db_date = QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm");
		use_last_save_date = "true";
    } else {
		db_date = DBIDateEdit->dateTime().toString("yyyy.MM.dd-hh:mm");
		use_last_save_date = "false";
    }
    QString db_comments = removeLineBreaks(ECTextEdit->toHtml());
    // Save database -----------------------------------------------------------
    QFile file(db_file_name);
    if (!file.open(QFile::WriteOnly | QFile::Text)) 
    {
		QMessageBox::critical(this, tr("Save database"), tr("Cannot write file %1:\n%2.").arg(db_file_name).arg(file.errorString()));
		this->setEnabled(true); return;
    }
    setProgress(5); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    QTextStream sfile(&file); QString q_file_name;
	sfile.setCodec("CP 1250");
    sfile << "[ITEST_VERSION]\n" << ver << endl;
    sfile << "[ITEST_DB_VERSION]\n" << db_ver << endl;
    sfile << "[DB_NAME]\n" << db_name << endl;
    sfile << "[DB_DATE]\n" << db_date << endl;
    sfile << "[DB_DATE_ULSD]\n" << use_last_save_date << endl;
    sfile << "[DB_COMMENTS]\n" << db_comments << endl;
    sfile << "[DB_QNUM]\n" << current_db_questions.size() << endl;
    sfile << "[DB_SNUM]\n" << current_db_sessions.size() << endl;
    sfile << "[DB_FLAGS]" << endl;
    for (int i = 0; i < 20; ++i) 
    {if (current_db_fe[i]) {sfile << "+";} else {sfile << "-";}} sfile << endl;
    for (int i = 0; i < 20; ++i) 
    {sfile << "[DB_F" << i << "]" << endl; sfile << current_db_f[i] << endl;}
    sfile << "[DB_FLAGS_END]" << endl;
    setProgress(10); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    int count = current_db_questions.size() + current_db_sessions.size();
    uint n = current_db_questions.size();
    for (int i = 0; i < LQListWidget->count(); ++i) {
		sfile << current_db_questions.value(LQListWidget->item(i))->allProperties() << endl;
		setProgress((90/(i+1)*count)+10); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>
    }
    QMapIterator<QDateTime, Session *> i(current_db_sessions);
    while (i.hasNext()) { i.next(); n++;
		sfile << i.value()->sessionData() << endl;
		for (int s = 0; s < i.value()->numStudents(); ++s) {
            sfile << i.value()->student(s)->studentData() << endl;
        }
		setProgress((90/n*count)+10); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>
    }
    current_db_name = db_name;
    current_db_date = db_date;
    current_db_comments = db_comments;
    current_db_file = db_file_name;
    if (actionUse_last_save_date->isChecked()) {
		DBIDateEdit->setDateTime(QDateTime::fromString(current_db_date, "yyyy.MM.dd-hh:mm"));
    }
    this->setWindowTitle(tr("%1[*] - iTest - Database Editor").arg(current_db_name));
    this->setWindowModified(false);
    statusBar()->showMessage(tr("Database saved"), 10000);
    setProgress(100); setProgress(-1); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // -------------------------------------------------------------------------
    this->setEnabled(true);
}

void MainWindow::open()
{
    // Save changes before proceeding?
    bool cancelled = saveChangesBeforeProceeding(tr("Open database"), true);
    if (!cancelled) {
    // Opening database --------------------------------------------------------
		QString openDBName = QFileDialog::getOpenFileName(this, tr("Open database file"), "", tr("iTest databases (*.itdb);;All files (*.*)"));
		if (!openDBName.isNull()) { addRecent(openDBName); openDB(openDBName); }
    }
}

void MainWindow::openRecent()
{
    if (recentDBsListWidget->currentIndex().isValid()) {
		addRecent(recentDBsListWidget->currentItem()->text());
		openDB(recentDBsListWidget->currentItem()->text());
    }
}

void MainWindow::openRecent(QListWidgetItem * item)
{
    QString buffer = item->text();
    addRecent(buffer);
    openDB(buffer);
}

void MainWindow::openDB(QString openDBName)
{
    if (openDBName.isNull()) { return; }
    this->setEnabled(false); qApp->processEvents();
    QFile file(openDBName);
    if (!file.open(QFile::ReadOnly | QFile::Text))
    {
		QMessageBox::critical(this, tr("Open database"), tr("Cannot read file %1:\n%2.").arg(openDBName).arg(file.errorString()));
		this->setEnabled(true); return;
    }
    setProgress(3); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    QTextStream rfile(&file);
	rfile.setCodec("CP 1250");

    QString db_buffer; float version; float db_version; QString db_name;
    QString db_date; QString db_comments; int db_qnum; bool db_fxxe[20];
    QString db_f[20]; QString q_file_name; QString db_ulsd; int s_lenum;
    QuestionItem * item; QStringList answers; int db_snum; int s_snum;
	QStringList bufferlist; QuestionItem::Answer ans;
	QuestionItem::Answer c_ans;
    // -------------------------------------------------------------------------
    db_buffer = rfile.readLine();
    if (db_buffer != "[ITEST_VERSION]")
    { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    db_buffer = rfile.readLine();
    version = db_buffer.toFloat();
    db_buffer = rfile.readLine();
    if (db_buffer != "[ITEST_DB_VERSION]")
    { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    db_buffer = rfile.readLine();
    db_version = db_buffer.toFloat();
    if ((version > f_ver) && (db_version == f_db_ver))
    { QMessageBox::information(this, tr("iTest version notice"), tr("There is a newer version of iTest available.\nNonetheless, this version is able to open the database file you selected,\nbut you are most probably missing a whole bunch of cool new features.")); }
    if ((version > f_ver) && (db_version > f_db_ver))
    { QMessageBox::critical(this, tr("iTest version notice"), tr("You need a newer version of iTest to open this database file.")); this->setEnabled(true); return; }

    if (rfile.readLine() != "[DB_NAME]")
    { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    // Database name
    db_name = rfile.readLine();
    if (rfile.readLine() != "[DB_DATE]")
    { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    // Database date
    db_date = rfile.readLine();
    if (rfile.readLine() != "[DB_DATE_ULSD]")
    { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    // Use last save date
    db_ulsd = rfile.readLine();
    if (rfile.readLine() != "[DB_COMMENTS]")
    { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    // Database comments
    db_comments = rfile.readLine();
    if (rfile.readLine() != "[DB_QNUM]")
    { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    // Question number
    db_qnum = rfile.readLine().toInt();
    if (rfile.readLine() != "[DB_SNUM]")
    { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    // Number of saved sessions
    db_snum = rfile.readLine().toInt();
    if (rfile.readLine() != "[DB_FLAGS]")
    { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    setProgress(6); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // fxxe
    db_buffer = rfile.readLine();
    for (int i = 0; i < 20; ++i) {
		if (db_buffer.at(i) == '+') {db_fxxe[i] = true;} else if (db_buffer.at(i) == '-')
		{db_fxxe[i] = false;} else { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    }
    // flags
    for (int i = 0; i < 20; ++i) {
		if (rfile.readLine() != QString("[DB_F%1]").arg(i)) { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		db_f[i] = rfile.readLine();
    }
    // End of flags
    if (rfile.readLine() != "[DB_FLAGS_END]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
    setProgress(10); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	int count = db_qnum + db_snum;
    // Questions
    for (int i = 0; i < db_qnum; ++i) {
		answers.clear();
		// Question name
		if (rfile.readLine() != "[Q_NAME]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		item = new QuestionItem (rfile.readLine());
		// Flag
		if (rfile.readLine() != "[Q_FLAG]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		item->setFlag(rfile.readLine().toInt());
		// Difficulty
		if (rfile.readLine() != "[Q_DIFFICULTY]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		item->setDifficulty(rfile.readLine().toInt());
		// Question text
		if (rfile.readLine() != "[Q_TEXT]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		item->setText(rfile.readLine());
		// Answer A
		if (rfile.readLine() != "[Q_ANSA]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		answers << rfile.readLine();
		if (rfile.readLine() != "[Q_ANSA_C]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		answers << rfile.readLine();
		// Answer B
		if (rfile.readLine() != "[Q_ANSB]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		answers << rfile.readLine();
		if (rfile.readLine() != "[Q_ANSB_C]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		answers << rfile.readLine();
		// Answer C
		if (rfile.readLine() != "[Q_ANSC]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		answers << rfile.readLine();
		if (rfile.readLine() != "[Q_ANSC_C]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		answers << rfile.readLine();
		// Answer D
		if (rfile.readLine() != "[Q_ANSD]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		answers << rfile.readLine();
		if (rfile.readLine() != "[Q_ANSD_C]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		answers << rfile.readLine();
		// Statistics
		if (rfile.readLine() != "[Q_ICNT]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		item->setIncorrectAnsCount(rfile.readLine().toUInt());
		if (rfile.readLine() != "[Q_CCNT]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		item->setCorrectAnsCount(rfile.readLine().toUInt());
		// End
		if (rfile.readLine() != "[Q_END]") { errorInvalidDBFile(tr("Open database"), openDBName); return; }
		// Add map entry
		item->setAnswers(answers);
		QListWidgetItem * q_item = new QListWidgetItem (item->name());
		LQListWidget->addItem(q_item);
		current_db_questions.insert(q_item, item);
		switch (item->difficulty()) {
			case 0: q_item->setIcon(QIcon(QString::fromUtf8(":/images/images/easy.png"))); break;
			case 1: q_item->setIcon(QIcon(QString::fromUtf8(":/images/images/medium.png"))); break;
			case 2: q_item->setIcon(QIcon(QString::fromUtf8(":/images/images/difficult.png"))); break;
			default: q_item->setIcon(QIcon(QString::fromUtf8(":/images/images/easy.png"))); break;
		}
		setQuestionItemColour(q_item, item->flag());
		setProgress((85/(i+1)*count)+10); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>
    }
	// Saved sessions
    for (int i = 0; i < db_qnum; ++i) {
		if (rfile.atEnd()) { break; }
		if (rfile.readLine() != "[SESSION]") { continue; }
		Session * session = new Session;
        session->setName(rfile.readLine());
		session->setDateTimeFromString(rfile.readLine());
		session->setPassMark(rfile.readLine().toInt());
		s_snum = rfile.readLine().toInt();
		s_lenum = rfile.readLine().toInt();
		for (int le = 0; le < s_lenum; ++le) {
			bufferlist.clear();
			bufferlist = rfile.readLine().split(';');
			if (bufferlist.count() == 6) {
				session->addLogEntry(bufferlist.at(0).toInt(),
									bufferlist.at(1).toInt(),
									bufferlist.at(2).toInt(),
									bufferlist.at(3).toInt(),
									bufferlist.at(4).toInt(),
									bufferlist.at(5).toInt(),
									rfile.readLine());
			} else {
				session->addLogEntry(255, 255, 255, 0, 0, 0, rfile.readLine());
			}
		}
		for (int s = 0; s < s_snum; ++s) {
			if (rfile.atEnd()) { break; }
			if (rfile.readLine() != "[STUDENT]") { continue; }
			Student * student = new Student (rfile.readLine());
			if (rfile.readLine() == "true") { student->setReady(true); }
			else { student->setReady(false); }
			student->setNumber(rfile.readLine().toInt());
			student->setScore(rfile.readLine().toInt());
			int numresults = rfile.readLine().toInt();
			QMap<QString, QuestionAnswer> * results = new QMap<QString, QuestionAnswer>;
			for (int a = 0; a < numresults; ++a) {
				db_buffer = rfile.readLine();
				ans = (QuestionItem::Answer)rfile.readLine().toInt();
				c_ans = (QuestionItem::Answer)rfile.readLine().toInt();
				QuestionAnswer qans (c_ans, ans);
				results->insert(db_buffer, qans);
			}
			student->setResults(results);
			session->addStudent(student);
		}
		current_db_sessions.insert(session->dateTime(), session);
		QListWidgetItem * item = new QListWidgetItem (QString("%1 - %2").arg(session->dateTimeToString()).arg(session->name()));
		VSSLSListWidget->insertItem(0, item);
        item->setData(Qt::UserRole, session->dateTime());
		setProgress((85/(db_qnum+i+1)*count)+10); // PROGRESS >>>>>>>>>>>>>>>>
    }
    // Set texts - DBI section
    DBIDatabaseNameLineEdit->setText( db_name );
    DBIDateEdit->setDateTime( QDateTime::fromString(db_date, "yyyy.MM.dd-hh:mm") );
    if (db_ulsd == "true") {
		DBIUseLastSaveDateCheckBox->setChecked(true);
		actionUse_last_save_date->setChecked(true);
		DBIDateEdit->setEnabled(false);
    } else if (db_ulsd == "false") {
		DBIUseLastSaveDateCheckBox->setChecked(false);
		actionUse_last_save_date->setChecked(false);
		DBIDateEdit->setEnabled(true);
    }
    ECTextEdit->setHtml( db_comments );
    // Set flags
    for (int i = 0; i < 20; ++i) {current_db_fe[i] = db_fxxe[i];}
    for (int i = 0; i < 20; ++i) {current_db_f[i] = db_f[i];}
    setProgress(97); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // Apply flags
    setFlags(); loadFlags();
    setProgress(98); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // Enable All
    enableAll();
    setProgress(99); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // Save values
    current_db_file = openDBName;
    current_db_name = db_name;
    current_db_date = db_date;
    current_db_comments = db_comments;
    current_db_open = true;
    this->setWindowTitle(tr("%1[*] - iTest - Database Editor").arg(current_db_name));
    this->setWindowModified(false);
    statusBar()->showMessage(tr("Database open"), 10000);
    setProgress(100); setProgress(-1); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    actionEdit_questions->setChecked(true);
	mainStackedWidget->setCurrentIndex(1); updateGeometry();
    // -------------------------------------------------------------------------
    this->setEnabled(true);
}

void MainWindow::closeDB()
{
	// Save changes before proceeding?
	bool cancelled = saveChangesBeforeProceeding(tr("Close database"), false);
	if (!cancelled) {
	// Closing database --------------------------------------------------------
	clearAll(); disableAll(); current_db_open = false;
	this->setWindowTitle(tr("iTest - Database Editor"));
	this->setWindowModified(false);
	setProgress(100); setProgress(-1); // PROGRESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	mainStackedWidget->setCurrentIndex(0); updateGeometry();
	statusBar()->showMessage(tr("Database closed"), 10000);
	// -------------------------------------------------------------------------
	}
}