/*******************************************************************************
***  This file is part of Dux Rei Nummariae.                                 ***
***                                                                          ***
***  Copyright (C) 2017, 2018, 2019, 2020, 2021                              ***
***  John Schneiderman <Licensing _AT_ Schneiderman _DOT_ me>                ***
***                                                                          ***
***  This program is free software: you can redistribute it and/or modify it ***
***  under the terms of the GNU Affero General Public License as published   ***
***  by the Free Software Foundation, either version 3 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 Affero General Public License for more details.             ***
***                                                                          ***
***  You should have received a copy of the GNU Affero General Public License***
***  along with this program. If not, see <http://www.gnu.org/licenses/>.    ***
*******************************************************************************/
#ifndef DRN_DESKTOP_UI_INTERNAL_GOALSWIDGET_H_
#define DRN_DESKTOP_UI_INTERNAL_GOALSWIDGET_H_

#include <pecunia/Money.h>
#include <QString>
#include <QWidget>

#include <chrono>
#include <functional>
#include <set>

#include <banking/BankName.h>
#include <foundation/CalendarTime.hpp>
#include <foundation/Optional.hpp>
#include <foundation/ObserverPtr.hpp>
#include <ui_GoalsWidget.h>


class QAbstractButton;
class QPushButton;

namespace drn
{
namespace banking
{

struct BankAccount;
struct BankAccountType;
enum class SupportedAccountTypes;

}
namespace budgeting
{

class BudgetSource;
class Goal;
struct GoalMap;

}
namespace navigation
{

struct BudgetBankAccount;

}
namespace desktop_ui
{
namespace internal
{

class GoalEntryWidget;

/**
 * A Qt Widget that displays all the sources of goal. This object deletes itself when it closes.
 */
class GoalsWidget : public ::QWidget, Ui::GoalsWdgt
{
	Q_OBJECT

	foundation::Optional<foundation::ObserverPtr<internal::GoalEntryWidget>> findGoal(
		const std::function<bool(const internal::GoalEntryWidget&)>& isMatch
	);
	void addGoal(
		const foundation::Optional<budgeting::Goal>& g,
		const foundation::Optional<banking::BankAccount>& ba
	);
	bool anyGoalDirty() const;

	const pecunia::currency::Money totalWage_;
	const std::chrono::hours hrInWeek_;
	const foundation::Days dayInWeek_;
	const pecunia::currency::Iso4217Codes preferred_;
	const std::set<pecunia::currency::Iso4217Codes> usableCurrencies_;
	foundation::ObserverPtr<::QPushButton> addPshbttn_;
	const std::set<banking::BankName> banks_;

private slots:
	void addEntry();
	void saveGoals();
	void updateTotal();
	void onClicked(foundation::ObserverPtr<::QAbstractButton> button);

public slots:
	bool close();
	void onSaveSucceeded(const budgeting::BudgetSource& source);
	void onSaveFailed(
		const foundation::Optional<budgeting::BudgetSource>& original,
		const ::QString& errorMessage,
		const foundation::Optional<budgeting::BudgetSource>& displayed
	);
	/**
	 * @brief Sets the looked up bank account information.
	 *
	 * @param bn The name of the bank whose accounts were looked up.
	 * @param accountTypes The accounts associated with the bank, filtering out accounts not related
	 * to a goal.
	 */
	void onLookedUpBankAccounts(
		const banking::BankName& bn,
		std::set<banking::BankAccountType> accountTypes
	);

signals:
	/// @brief Triggered when a new goal is entered.
	void added(
		const budgeting::Goal& goal,
		const foundation::Optional<banking::BankAccount>& ba
	);
	/// @brief Triggered when the name of a goal changes.
	void renamed(const budgeting::BudgetSource& original, const budgeting::BudgetSource& changed);
	/// @brief Triggered when the values of an goal changes.
	void updated(
		const budgeting::Goal& goal,
		const foundation::Optional<banking::BankAccount>& ba
	);
	/// @brief Triggered when a source of goal is removed.
	void removed(const budgeting::BudgetSource& source);
	/// @brief Triggered when the widget is in the process of being closed.
	void closing();
	void lookUpBankAccounts(const banking::BankName& bn);

public:
	GoalsWidget(
		const budgeting::GoalMap& goals,
		const std::set<navigation::BudgetBankAccount>& accounts,
		const pecunia::currency::Money& totalWage,
		const std::chrono::hours& hrInWeek,
		const foundation::Days& dayInWeek,
		std::set<banking::BankName> banks,
		const pecunia::currency::Iso4217Codes& preferred,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies,
		foundation::ObserverPtr<::QWidget> parent
	);
};

}}}

#endif
