/*******************************************************************************
***  This file is part of Pecunia.                                           ***
***                                                                          ***
***  Copyright (C) 2017, 2018, 2019, 2020, 2021, 2023                        ***
***  John Schneiderman <Licencing _AT_ Schneiderman _DOT_ me>                ***
***                                                                          ***
***  This program is free software: you can redistribute it and/or modify it ***
***  under the terms of the GNU Lesser 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 Lesser General Public License for more details.             ***
***                                                                          ***
***  You should have received a copy of the GNU Lesser General Public License***
***  along with this program. If not, see <http://www.gnu.org/licenses/>.    ***
*******************************************************************************/
#ifndef PECUNIA_MONEYTYPES_H_
#define PECUNIA_MONEYTYPES_H_

#include <cstdint>
#include <functional>

#ifdef __WIN32
#	pragma STDC FENV_ACCESS ON
#endif

#include <pecunia_export.h> // cppcheck-suppress missingInclude
#include <MoneySize.hpp> // cppcheck-suppress missingInclude


namespace pecunia
{

class FloatingPoint;

namespace currency
{

enum class Iso4217Codes : std::uint16_t;

}

/**
 * @breif When working with minor units, this represents the postivity or negativity of a minor
 * value.
 */
enum class PECUNIA_EXPORT MinorSign
{
	/// The minor value is negative.
	Negative,
	/// The minor value is neither positive nor negative, i.e. zero.
	Neither,
	/// The minor value is positive.
	Positive,
};
/**
 * @breif A representation of a function that performs a rounding operation upon a real number. This
 * function must take a number, the number of digits after the whole number to round, and giving
 * back the rounded number.
 *
 * @exception std::runtime_error When the rounding is not possible.
 */
using FloatingPointRounderFunction =
		std::function<FloatingPoint(const FloatingPoint&, const std::uint8_t&)>;
/**
 * @breif A representation of a function that performs a rounding operation upon a money storage
 * type. This function must take first the major and minor amount value stored together, then the
 * number of digits in the minor unit, finally the number of digits after the whole number to round,
 * and giving back the rounded number with the major and minor amount stored together.
 *
 * @exception std::runtime_error When the rounding is not possible.
 */
using RounderFunction =
		std::function<UnitStorage(const UnitStorage&, const std::uint8_t&, const std::uint8_t)>;
/**
 * @breif A conversion function between two currencies where the first argument is the currency to
 * convert from, the second argument is the currency to convert to, and giving back the conversion
 * factor to get from the first currency to the second currency.
 *
 * @throw std::runtime_error When either the from or to currency is not supported.
 */
using ConversionFunction =
		std::function<FloatingPoint(const currency::Iso4217Codes&, const currency::Iso4217Codes&)>;
/**
 * @breif Provides a 1:1 conversion for a currency whose currency::Codes match.
 *
 * @param[in] from The currency code whose conversion value is desired.
 * @param[in] to The currency code the conversion value is directed towards.
 *
 * @throw std::logic_error When either the from and to currency currency::Codes do not match.
 *
 * @return The conversion value for the supplied currency when multiplied from to the other.
 */
PECUNIA_EXPORT FloatingPoint defaultConverter(
	const currency::Iso4217Codes& from,
	const currency::Iso4217Codes& to
);
/// The holder for all conversion operations for any money unit.
PECUNIA_EXPORT extern ConversionFunction converter;

}

#endif
