#include <klocale.h>
#include <kapplication.h>
#include <kaboutdata.h>
#include <kaboutapplication.h>
#include <qwidget.h>
#include <qlayout.h>
#include <qvgroupbox.h>
#include <qgrid.h>
#include <qlabel.h>
#include <qhbox.h>
#include <qpushbutton.h>
#include "version.h"
#include "mainwidget.h"

MainWidget::MainWidget(QWidget* parent) : QWidget(parent)
{
	QVBoxLayout* layout = new QVBoxLayout(this);

	QVGroupBox* groupBoxDates = new QVGroupBox(i18n("Dates"), this);
	QGrid* gridDate = new QGrid(4, Qt::Horizontal, groupBoxDates);
	new QLabel(i18n("First date:"), gridDate);
	m_comboboxFirstDay = new QComboBox(false, gridDate);
	m_comboboxFirstMonth = new QComboBox(false, gridDate);
	m_lineeditFirstYear = new QLineEdit(gridDate);
	new QLabel(i18n("Second date:"), gridDate);
	m_comboboxSecondDay = new QComboBox(false, gridDate);
	m_comboboxSecondMonth = new QComboBox(false, gridDate);
	m_lineeditSecondYear = new QLineEdit(gridDate);
	QHBox* hboxDateButtons = new QHBox(groupBoxDates);
	QPushButton* buttonCalculate = new QPushButton
		(i18n("Calculate difference"), hboxDateButtons);
	QObject::connect(buttonCalculate, SIGNAL(clicked()),
		this, SLOT(slotCalculate()));
	QHBox* hboxResult = new QHBox(groupBoxDates);
	new QLabel(i18n("Result:"), hboxResult);
	m_labelResult = new QLabel(hboxResult);
	layout->addWidget(groupBoxDates);

	QHBox* hboxMiscButtons = new QHBox(this);
	QPushButton* buttonClose = new QPushButton(i18n("Close"),
		hboxMiscButtons);
	QPushButton* buttonAbout = new QPushButton(i18n("About"),
		hboxMiscButtons);
	layout->addWidget(hboxMiscButtons);

	fillDays(m_comboboxFirstDay);
	fillMonths(m_comboboxFirstMonth);
	fillDays(m_comboboxSecondDay);
	fillMonths(m_comboboxSecondMonth);

	QObject::connect(buttonClose, SIGNAL(clicked()),
		this, SLOT(slotClose()));
	QObject::connect(buttonAbout, SIGNAL(clicked()),
		this, SLOT(slotAbout()));
}

void MainWidget::fillDays(QComboBox* comboBox)
{
	for (int i = 1; i <= 31; i++)
	{
		char text[256];
		sprintf(text, "%d", i);
		comboBox->insertItem(QString(text));
	}
}

void MainWidget::fillMonths(QComboBox* comboBox)
{
	comboBox->insertItem(i18n("January"));
	comboBox->insertItem(i18n("February"));
	comboBox->insertItem(i18n("March"));
	comboBox->insertItem(i18n("April"));
	comboBox->insertItem(i18n("May"));
	comboBox->insertItem(i18n("June"));
	comboBox->insertItem(i18n("July"));
	comboBox->insertItem(i18n("August"));
	comboBox->insertItem(i18n("September"));
	comboBox->insertItem(i18n("October"));
	comboBox->insertItem(i18n("November"));
	comboBox->insertItem(i18n("December"));
}

bool MainWidget::getDate(QComboBox* comboBoxDay, QComboBox* comboBoxMonth,
		QLineEdit* lineEditYear, int& day, int& month, int& year,
		QString& errorMessage)
{
	day = comboBoxDay->currentItem()+1;
	month = comboBoxMonth->currentItem()+1;
	QString yearText = lineEditYear->text();
	bool ok;
	year = yearText.toInt(&ok);
	if (!ok)
	{
		errorMessage = i18n("Year is not a number");
		return false;
	}
	return true;
}

