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

#include "core/athletelog.h"
#include "core/profile.h"

#include "veneer/datetime.h"
#include "veneer/locale.h"
#include "veneer/settings.h"

#include "util/unit.h"

AthleteLogModel::AthleteLogModel(QObject* parent) :
	QAbstractItemModel(parent),
	m_Profile(NULL)
{
}

QModelIndex AthleteLogModel::first()
{
	if (rowCount() > 0)
		return createIndex(0, 0);

	return QModelIndex();
}

QModelIndex AthleteLogModel::find(AthleteLog* log)
{
	quint32 count = 0;
	foreach(const AthleteLog* entry, m_AthleteLogs)
	{
		if (entry == log)
			return createIndex(count, 0);
		count++;
	}

	return QModelIndex();
}

void AthleteLogModel::add(AthleteLog* a)
{
	beginInsertRows(QModelIndex(), rowCount(), rowCount());
	m_AthleteLogs.append(a);
	endInsertRows();
}

void AthleteLogModel::remove(AthleteLog* a)
{
	QModelIndex idx = find(a);

	if (!idx.isValid())
		return;

	beginRemoveRows(QModelIndex(), idx.row(), idx.row());

	ModelAthleteLogs::iterator i = m_AthleteLogs.begin();

	while (i != m_AthleteLogs.end())
		if (*i == a)
			i = m_AthleteLogs.erase(i);
		else
			i++;

	endRemoveRows();
}

void AthleteLogModel::updateEntry(AthleteLog* changedAthleteLog)
{
	quint32 row = 0;
	foreach(const AthleteLog* a, m_AthleteLogs)
	{
		if (a == changedAthleteLog)
		{
			QModelIndex from = createIndex(row, 0);
			QModelIndex to = createIndex(row, columnCount() - 1);
			emit dataChanged(from, to);
			return;
		}

		row++;
	}
}

void AthleteLogModel::clear()
{
	if (rowCount() > 0)
	{
		beginRemoveRows(QModelIndex(), 0, rowCount() - 1);
		m_AthleteLogs.clear();
		endRemoveRows();
	}
}

QModelIndex AthleteLogModel::index(int row, int column, const QModelIndex&) const
{
	return createIndex(row, column);
}

AthleteLog* AthleteLogModel::athleteLog(const QModelIndex& index)
{
	if (index.row() >= m_AthleteLogs.size())
		return NULL;

	ModelAthleteLogs::iterator i = m_AthleteLogs.begin();
	i += index.row();

	return *i;
}

const AthleteLog* AthleteLogModel::athleteLog(const QModelIndex& index) const
{
	if (index.row() >= m_AthleteLogs.size())
		return NULL;

	ModelAthleteLogs::const_iterator i = m_AthleteLogs.constBegin();
	i += index.row();

	return *i;
}

QVariant AthleteLogModel::data(const QModelIndex& index, int role) const
{
	Q_ASSERT(m_Profile);

	const AthleteLog* a = athleteLog(index);

	if (a == NULL)
		return QVariant();

	switch (role)
	{
		case Qt::EditRole:
			switch (index.column())
			{
				case AthleteLogTree::dateCol:                return a->date();
				case AthleteLogTree::weightCol:              return a->weight() / 1000.0;
				case AthleteLogTree::bodyFatPercentCol:      return a->bodyFatPercent();
				case AthleteLogTree::bmiCol:                 return m_Profile->bmi(*a);
				case AthleteLogTree::restingHRCol:           return a->restingHeartRate();
				case AthleteLogTree::maxHRCol:               return a->maxHeartRate();
				case AthleteLogTree::bloodPressureCol:       return QList<QVariant>() << a->bloodPressureSystolic() << a->bloodPressureDiastolic();
				case AthleteLogTree::energyConsCol:
					return Veneer::Settings::self()->energyUnit() == Unit::kcal
						? Unit::toKiloCalories(a->energyConsumption())
						: a->energyConsumption();
				case AthleteLogTree::sleepDurationCol:       return QTime(a->sleepDuration() / 60, a->sleepDuration() % 60);
			}
			break;

		case sortingRole:
			switch (index.column())
			{
				case AthleteLogTree::dateCol:                return a->date();
				case AthleteLogTree::weightCol:              return a->weight();
				case AthleteLogTree::bodyFatPercentCol:      return a->bodyFatPercent();
				case AthleteLogTree::bmiCol:                 return m_Profile->bmi(*a);
				case AthleteLogTree::restingHRCol:           return a->restingHeartRate();
				case AthleteLogTree::maxHRCol:               return a->maxHeartRate();
				case AthleteLogTree::bloodPressureCol:       return a->bloodPressureSystolic() * 1000 + a->bloodPressureDiastolic();
				case AthleteLogTree::energyConsCol:          return a->energyConsumption();
				case AthleteLogTree::sleepDurationCol:       return a->sleepDuration();
			}
			// fall through

		case Qt::DisplayRole:
			switch (index.column())
			{
				case AthleteLogTree::dateCol:                return Veneer::formatShortDate(a->date());
				case AthleteLogTree::weightCol:              return Unit::formatWeight(a->weight());
				case AthleteLogTree::bodyFatPercentCol:      return QString("%1 %").arg(a->bodyFatPercent());
				case AthleteLogTree::bmiCol:                 return Veneer::formatNumber(m_Profile->bmi(*a));
				case AthleteLogTree::restingHRCol:           return QString("%1 bpm").arg(a->restingHeartRate());
				case AthleteLogTree::maxHRCol:               return QString("%1 bpm").arg(a->maxHeartRate());
				case AthleteLogTree::bloodPressureCol:       return QString("%1 / %2 mmHg").arg(a->bloodPressureSystolic()).arg(a->bloodPressureDiastolic());
				case AthleteLogTree::energyConsCol:          return Unit::formatEnergy(a->energyConsumption());
				case AthleteLogTree::sleepDurationCol:       return QTime().addSecs(a->sleepDuration() * 60).toString("H:mm");
				default:                     break;
			}
			break;

		default:
			break;
	}

	return QVariant();
}

