/***************************************************************************
 *   Copyright (C) 2010 by Volker Lanz <vl@fidra.de>                       *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
 ***************************************************************************/

#include "gui/athletelogpage.h"
#include "gui/athletelogtree.h"

#include "core/profile.h"

#include "veneer/settings.h"
#include "veneer/datetime.h"
#include "veneer/messagebox.h"
#include "veneer/filedialog.h"
#include "veneer/iconloader.h"

#include "util/unit.h"
#include "util/helpers.h"

#include <kicon.h>

#include <QTreeWidgetItem>
#include <QDebug>
#include <QMessageBox>

AthleteLogPage::AthleteLogPage(QWidget* parent) :
	QWidget(parent),
	m_Profile(NULL)
{
	setupUi(this);

	init();
	setupConnections();
}

void AthleteLogPage::init()
{
	clear();

	addAthleteLogButton->setIcon(BarIcon("list-add"));
	removeAthleteLogButton->setIcon(BarIcon("list-remove"));

	athleteLogTree->header()->setContextMenuPolicy(Qt::CustomContextMenu);
}

void AthleteLogPage::initTree()
{
	clear();

	if (m_Profile == NULL)
		return;

	foreach(AthleteLog* log, m_Profile->athleteLogs())
		athleteLogTree->add(log);

	on_athleteLogTree_selectedAthleteLogChanged();
}

void AthleteLogPage::loadConfig()
{
	loadTreeWidgetHeaderConfig(athleteLogTree, Veneer::Settings::self()->athleteLogTreeColumnWidths(), Veneer::Settings::self()->athleteLogTreeColumnPositions(), Veneer::Settings::self()->athleteLogTreeColumnVisible());
	athleteLogSplitter->setSizes(Veneer::Settings::self()->athleteLogPageSplitterSizes());
}

void AthleteLogPage::saveConfig()
{
	Veneer::Settings::self()->setAthleteLogTreeColumnPositions(treeViewHeaderColPositions(athleteLogTree));
	Veneer::Settings::self()->setAthleteLogTreeColumnVisible(treeViewHeaderColVisible(athleteLogTree));
	Veneer::Settings::self()->setAthleteLogTreeColumnWidths(treeViewHeaderColWidths(athleteLogTree));
	Veneer::Settings::self()->setAthleteLogPageSplitterSizes(athleteLogSplitter->sizes());
}

void AthleteLogPage::setupConnections()
{
	connect(athleteLogTree->header(), SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(onHeaderContextMenu(const QPoint&)));
	connect(athleteLogTree, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(onContextMenu(const QPoint&)));
}

void AthleteLogPage::clear()
{
	foreach(QSpinBox* spin, qFindChildren<QSpinBox*>(this))
		spin->setValue(0);

	weightSpin->setValue(0.0);
	athleteLogDateEdit->setDate(QDate::currentDate());
	sleepDurationTime->setTime(QTime());
	athleteLogNotesEdit->clear();
	athleteLogPhotoButton->setIcon(KIcon());
}

void AthleteLogPage::onHeaderContextMenu(const QPoint& p)
{
	showColumnsContextMenu(p, *athleteLogTree);
}

void AthleteLogPage::on_athleteLogTree_athleteLogChanged(AthleteLog*, int col)
{
	on_athleteLogTree_selectedAthleteLogChanged();

	switch(col)
	{
		case AthleteLogTree::dateCol:              emit dateChanged(); break;
		case AthleteLogTree::weightCol:            emit weightChanged(); break;;
		case AthleteLogTree::bodyFatPercentCol:    emit bodyFatPercentageChanged(); break;
		case AthleteLogTree::restingHRCol:         emit restingHeartRateChanged(); break;
		case AthleteLogTree::maxHRCol:             emit maxHeartRateChanged(); break;
		case AthleteLogTree::bloodPressureCol:
			emit bloodPressureDiastolicChanged();
			emit bloodPressureSystolicChanged();
			break;
		case AthleteLogTree::energyConsCol:        emit energyConsumptionChanged(); break;
		case AthleteLogTree::sleepDurationCol:     emit sleepDurationChanged(); break;
		default:
			qWarning() << "unknown column " << col << " changed for athlete log tree entry.";
			break;
	}
}

void AthleteLogPage::on_athleteLogTree_selectedAthleteLogChanged()
{
	addAthleteLogButton->setEnabled(m_Profile != NULL);
	removeAthleteLogButton->setEnabled(selectedAthleteLogs().size() > 0);

	foreach(QSpinBox* spin, qFindChildren<QSpinBox*>(this))
		spin->setEnabled(selectedAthleteLogs().size() == 1);

	foreach(QDoubleSpinBox* spin, qFindChildren<QDoubleSpinBox*>(this))
		spin->setEnabled(selectedAthleteLogs().size() == 1);

	athleteLogDateEdit->setEnabled(selectedAthleteLogs().size() == 1);
	sleepDurationTime->setEnabled(selectedAthleteLogs().size() == 1);
	athleteLogNotesEdit->setEnabled(selectedAthleteLogs().size() == 1);
	athleteLogPhotoButton->setEnabled(selectedAthleteLogs().size() == 1);

	foreach(QWidget* w, qFindChildren<QWidget*>(this))
		w->blockSignals(true);

	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		athleteLogDateEdit->setDate(log->date());
		Unit::setSpinBoxWeight(*weightSpin, log->weight());
		bodyFatSpin->setValue(log->bodyFatPercent());
		hrRestingSpin->setValue(log->restingHeartRate());
		hrMaxSpin->setValue(log->maxHeartRate());
		bpSystolicSpin->setValue(log->bloodPressureSystolic());
		bpDiastolicSpin->setValue(log->bloodPressureDiastolic());
		Unit::setSpinBoxEnergy(*energyConsumptionSpin, log->energyConsumption());
		sleepDurationTime->setTime(QTime().addSecs(log->sleepDuration() * 60));
		athleteLogNotesEdit->setText(log->notes());
		athleteLogPhotoButton->setIcon(log->photo());
	}
	else
		clear();

	foreach(QWidget* w, qFindChildren<QWidget*>(this))
		w->blockSignals(false);

	emit selectedAthleteLogChanged(selectedAthleteLogs().size() > 0 ? selectedAthleteLogs()[0] : NULL);
}