bool MainWidget::validateDate(int day, int month, int year,
		QString& errorMessage)
{
	if ((year < 1583) || (year > 3000))
	{
		errorMessage = i18n("Year must be between 1583 and 3000");
		return false;
	}
	if ((month < 1) || (month > 12))
	{
		errorMessage = i18n("Month must be between 1 and 12");
		return false;
	}
	int lastDay = getLastDayOfGregorianMonth(month, year);
	if ((day < 1) || (day > lastDay))
	{
		errorMessage = i18n("Day must be between 1 and %1").arg(lastDay);
		return false;
	}
	return true;
}

int MainWidget::calculateDiff(int day1, int month1, int year1,
		int day2, int month2, int year2)
{
	int count1 = getDayCountFromStart(day1, month1, year1);
	int count2 = getDayCountFromStart(day2, month2, year2);
	return abs(count1-count2);
}

int MainWidget::getDayCountFromStart(int day, int month, int year)
{
	int result = 0;

	result += 365 * (year - 1);
	for (int y = 1; y < year; y++)
	{
		if (isGregorianLeapYear(y))
			result++;
	}

	for (int m = 1; m < month; m++)
		result += getLastDayOfGregorianMonth(m, year);

	result += (day-1);

	return result;
}

int MainWidget::getLastDayOfGregorianMonth(int month, int year)
{
	int table[] = {
		31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
	};
	if (month == 2 && isGregorianLeapYear(year))
		return 29;
	else
		return table[month-1];
}

bool MainWidget::isGregorianLeapYear(int year)
{
	if (year % 4 == 0)
	{
		if (year % 100 == 0)
		{
			if (year % 400 == 0)
				return true;
			else
				return false;
		}
		else
			return true;
	}
	else
		return false;
}

void MainWidget::slotCalculate()
{
	bool result;
	QString errorMessage, errorMessage2;
	int day1, month1, year1, day2, month2, year2;

	result = getDate(m_comboboxFirstDay, m_comboboxFirstMonth,
		m_lineeditFirstYear, day1, month1, year1, errorMessage);
	if (!result)
	{
		errorMessage2 = i18n("Error with first date: %1").arg(errorMessage);
		m_labelResult->setText(errorMessage2);
		return;
	}
	result = getDate(m_comboboxSecondDay, m_comboboxSecondMonth,
		m_lineeditSecondYear, day2, month2, year2, errorMessage);
	if (!result)
	{
		errorMessage2 = i18n("Error with second date: %1").arg(errorMessage);
		m_labelResult->setText(errorMessage2);
		return;
	}
	result = validateDate(day1, month1, year1, errorMessage);
	if (!result)
	{
		errorMessage2 = i18n("Error with first date: %1").arg(errorMessage);
		m_labelResult->setText(errorMessage2);
		return;
	}
	result = validateDate(day2, month2, year2, errorMessage);
	if (!result)
	{
		errorMessage2 = i18n("Error with second date: %1").arg(errorMessage);
		m_labelResult->setText(errorMessage2);
		return;
	}

	int difference = calculateDiff(day1, month1, year1, day2, month2, year2);
	char resultMsg[256];
	sprintf(resultMsg, "The difference in days is %d", difference);
	m_labelResult->setText(QString(resultMsg));
}

void MainWidget::slotClose()
{
	KApplication::kApplication()->quit();
}

void MainWidget::slotAbout()
{
	QString appName("kdiffdate");
	QString programName("kdiffdate");
	QString version(APP_VERSION);
	QString shortDescription(APP_SHORTDESCRIPTION);
	QString copyright(APP_COPYRIGHT);
	QString text(APP_TEXT);
	QString homepage(APP_HOMEPAGE);
	QString email(APP_EMAIL);
	KAboutData aboutData(appName, programName,
		version, shortDescription,
		KAboutData::License_GPL_V2, copyright,
		text, homepage, email);
	KAboutApplication aboutApp(&aboutData, this);
	aboutApp.exec();
}

