/*******************************************************************************
***  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_POSTBUDGETITEMWIDGET_H_
#define DRN_DESKTOP_UI_INTERNAL_POSTBUDGETITEMWIDGET_H_

#include <set>

#include <QWidget>

#include <foundation/Switch.h>
#include <ui_PostBudgetItemEntryWidget.h>


class QDate;

namespace pecunia
{
namespace currency
{

enum class Iso4217Codes : quint16;
class Money;

}}

namespace drn
{
namespace accounting
{

class AccountCode;
class TransactionNumber;

}
namespace banking
{

class BankName;
struct BankAccountType;

}
namespace budgeting
{

struct BudgetItemDue;
struct BudgetItemIdentifier;
enum class BudgetItemTypes : quint8;
class BudgetSource;

}
namespace foundation
{

template<typename>
class ObserverPtr;
template<typename>
class Optional;

}
namespace desktop_ui
{
namespace internal
{

enum class BudgetItemDueAction : quint8
{
	Unknown,
	Ignore,
	Post,
	Skip
};

class PostBudgetItemEntryWidget : public ::QWidget, Ui::PostBudgetItemEntryWdgt
{
	Q_OBJECT

	void setReadOnly(const bool isReadOnly);
	void updateSourceDescription(const budgeting::BudgetItemTypes& bit);

	foundation::Switch isDirty_;
	foundation::Switch isReadOnly_;
	foundation::Switch isUnexpectedItem_;
	foundation::Switch hasRequestedAccounts_;

private slots:
	void onTypeIndexChanged(const int index);
	void markDirty();
	void onLookUpBankAccounts(const banking::BankName& name);

signals:
	/**
	 * @brief Triggered when the user selects a bank account.
	 *
	 * @param name The name of the bank whose accounts are desired.
	 */
	void lookUpBankAccounts(const banking::BankName& name);
	/**
	 * @brief Triggered when the amount for a budget item due changes.
	 *
	 * @param m The amount that was changed.
	 */
	void amountChanged(const pecunia::currency::Money& m);
	/**
	 * @brief Triggered when the users changes the source to a different bank.
	 *
	 * @param bn The name of the bank changed.
	 */
	void sourceChanged(const foundation::Optional<banking::BankName>& bn);
	/**
	 * @brief Triggered when the user changes the account to use as the source for the budget item
	 * due.
	 *
	 * @param ac The account number the budget item due was changed to.
	 */
	void accountNumberChanged(const foundation::Optional<accounting::AccountNumber>& an);
	/**
	 * @brief Triggered when the user changes the action to perform for a budget item due.
	 *
	 * @param action The action to be performed.
	 */
	void actionChanged(const BudgetItemDueAction& action);
	/**
	 * @brief Triggered when the user changes the budget item due.
	 *
	 * @param action The action to be performed.
	 */
	void lookUpBudgetItemDueSources(
		const budgeting::BudgetItemIdentifier& requestedBy, // TODO: this shouldn't be needed
		const budgeting::BudgetItemTypes& bit
	);

public:
	PostBudgetItemEntryWidget(
		const foundation::Optional<budgeting::BudgetItemDue>& item,
		const std::set<banking::BankName>& banks,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies,
		const foundation::ObserverPtr<::QWidget>& parent
	);
	/**
	 * @brief The name of the bank when used as a funding source.
	 *
	 * @return The source name, else empty optional.
	 */
	foundation::Optional<banking::BankName> bankName() const;
	/**
	 * @brief The type of the budget item that is due.
	 */
	budgeting::BudgetItemTypes itemType() const;
	/**
	 * @brief The name of the budget item that is due.
	 */
	budgeting::BudgetSource itemDue() const;
	/**
	 * @brief The action to perform for handling the budget item due.
	 */
	BudgetItemDueAction dueAction() const;
	/**
	 * @brief The amount of money to be used when handling the budget item due.
	 */
	pecunia::currency::Money amount() const;
	/**
	 * @brief The selected account code for the budget item due.
	 */
	foundation::Optional<accounting::AccountCode> accountCode() const;
	/**
	 * @brief The date the the budget item is due.
	 */
	::QDate dueOn() const;
	/**
	 * @brief The date the user selected to post on for the budget item due.
	 */
	::QDate postOn() const;
	bool isUnexpectedItem() const;
	void setAccounts(std::set<banking::BankAccountType> accountTypes);
	void setPosted(const accounting::TransactionNumber& txnNum);
	void setSkipped();
	bool isDirty() const;
	bool isReadOnly() const;
	void clearBankName();
	void saved();
	void setErrorMessage(const ::QString& message);
	void setItemDueSources(const std::set<drn::budgeting::BudgetSource>& sources);
	bool hasRequestedAccounts() const;
};

}}}

#endif
