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

#include "core/profile.h"
#include "core/equipment.h"
#include "core/activity.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 <kicon.h>

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

class EquipmentTreeDelegate : public QStyledItemDelegate
{
	public:
		EquipmentTreeDelegate(QObject* parent = NULL) : QStyledItemDelegate(parent) {}

	public:
		virtual QWidget* createEditor(QWidget* w, const QStyleOptionViewItem& item, const QModelIndex& idx) const
		{
			if (idx.column() > 0)
				return NULL;

			return QStyledItemDelegate::createEditor(w, item, idx);
		}
};

class EquipmentTreeWidgetItem : public QTreeWidgetItem
{
	public:
		EquipmentTreeWidgetItem(Equipment* e) : QTreeWidgetItem(), equipment(e) {}
		Equipment* equipment;
};

EditProfileEquipmentPage::EditProfileEquipmentPage(QWidget* parent) :
	QWidget(parent),
	m_Profile(NULL),
	m_DeletedEquipments(),
	m_BackupEquipments()
{
	setupUi(this);
	addEquipmentButton->setIcon(BarIcon("list-add"));
	removeEquipmentButton->setIcon(BarIcon("list-remove"));
}

EditProfileEquipmentPage::~EditProfileEquipmentPage()
{
	qDeleteAll(m_BackupEquipments);
}

QTreeWidgetItem* EditProfileEquipmentPage::createEquipmentTreeNode(Equipment& e)
{
	QTreeWidgetItem* item = new EquipmentTreeWidgetItem(&e);

	item->setText(0, e.name());

	const quint64 totalDistance = Activity::totalEquipmentDistance(m_Profile->activities(), &e);
	item->setText(1, Unit::formatDistance(totalDistance));

	const QDate lastUsed = Activity::equipmentLastused(m_Profile->activities(), &e);
	item->setText(2, Veneer::formatShortDate(lastUsed));

	item->setIcon(3, e.isInUse() ? BarIcon("dialog-ok") : BarIcon("dialog-cancel"));

	item->setFlags(item->flags() | Qt::ItemIsEditable);

	return item;
}

void EditProfileEquipmentPage::setupPage(Profile* profile)
{
	m_Profile = profile;

	foreach (const Equipment* e, m_Profile->equipments())
		m_BackupEquipments.append(new Equipment(*e));

	foreach(Equipment* e, m_Profile->equipments())
		if (!e->isRemoved())
			equipmentTree->addTopLevelItem(createEquipmentTreeNode(*e));

	for (int i = 0; i < equipmentTree->columnCount(); i++)
		equipmentTree->resizeColumnToContents(i);

	equipmentTree->header()->setSortIndicator(0, Qt::AscendingOrder);

	equipmentTree->sortItems(equipmentTree->sortColumn(), equipmentTree->header()->sortIndicatorOrder());

	if (equipmentTree->topLevelItemCount() > 0)
	{
		equipmentTree->setCurrentItem(equipmentTree->topLevelItem(0));
		onEquipmentSelectionChanged();
	}

	equipmentTree->setItemDelegate(new EquipmentTreeDelegate(equipmentTree));
}

void EditProfileEquipmentPage::setupConnections()
{
	connect(addEquipmentButton, SIGNAL(clicked(bool)), SLOT(onAddEquipmentButton(bool)));
	connect(removeEquipmentButton, SIGNAL(clicked(bool)), SLOT(onRemoveEquipmentButton(bool)));
	connect(equipmentTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onEquipmentItemChanged(QTreeWidgetItem*, int)));
	connect(equipmentTree, SIGNAL(itemSelectionChanged()), SLOT(onEquipmentSelectionChanged()));

	connect(purchaseDateEdit, SIGNAL(dateChanged(const QDate&)), SLOT(onEquipmentPurchaseDateChanged(const QDate&)));
	connect(statusCheckBox, SIGNAL(stateChanged(int)), SLOT(onEquipmentStatusChanged(int)));
	connect(modelEdit, SIGNAL(editingFinished()), SLOT(onEquipmentModelEditFinished()));
	connect(brandEdit, SIGNAL(editingFinished()), SLOT(onEquipmentBrandEditFinished()));
	connect(typeEdit, SIGNAL(editingFinished()), SLOT(onEquipmentTypeEditFinished()));
	connect(weightSpin, SIGNAL(valueChanged(double)), SLOT(onEquipmentWeightChanged(double)));
	connect(notesEdit, SIGNAL(textChanged()), SLOT(onEquipmentNotesTextChanged()));
	connect(equipmentPhotoButton, SIGNAL(clicked(bool)), SLOT(onEquipmentPhotoButton(bool)));
}

