/*******************************************************************************
***  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_MAINWINDOW_H_
#define DRN_DESKTOP_UI_MAINWINDOW_H_

#include <pecunia/Codes.h>
#include <pecunia/Money.h>
#include <QMainWindow>
#include <QString>
#include <vector>

#include <chrono>
#include <map>
#include <memory>
#include <set>
#include <utility>

#include <accounting/Account.h>
#include <accounting/AccountCode.h>
#include <accounting/LedgerBooks.h>
#include <accounting/Transaction.h>
#include <adviser/BudgetHealth.h>
#include <banking/BankAccount.h>
#include <banking/BankAccountType.h>
#include <banking/BankMap.h>
#include <banking/BankName.h>
#include <budgeting/BillMap.hpp>
#include <budgeting/Budget.h>
#include <budgeting/BudgetItemDue.h>
#include <budgeting/BudgetItemTypes.h>
#include <budgeting/DebtMap.h>
#include <budgeting/GoalMap.h>
#include <budgeting/NontrackMap.hpp>
#include <budgeting/WageMap.hpp>
#include <conversion/ConversionMap.h>
#include "desktop-ui_export.h"
#include <foundation/CalendarTime.hpp>
#include <foundation/Optional.hpp>
#include <foundation/Switch.h>


class QCloseEvent;

namespace Ui
{

class BwmMnwndw;

}
namespace drn
{
namespace foundation
{

template<typename>
class Optional;

}
namespace navigation
{

struct BudgetBankAccount;

}
namespace desktop_ui
{

class DRN_DESKTOP_UI_EXPORT MainWindow : public QMainWindow
{
	Q_OBJECT

	static const qint32 statusBarTimeOut_;
	static const ::QString budgetFileExtentionFilter_;

	std::unique_ptr<Ui::BwmMnwndw> ui_;
	foundation::Switch confirmedExit_;

private slots:
	//{ Help Menu

	void onShowAbout();
	void onShowAboutQt();

	//}

	void onDisplayBudgetInterface(const budgeting::BudgetItemTypes& type);

protected:
	void closeEvent(QCloseEvent* event) override;

public slots:
	void onShowBills(
		const budgeting::BillMap& bills,
		const std::chrono::hours& hrInWeek,
		const foundation::Days& dayInWeek,
		const pecunia::currency::Iso4217Codes& preferred,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies
	);
	void onShowDebts(
		const budgeting::DebtMap& debts,
		const std::set<navigation::BudgetBankAccount>& accounts,
		const std::set<banking::BankName>& banks,
		const std::chrono::hours& hrInWeek,
		const foundation::Days& dayInWeek,
		const pecunia::currency::Iso4217Codes& preferred,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies
	);
	void onShowGoals(
		const budgeting::GoalMap& goals,
		const std::set<navigation::BudgetBankAccount>& accounts,
		const std::set<banking::BankName>& banks,
		const std::chrono::hours& hrInWeek,
		const foundation::Days& dayInWeek,
		const pecunia::currency::Iso4217Codes& preferred,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies,
		const pecunia::currency::Money& wagesTotal
	);
	void onShowNontracks(
		const budgeting::NontrackMap& nontracks,
		const std::chrono::hours& hrInWeek,
		const foundation::Days& dayInWeek,
		const pecunia::currency::Iso4217Codes& preferred,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies
	);
	void onShowWages(
		const budgeting::WageMap& wages,
		const std::chrono::hours& hrInWeek,
		const foundation::Days& dayInWeek,
		const pecunia::currency::Iso4217Codes& preferred,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies
	);
	void onShowAccounts(
		const std::set<accounting::Account>& accounts,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies
	);
	void onShowLedgers(
		const std::set<accounting::Account>& accounts,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies
	);
	void onShowBanks(
		const banking::BankMap& banks,
		const std::set<accounting::Account>& allAccounts,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies,
		const std::set<banking::BankAccountType>& accountTypes
	);
	void onShowPostBudgetItems(
		const qint32& dueWithin,
		const std::vector<budgeting::BudgetItemDue>& items,
		const std::set<banking::BankName>& banks,
		const pecunia::currency::Iso4217Codes& preferredCurrency,
		const std::set<pecunia::currency::Iso4217Codes>& usableCurrencies
	);
	void onShowConfirmNewBudgetFile();
	void onClearedBudgetFile();
	void onShowOpenBudgetFile();
	void onShowConfirmLoadBudgetFile(const ::QString& filePathName);
	void onLoadedBudgetFile(const QString& filePathName, const bool isReloaded);
	void onSavedBudgetFile(const QString& filePathName);
	void onShowSaveAsBudgetFile();
	void onShowNoBudgetFileOpened();
	void onCheckCleanExit(const foundation::Switch& isDirty);
	void show();
	void onShowDashboard(
		const budgeting::BudgetTotals& bt,
		const std::vector<budgeting::BudgetItemDue>& due,
		const adviser::BudgetHealth& bh,
		const foundation::Days& dueWithin,
		const pecunia::currency::Iso4217Codes& preferred
	);
	void onShowExchangeRates(
		const conversion::ConversionMap& currentConversions,
		const std::set<pecunia::currency::Iso4217Codes>& currencies
	);
	void onShowConfigure(
		const std::chrono::hours& hrInWeek,
		const foundation::Days& dayInWeek,
		const foundation::Days& notifyDueWithin,
		const pecunia::currency::Iso4217Codes& preferred,
		const std::set<pecunia::currency::Iso4217Codes>& usable,
		const std::set<pecunia::currency::Iso4217Codes>& used
	);

signals:
	void prepareShowBills();
	void prepareShowDebts();
	void prepareShowGoals();
	void prepareShowNontracks();
	void prepareShowWages();
	void added(
		const budgeting::BudgetItemTypes& type,
		const budgeting::BudgetedMoney& item,
		const foundation::Optional<banking::BankAccount>& ba
	);
	void renamed(
		const budgeting::BudgetItemTypes& type,
		const budgeting::BudgetSource& original,
		const budgeting::BudgetSource& changed
	);
	void updated(
		const budgeting::BudgetItemTypes& type,
		const budgeting::BudgetedMoney& item,
		const foundation::Optional<banking::BankAccount>& ba
	);
	void removed(const budgeting::BudgetItemTypes& type, const budgeting::BudgetSource& source);
	void saveSucceeded(const budgeting::BudgetSource& source);
	void saveFailed(
		const foundation::Optional<budgeting::BudgetSource>& original,
		const ::QString& errorMessage,
		const foundation::Optional<budgeting::BudgetSource>& displayed
	);
	void prepareShowAccounts();
	void addedAct(const accounting::Account& a);
	void recoded(const accounting::AccountCode& current, const accounting::AccountCode& changed);
	void closed(const accounting::AccountCode& code);
	void opened(const accounting::AccountCode& code);
	void removedAct(const accounting::AccountCode& code);
	void accountSaveSucceeded(const accounting::AccountCode& code);
	void accountSaveFailed(
		const foundation::Optional<accounting::AccountCode>& original,
		const ::QString& errorMessage,
		const foundation::Optional<accounting::AccountCode>& displayed
	);
	void prepareShowLedgers();
	void selectedLedger(const accounting::AccountCode& code);
	void showLedger(const accounting::LedgerAccount& ledger);
	void addedTransaction(const accounting::Transaction& txn);
	void updatedTransaction(
		const accounting::TransactionNumber& tn,
		const accounting::Transaction& txn
	);
	void markCleared(const accounting::TransactionNumber& number);
	void markReconciled(const accounting::TransactionNumber& number);
	void removedTransaction(const accounting::TransactionNumber& number);
	void transactionSaveSucceeded(
		const foundation::Optional<accounting::TransactionNumber>& displayed,
		const foundation::Optional<accounting::TransactionNumber>& posted
	);
	void transactionSaveFailed(
		const foundation::Optional<accounting::TransactionNumber>& tn,
		const ::QString& errorMessage
	);
	void prepareShowBanks();
	void bankAdded(
		const banking::Bank& b,
		const std::map<
			accounting::AccountNumber,
			banking::SupportedAccountTypes
		>& accountNumbersBankTypes
	);
	void bankUpdated(
		const banking::Bank& b,
		const std::map<
			accounting::AccountNumber,
			banking::SupportedAccountTypes
		>& accountNumbersBankTypes
	);
	void bankRenamed(
		const banking::BankName& original,
		const banking::BankName& change
	);
	void bankClosed(const banking::BankName& bn);
	void bankOpened(const banking::BankName& bn);
	void bankRemoved(const banking::BankName& bn);
	void bankSaveSucceeded(const banking::BankName& bn);
	void bankSaveFailed(
		const foundation::Optional<banking::BankName>& original,
		const ::QString& errorMessage,
		const foundation::Optional<banking::BankName>& displayed
	);
	void addedBankAccount(
		const ::QString& name,
		const banking::SupportedAccountTypes& type,
		const pecunia::currency::Money& openingBalance
	);
	void renamedBankAccount(
		const accounting::AccountCode& original,
		const accounting::AccountCode& changed
	);
	void removedBankAccount(const accounting::AccountCode& ac);
	void bankAccountSaveSucceeded(const accounting::AccountCode& ac);
	void bankAccountSaveFailed(
		const foundation::Optional<accounting::AccountCode>& original,
		const ::QString& errorMessage,
		const foundation::Optional<accounting::AccountCode>& displayed
	);
	void prepareShowPostBudgetItems();
	void lookUpBankAccounts(const banking::BankName& bn);
	void lookedUpBankAccounts(
		const banking::BankName& bn,
		const std::set<banking::BankAccountType>& accountTypes
	);
	void lookUpBudgetItemSources(
		const budgeting::BudgetItemIdentifier& requestedBy,
		const budgeting::BudgetItemTypes& bit
	);
	void lookedUpBudgetItemSources(
		const budgeting::BudgetItemIdentifier& requestedBy,
		const budgeting::BudgetItemTypes& bit,
		const std::set<drn::budgeting::BudgetSource>& sources
	);
	void postBudgetItemPosted(
		const budgeting::BudgetItemDue& bid,
		const accounting::AccountCode& ac,
		const ::QDate& postOn
	);
	void postBudgetItemPostedUnexpected(
		const budgeting::BudgetItemIdentifier& bii,
		const pecunia::currency::Money& amount,
		const accounting::AccountCode& ac,
		const ::QDate& postOn
	);
	void postBudgetItemSkipped(const budgeting::BudgetItemIdentifier& bii);
	void postBudgetItemSaveSucceeded(
		const budgeting::BudgetItemIdentifier& bii,
		const foundation::Optional<accounting::TransactionNumber>& txnNum
	);
	void postBudgetItemSaveFailed(
		const budgeting::BudgetItemIdentifier& bii,
		const ::QString& errorMessage
	);
	void newBudgetFile();
	void confirmedNewBudgetFile();
	void loadBudgetFile(const ::QString& filePathName);
	void confirmedLoadBudgetFile(const ::QString& filePathName, const bool isReloaded);
	void saveBudgetFile();
	void saveAsBudgetFile(const ::QString& filePathName);
	void reloadBudgetFile();
	void checkIsBudgetFileDirty();
	void prepareShowDashboard();
	void prepareShowExchangeRates();
	void fetchExchangeRates(const std::set<pecunia::currency::Iso4217Codes>& currencies);
	void fetchedExchangeRates(
		const std::set<pecunia::currency::Iso4217Codes>& currencies,
		const conversion::ConversionMap& conversions
	);
	void storeExchangeRates(const conversion::ConversionMap& conversions);
	void prepareShowConfigure();
	void configureUpdated(
		const std::chrono::hours& hrInWeek,
		const foundation::Days& dayInWeek,
		const foundation::Days& notifyDueWithin,
		const pecunia::currency::Iso4217Codes& preferred,
		const std::set<pecunia::currency::Iso4217Codes>& usable
	);
	void configureSaveSucceeded();
	void configureSaveFailed(const ::QString& errorMessage);

public:
	MainWindow();
	~MainWindow() override;
};

}}
#endif

