/***************************************************************************
 *   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/activitypage.h"

#include "core/activity.h"
#include "core/category.h"
#include "core/equipment.h"
#include "core/profile.h"

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

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

#include <QDebug>
#include <QMessageBox>

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

	init();
	setupConnections();
}

void ActivityPage::init()
{
	weatherCombo->clear();

	QStringList::const_iterator i = Weather::icons().constBegin();
	QStringList::const_iterator j = Weather::descriptions().constBegin();

	while (i != Weather::icons().constEnd())
		weatherCombo->addItem(SmallIcon(*i++), *j++);

	clear();

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

void ActivityPage::loadConfig()
{
	loadTreeWidgetHeaderConfig(activitiesTree, Veneer::Settings::self()->activitiesTreeColumnWidths(), Veneer::Settings::self()->activitiesTreeColumnPositions(), Veneer::Settings::self()->activitiesTreeColumnVisible());
	activityPageSplitter->setSizes(Veneer::Settings::self()->activityPageSplitterSizes());
}

void ActivityPage::saveConfig()
{
	Veneer::Settings::self()->setActivitiesTreeColumnPositions(treeViewHeaderColPositions(activitiesTree));
	Veneer::Settings::self()->setActivitiesTreeColumnVisible(treeViewHeaderColVisible(activitiesTree));
	Veneer::Settings::self()->setActivitiesTreeColumnWidths(treeViewHeaderColWidths(activitiesTree));
	Veneer::Settings::self()->setActivityPageSplitterSizes(activityPageSplitter->sizes());
}

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

void ActivityPage::clear()
{
	foreach (QDoubleSpinBox* w, qFindChildren<QDoubleSpinBox*>(this))
		w->setValue(0);

	foreach (QComboBox* w, qFindChildren<QComboBox*>(this))
		w->setCurrentIndex(0);

	foreach (QLineEdit* w, qFindChildren<QLineEdit*>(this))
		w->clear();

	notesEdit->clear();
}

void ActivityPage::updateCategories(Categories& cats)
{
	categoryCombo->blockSignals(true);
	categoryCombo->clear();
	Category::toComboBox(categoryCombo, cats);
	categoryCombo->blockSignals(false);
}

void ActivityPage::updateEquipments(Equipments& eqs)
{
	equipmentCombo->blockSignals(true);
	equipmentCombo->clear();
	Equipment::toComboBox(equipmentCombo, eqs);
	equipmentCombo->blockSignals(false);
}

void ActivityPage::updateDetails()
{
	foreach(QSpinBox* spin, qFindChildren<QSpinBox*>(this))
		spin->setEnabled(selectedActivities().size() == 1);

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

	foreach(QLineEdit* edit, qFindChildren<QLineEdit*>(this))
		edit->setEnabled(selectedActivities().size() == 1);

	foreach(QComboBox* combo, qFindChildren<QComboBox*>(this))
		combo->setEnabled(selectedActivities().size() == 1);

	notesEdit->setEnabled(selectedActivities().size() == 1);

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

	if (selectedActivities().size() == 1)
	{
		Activity* a = selectedActivities()[0];

		dateEdit->setText(Veneer::formatShortDate(a->timeStamp().date()));
		timeEdit->setText(Veneer::formatTime(a->timeStamp().toLocalTime().time()));

		nameEdit->setText(a->name());

		const int idxCat = categoryCombo->findData(QVariant::fromValue<Category*>(a->category()));
		categoryCombo->setCurrentIndex(idxCat);

		const int idxEquip = equipmentCombo->findData(QVariant::fromValue<Equipment*>(a->equipment()));
		equipmentCombo->setCurrentIndex(idxEquip);

		Unit::setSpinBoxDistance(*distanceSpin, a->totalDistance());
		avgPaceEdit->setText(Unit::formatPace(a->averagePace()));

		Unit::setSpinBoxHeight(*ascentSpin, a->totalAscent());
		Unit::setSpinBoxHeight(*descentSpin, a->totalDescent());

		Unit::setSpinBoxSpeed(*maxSpeedSpin, a->maxSpeed());
		Unit::setSpinBoxSpeed(*avgSpeedSpin, a->averageSpeed());

		Unit::setSpinBoxEnergy(*energySpin, a->energyConsumption());

		avgCadenceSpin->setValue(a->averageCadence());

		avgHeartRateSpin->setValue(a->averageHeartRate());
		maxHeartRateSpin->setValue(a->maxHeartRate());

		Unit::setSpinBoxTemperature(*temperatureSpin, a->temperature());
		weatherCombo->setCurrentIndex(a->weather());
		weatherDescriptionEdit->setText(a->weatherDescription());

		notesEdit->setText(a->notes());
	}
	else
		clear();

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

void ActivityPage::on_activitiesTree_activityChanged(Activity*, int column)
{
	if (column == ActivityTree::nameCol)
		emit nameChanged();

	// nothing else can be edited in the activity tree

	updateDetails();
}

// TODO: allow changing of date and time in the GUI and add a slot here.
// TODO: allow overwriting calculated values (like total distance) and add slots here

void ActivityPage::on_nameEdit_editingFinished()
{
	if (selectedActivities().size() == 1)
	{
		Activity* a = selectedActivities()[0];
		a->setName(nameEdit->text());
		activitiesTree->activityChanged();
		emit nameChanged();
	}
}

void ActivityPage::on_categoryCombo_currentIndexChanged(int)
{
	Category* c = categoryCombo->itemData(categoryCombo->currentIndex()).value<Category*>();

	Q_ASSERT(c);

	if (selectedActivities().size() == 1 && c != NULL)
	{
		Activity* a = selectedActivities()[0];
		a->setCategory(c);
		activitiesTree->activityChanged();
		emit categoryChanged();
	}
}

void ActivityPage::on_equipmentCombo_currentIndexChanged(int)
{
	Equipment* e = equipmentCombo->itemData(equipmentCombo->currentIndex()).value<Equipment*>();

	if (selectedActivities().size() == 1)
	{
		Activity* a = selectedActivities()[0];
		a->setEquipment(e);
		activitiesTree->activityChanged();
		emit equipmentChanged();
	}
}

void ActivityPage::on_temperatureSpin_valueChanged(double value)
{
	if (selectedActivities().size() == 1)
	{
		Activity* a = selectedActivities()[0];

		if (Veneer::Settings::self()->measureSystem() == Veneer::Settings::EnumMeasureSystem::Imperial)
			value = Unit::toCelsius(value);

		a->setTemperature(value * 10.0);
		activitiesTree->activityChanged();
		emit temperatureChanged();
	}
}

void ActivityPage::on_weatherCombo_currentIndexChanged(int)
{
	if (selectedActivities().size() == 1)
	{
		Activity* a = selectedActivities()[0];
		a->setWeather(static_cast<Weather::Condition>(weatherCombo->currentIndex()));
		activitiesTree->activityChanged();
		emit weatherChanged();
	}
}

void ActivityPage::on_weatherDescriptionEdit_editingFinished()
{
	if (selectedActivities().size() == 1)
	{
		Activity* a = selectedActivities()[0];
		a->setWeatherDescription(weatherDescriptionEdit->text());
		activitiesTree->activityChanged();
		emit windChanged();
	}
}

void ActivityPage::on_notesEdit_textChanged()
{
	if (selectedActivities().size() == 1)
	{
		Activity* a = selectedActivities()[0];
		a->setNotes(notesEdit->toPlainText());
		activitiesTree->activityChanged();
		emit notesChanged();
	}
}

void ActivityPage::on_activitiesTree_selectedActivityChanged()
{
	updateDetails();
	emit selectionChanged();
}

Activities ActivityPage::selectedActivities()
{
	return activitiesTree->selectedActivities();
}


void ActivityPage::onHeaderContextMenu(const QPoint& p)
{
	showColumnsContextMenu(p, *activitiesTree);
}

void ActivityPage::showActivitiesForCategory(Category* cat)
{
	const Activity* const oldSelectedActivity = selectedActivities().size() == 1 ? selectedActivities()[0] : NULL;

	activitiesTree->clear();

	if (m_Profile != NULL && cat != NULL)
	{
		foreach(Activity* activity, m_Profile->activities())
		{
			if (activity->isRemoved())
				continue;

			if (Category::indirectlyContains(cat, activity->category()))
			{
				activitiesTree->add(activity);

				if (activity == oldSelectedActivity)
					activitiesTree->selectActivity(activity);
			}
		}

		if (selectedActivities().size() == 0)
			activitiesTree->selectFirstActivity();

		updateDetails();
	}
}

void ActivityPage::showActivity(Activity* activity)
{
	activitiesTree->clear();

	if (activity == NULL || activity->isRemoved() || m_Profile == NULL || m_Profile->activities().indexOf(activity) != -1)
		return;

	activitiesTree->add(activity);

	activitiesTree->selectActivity(activity);

	updateDetails();
}

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

	if (m_Profile)
	{
		updateCategories(m_Profile->categories());
		updateEquipments(m_Profile->equipments());
	}

	showActivity(0);
}

bool ActivityPage::onDeleteActivity()
{
	if (selectedActivities().size() < 1)
		return false;

	QStringList activityNames;

	foreach (const Activity* a, selectedActivities())
		activityNames << tr("%1 (from: %2)", "activity name and date to delete, like \"Cycle Race (from 2010-07-23 17:34:08)\"").arg(a->name()).arg(Veneer::formatDateTime(a->timeStamp().toLocalTime()));

	if (Veneer::messageBoxQuestionYesNoList(this,
			tr("Are you sure you want to delete these activities from the profile?"),
			activityNames,
			tr("Really Delete Activities?"),
			tr("Delete Activities"),
			tr("Cancel"),
			"deleteActivities"
		) == QMessageBox::No)
			return false;

	foreach (Activity* a, selectedActivities())
	{
		a->setRemoved();
		activitiesTree->remove(a);
	}

	return true;
}

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

void ActivityPage::onSelectAll()
{
	activitiesTree->selectAll();
}