bool EditProfileEquipmentPage::accept()
{
	handleDeletedEquipment();

	return true;
}

void EditProfileEquipmentPage::reject()
{
	// we need to copy back the backup we made to the profile's equipment container. do this
	// one by one, then delete any equipment that's in profile but not in our backup because
	// it must have been added in the dialog just now.
	int count = 0;
	while (count < m_BackupEquipments.size())
	{
		*m_Profile->equipments()[count] = *m_BackupEquipments[count];
		count++;
	}

	while (count < m_Profile->equipments().size())
		m_Profile->equipments().removeAt(count);


	// delete no objects in m_BackupEquipments, the dtor will do that
}

/** Go through all activities in the profile and set the equipment id to zero for those
  * activities using equipment that has now been deleted.
  */
void EditProfileEquipmentPage::handleDeletedEquipment()
{
	foreach(Activity* a, m_Profile->activities())
	{
		if (m_DeletedEquipments.find(const_cast<Equipment*>(a->equipment())) != m_DeletedEquipments.end())
			a->setEquipment(NULL);
	}

	foreach(Equipment* e, m_DeletedEquipments)
		e->setRemoved(true);
}

Equipment* EditProfileEquipmentPage::selectedEquipment() const
{
	if (equipmentTree->selectedItems().size() == 0)
		return 0;

	return static_cast<EquipmentTreeWidgetItem*>(equipmentTree->selectedItems()[0])->equipment;
}

void EditProfileEquipmentPage::onAddEquipmentButton(bool)
{
	Equipment* e = new Equipment(m_Profile, tr("New Equipment"));
	m_Profile->equipments().append(e);

	QTreeWidgetItem* item = createEquipmentTreeNode(*e);

	equipmentTree->insertTopLevelItem(0, item);
	equipmentTree->editItem(item);

	emit modified();
}

void EditProfileEquipmentPage::onRemoveEquipmentButton(bool)
{
	if (equipmentTree->selectedItems().size() == 0)
		return;

	QTreeWidgetItem* item = equipmentTree->selectedItems()[0];
	if (Veneer::messageBoxQuestionYesNo(this,
			tr("Are you sure you want to delete the selected equipment \"%1\"?").arg(item->text(0)),
			tr("Really Delete Equipment?"),
			tr("Delete Equipment"),
			tr("Cancel"),
			"deleteEquipmentWarning") == QMessageBox::No)
		return;

	foreach (QTreeWidgetItem* item, equipmentTree->selectedItems())
	{
		Equipment* e = static_cast<EquipmentTreeWidgetItem*>(item)->equipment;

		if (e)
			m_DeletedEquipments.insert(e);

		delete item;
	}

	emit modified();
}

void EditProfileEquipmentPage::onEquipmentItemChanged(QTreeWidgetItem* item, int)
{
	Equipment* e = static_cast<EquipmentTreeWidgetItem*>(item)->equipment;

	if (e)
		e->setName(item->text(0));

	emit modified();
}