bool AthleteLogModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
	ModelAthleteLogs::iterator i = m_AthleteLogs.begin();
	i += index.row();

	if (index.isValid() && (role == Qt::EditRole || role == Qt::CheckStateRole))
	{
		switch(index.column())
		{
			case AthleteLogTree::dateCol:               (*i)->setDate(value.toDate()); break;
			case AthleteLogTree::weightCol:             (*i)->setWeight(value.toDouble() * 1000.0); break;
			case AthleteLogTree::bodyFatPercentCol:     (*i)->setBodyFatPercent(value.toUInt()); break;
			case AthleteLogTree::restingHRCol:          (*i)->setRestingHeartRate(value.toUInt()); break;
			case AthleteLogTree::maxHRCol:              (*i)->setMaxHeartRate(value.toUInt()); break;
			case AthleteLogTree::energyConsCol:
				(*i)->setEnergyConsumption(
					Veneer::Settings::self()->energyUnit() == Unit::kcal ? Unit::toKiloJoule(value.toUInt()) : value.toUInt()
				);
				break;
			case AthleteLogTree::bloodPressureCol:
				(*i)->setBloodPressureSystolic(value.toList()[0].toUInt());
				(*i)->setBloodPressureDiastolic(value.toList()[1].toUInt());
				break;
			case AthleteLogTree::sleepDurationCol:      (*i)->setSleepDuration(value.toTime().hour() * 60 + value.toTime().minute()); break;
			default:                    return false;
		}

		emit dataChanged(index, index);
		return true;
	}

	return false;
}

Qt::ItemFlags AthleteLogModel::flags(const QModelIndex& index) const
{
	if (!index.isValid())
		return Qt::ItemIsEnabled;

	Qt::ItemFlags rval = 0;

	switch(index.column())
	{
		case AthleteLogTree::dateCol:
		case AthleteLogTree::weightCol:
		case AthleteLogTree::bodyFatPercentCol:
		case AthleteLogTree::restingHRCol:
		case AthleteLogTree::maxHRCol:
		case AthleteLogTree::energyConsCol:
		case AthleteLogTree::bloodPressureCol:
		case AthleteLogTree::sleepDurationCol:
			rval = Qt::ItemIsEditable;
			break;

		default:
			break;
	}


	return QAbstractItemModel::flags(index) | rval;
}

QVariant AthleteLogModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	QStringList headers;
	headers <<
		tr("Date", "athlete log column header") <<
		tr("Weight", "athlete log column header") <<
		tr("Body Fat", "athlete log column header") <<
		tr("BMI", "athlete log column header") <<
		tr("Resting HR", "athlete log column header") <<
		tr("Max. HR", "athlete log column header") <<
		tr("Blood Pressure", "athlete log column header") <<
		tr("Energy Con.", "athlete log column header") <<
		tr("Sleep Duration", "athlete log column header");

	if (role == Qt::DisplayRole && orientation == Qt::Horizontal && section >= 0 && section < headers.size())
		return headers[section];

    return QAbstractItemModel::headerData(section, orientation, role);
}