void AthleteLogPage::on_addAthleteLogButton_clicked(bool)
{
	AthleteLog* a = new AthleteLog();;
	a->setDate(QDate::currentDate());

	m_Profile->athleteLogs().append(a);
	athleteLogTree->add(a);
	m_Profile->setDirty(true);
	emit athleteLogChanged();
}

bool AthleteLogPage::on_removeAthleteLogButton_clicked(bool)
{
	if (selectedAthleteLogs().size() < 1)
		return false;

	QStringList athleteLogNames;

	foreach (const AthleteLog* log, selectedAthleteLogs())
		athleteLogNames << Veneer::formatLongDate(log->date());

	if (Veneer::messageBoxQuestionYesNoList(this,
			tr("Are you sure you want to delete these athlete log entries?"),
			athleteLogNames,
			tr("Really Delete Entries?"),
			tr("Delete Entries"),
			tr("Cancel"),
			"deleteAthleteLogWarning") == QMessageBox::No)
		return false;

	foreach(AthleteLog* log, selectedAthleteLogs())
	{
		log->setRemoved(true);
		athleteLogTree->remove(log);
	}

	emit athleteLogChanged();

	return true;
}

void AthleteLogPage::setProfile(Profile* p)
{
	m_Profile = p;

	on_athleteLogTree_selectedAthleteLogChanged();

	athleteLogTree->clear();
	athleteLogTree->setProfile(m_Profile);

	initTree();
}

AthleteLogs AthleteLogPage::selectedAthleteLogs()
{
	return athleteLogTree->selectedAthleteLogs();
}

void AthleteLogPage::on_athleteLogDateEdit_dateChanged(const QDate& date)
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		log->setDate(date);
		athleteLogTree->updateEntry(log);
		emit dateChanged();
	}
}

void AthleteLogPage::on_weightSpin_valueChanged(double val)
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		val *= 1000;

		if (Veneer::Settings::self()->measureSystem() == Veneer::Settings::EnumMeasureSystem::Imperial)
			val = Unit::toMetricWeight(val);

		log->setWeight(val);
		athleteLogTree->updateEntry(log);
		emit weightChanged();
	}
}

void AthleteLogPage::on_bodyFatSpin_valueChanged(int val)
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		log->setBodyFatPercent(val);
		athleteLogTree->updateEntry(log);
		emit bodyFatPercentageChanged();
	}
}

void AthleteLogPage::on_hrRestingSpin_valueChanged(int val)
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		log->setRestingHeartRate(val);
		athleteLogTree->updateEntry(log);
		emit restingHeartRateChanged();
	}
}

void AthleteLogPage::on_hrMaxSpin_valueChanged(int val)
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		log->setMaxHeartRate(val);
		athleteLogTree->updateEntry(log);
		emit maxHeartRateChanged();
	}
}

void AthleteLogPage::on_bpSystolicSpin_valueChanged(int val)
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		log->setBloodPressureSystolic(val);
		athleteLogTree->updateEntry(log);
		emit bloodPressureSystolicChanged();
	}
}

void AthleteLogPage::on_bpDiastolicSpin_valueChanged(int val)
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		log->setBloodPressureDiastolic(val);
		athleteLogTree->updateEntry(log);
		emit bloodPressureDiastolicChanged();
	}
}

void AthleteLogPage::on_energyConsumptionSpin_valueChanged(int val)
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		log->setEnergyConsumption(Veneer::Settings::self()->energyUnit() == Unit::kcal ? Unit::toKiloJoule(val) : val);
		athleteLogTree->updateEntry(log);
		emit energyConsumptionChanged();
	}
}

void AthleteLogPage::on_sleepDurationTime_timeChanged(const QTime& time)
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		log->setSleepDuration(time.hour() * 60 + time.minute());
		athleteLogTree->updateEntry(log);
		emit sleepDurationChanged();
	}
}

void AthleteLogPage::on_athleteLogNotesEdit_textChanged()
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];
		log->setNotes(athleteLogNotesEdit->toPlainText());
		athleteLogTree->updateEntry(log);
		emit notesChanged();
	}
}

void AthleteLogPage::on_athleteLogPhotoButton_clicked(bool)
{
	if (selectedAthleteLogs().size() == 1)
	{
		AthleteLog* log = selectedAthleteLogs()[0];

		QString fileName = Veneer::getOpenFileName(this, "kfiledialog://athleteLogPhoto");

		if (fileName.isEmpty())
			return;

		QPixmap photo;

		if (!photo.load(fileName))
		{
			qWarning() << "could not load photo from " << fileName;
			return;
		}

		photo = photo.scaled(athleteLogPhotoButton->width() - 10, athleteLogPhotoButton->height() - 10, Qt::KeepAspectRatio);
		athleteLogPhotoButton->setIcon(photo);

		log->setPhoto(photo);
		emit photoChanged();
	}
}

void AthleteLogPage::onContextMenu(const QPoint& p)
{
	emit contextMenuRequested(mapToGlobal(p));
}

void AthleteLogPage::onSelectAll()
{
	athleteLogTree->selectAll();
}