void EditProfileEquipmentPage::onEquipmentSelectionChanged()
{
	QTreeWidgetItem* item = NULL;

	if (equipmentTree->selectedItems().size() > 0)
		item = equipmentTree->selectedItems()[0];

	removeEquipmentButton->setEnabled(item != NULL);

	purchaseDateEdit->setEnabled(item != NULL);
	statusCheckBox->setEnabled(item != NULL);
	modelEdit->setEnabled(item != NULL);
	brandEdit->setEnabled(item != NULL);
	typeEdit->setEnabled(item != NULL);
	weightSpin->setEnabled(item != NULL);
	notesEdit->setEnabled(item != NULL);
	equipmentPhotoButton->setEnabled(item != NULL);

	if (item != NULL)
	{
		const Equipment* e = static_cast<EquipmentTreeWidgetItem*>(item)->equipment;

		Q_ASSERT(e);

		if (e)
		{
			purchaseDateEdit->setDate(e->purchaseDate());
			statusCheckBox->setChecked(e->isInUse());
			modelEdit->setText(e->model());
			brandEdit->setText(e->brand());
			typeEdit->setText(e->type());
			Unit::setSpinBoxWeight(*weightSpin, e->weight());
			notesEdit->setPlainText(e->notes());
			equipmentPhotoButton->setIcon(e->photo());
		}
	}
}

void EditProfileEquipmentPage::onEquipmentPhotoButton(bool)
{
	QString fileName = Veneer::getOpenFileName(this, "editProfileEquipmentPhoto");

	if (fileName.isEmpty())
		return;

	QPixmap photo;

	if (!photo.load(fileName))
		qWarning() << "could not load photo";

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

	selectedEquipment()->setPhoto(photo);

	emit modified();
}

void EditProfileEquipmentPage::onEquipmentPurchaseDateChanged(const QDate& date)
{
	if (selectedEquipment() && selectedEquipment()->purchaseDate() != date)
	{
		selectedEquipment()->setPurchaseDate(date);
		emit modified();
	}
}

void EditProfileEquipmentPage::onEquipmentStatusChanged(int i)
{
	if (selectedEquipment() && selectedEquipment()->isInUse() != bool(i))
	{
		selectedEquipment()->setInUse(i);

		QList<QTreeWidgetItem*> items = equipmentTree->findItems(selectedEquipment()->name(), Qt::MatchExactly, 0);

		if (items.size() == 1)
			items[0]->setIcon(3, selectedEquipment()->isInUse() ? BarIcon("dialog-ok") : BarIcon("dialog-cancel"));

		emit modified();
	}
}

void EditProfileEquipmentPage::onEquipmentModelEditFinished()
{
	if (selectedEquipment() && selectedEquipment()->model() != modelEdit->text())
	{
		selectedEquipment()->setModel(modelEdit->text());
		emit modified();
	}
}

void EditProfileEquipmentPage::onEquipmentBrandEditFinished()
{
	if (selectedEquipment() && selectedEquipment()->brand() != brandEdit->text())
	{
		selectedEquipment()->setBrand(brandEdit->text());
		emit modified();
	}
}

void EditProfileEquipmentPage::onEquipmentTypeEditFinished()
{
	if (selectedEquipment() && selectedEquipment()->type() != typeEdit->text())
	{
		selectedEquipment()->setType(typeEdit->text());
		emit modified();
	}
}

void EditProfileEquipmentPage::onEquipmentWeightChanged(double val)
{
	val *= 1000;
	if (Veneer::Settings::self()->measureSystem() == Veneer::Settings::EnumMeasureSystem::Imperial)
		val = Unit::toMetricWeight(val);

	if (selectedEquipment() && selectedEquipment()->weight() != val)
	{
		selectedEquipment()->setWeight(val);
		emit modified();
	}
}

void EditProfileEquipmentPage::onEquipmentNotesTextChanged()
{
	if (selectedEquipment() && selectedEquipment()->notes() != notesEdit->toPlainText())
	{
		selectedEquipment()->setNotes(notesEdit->toPlainText());
		emit modified();
	}
}
