<?php
namespace SabaiApps\Directories\Component\System\Helper;

use SabaiApps\Directories\Application;

/**
 * CurrencyHelper provides currency options, formatting, and symbols.
 */
class CurrencyHelper {

	/**
	 * Returns an array of currency codes and their names.
	 *
	 * @param Application $application
	 * @return array
	 */
	public function options( Application $application ) {
		return array(
			'ALL' => 'Albania Lek',
			'AFN' => 'Afghanistan Afghani',
			'ARS' => 'Argentina Peso',
			'AWG' => 'Aruba Guilder',
			'AUD' => 'Australia Dollar',
			'AZN' => 'Azerbaijan New Manat',
			'BSD' => 'Bahamas Dollar',
			'BHD' => 'Bahraini Dinar',
			'BBD' => 'Barbados Dollar',
			'BDT' => 'Bangladeshi taka',
			'BYR' => 'Belarus Ruble',
			'BZD' => 'Belize Dollar',
			'BMD' => 'Bermuda Dollar',
			'BOB' => 'Bolivia Boliviano',
			'BAM' => 'Bosnia and Herzegovina Convertible Marka',
			'BWP' => 'Botswana Pula',
			'BGN' => 'Bulgaria Lev',
			'BRL' => 'Brazil Real',
			'BND' => 'Brunei Darussalam Dollar',
			'KHR' => 'Cambodia Riel',
			'CAD' => 'Canada Dollar',
			'KYD' => 'Cayman Islands Dollar',
			'CLP' => 'Chile Peso',
			'CNY' => 'China Yuan Renminbi',
			'COP' => 'Colombia Peso',
			'CRC' => 'Costa Rica Colon',
			'HRK' => 'Croatia Kuna',
			'CUP' => 'Cuba Peso',
			'CZK' => 'Czech Republic Koruna',
			'DKK' => 'Denmark Krone',
			'DOP' => 'Dominican Republic Peso',
			'XCD' => 'East Caribbean Dollar',
			'EGP' => 'Egypt Pound',
			'SVC' => 'El Salvador Colon',
			'EEK' => 'Estonia Kroon',
			'EUR' => 'Euro Member Countries',
			'FKP' => 'Falkland Islands (Malvinas) Pound',
			'FJD' => 'Fiji Dollar',
			'GHC' => 'Ghana Cedis',
			'GIP' => 'Gibraltar Pound',
			'GTQ' => 'Guatemala Quetzal',
			'GGP' => 'Guernsey Pound',
			'GYD' => 'Guyana Dollar',
			'HNL' => 'Honduras Lempira',
			'HKD' => 'Hong Kong Dollar',
			'HUF' => 'Hungary Forint',
			'ISK' => 'Iceland Krona',
			'INR' => 'India Rupee',
			'IDR' => 'Indonesia Rupiah',
			'IRR' => 'Iran Rial',
			'IMP' => 'Isle of Man Pound',
			'ILS' => 'Israel Shekel',
			'JMD' => 'Jamaica Dollar',
			'JPY' => 'Japan Yen',
			'JEP' => 'Jersey Pound',
			'JOD' => 'Jordanian Dinar',
			'KES' => 'Kenyan Shilling',
			'KZT' => 'Kazakhstan Tenge',
			'KPW' => 'Korea (North) Won',
			'KRW' => 'Korea (South) Won',
			'KWD' => 'Kuwaiti Dinar',
			'KGS' => 'Kyrgyzstan Som',
			'LAK' => 'Laos Kip',
			'LVL' => 'Latvia Lat',
			'LBP' => 'Lebanon Pound',
			'LRD' => 'Liberia Dollar',
			'LTL' => 'Lithuania Litas',
			'MKD' => 'Macedonia Denar',
			'MYR' => 'Malaysia Ringgit',
			'MUR' => 'Mauritius Rupee',
			'MXN' => 'Mexico Peso',
			'MNT' => 'Mongolia Tughrik',
			'MZN' => 'Mozambique Metical',
			'NAD' => 'Namibia Dollar',
			'NPR' => 'Nepal Rupee',
			'ANG' => 'Netherlands Antilles Guilder',
			'NZD' => 'New Zealand Dollar',
			'NIO' => 'Nicaragua Cordoba',
			'NGN' => 'Nigeria Naira',
			'NOK' => 'Norway Krone',
			'OMR' => 'Oman Rial',
			'PKR' => 'Pakistan Rupee',
			'PAB' => 'Panama Balboa',
			'PYG' => 'Paraguay Guarani',
			'PEN' => 'Peru Nuevo Sol',
			'PHP' => 'Philippines Peso',
			'PLN' => 'Poland Zloty',
			'QAR' => 'Qatar Riyal',
			'RON' => 'Romania New Leu',
			'RUB' => 'Russia Ruble',
			'SHP' => 'Saint Helena Pound',
			'SAR' => 'Saudi Arabia Riyal',
			'RSD' => 'Serbia Dinar',
			'SCR' => 'Seychelles Rupee',
			'SGD' => 'Singapore Dollar',
			'SBD' => 'Solomon Islands Dollar',
			'SOS' => 'Somalia Shilling',
			'ZAR' => 'South Africa Rand',
			'LKR' => 'Sri Lanka Rupee',
			'SEK' => 'Sweden Krona',
			'CHF' => 'Switzerland Franc',
			'SRD' => 'Suriname Dollar',
			'SYP' => 'Syria Pound',
			'TWD' => 'Taiwan New Dollar',
			'THB' => 'Thailand Baht',
			'TTD' => 'Trinidad and Tobago Dollar',
			'TRL' => 'Turkey Lira (TRL)',
			'TRY' => 'Turkey Lira',
			'TVD' => 'Tuvalu Dollar',
			'TZS' => 'Tanzanian Shilling',
			'UAH' => 'Ukraine Hryvna',
			'GBP' => 'United Kingdom Pound',
			'USD' => 'United States Dollar',
			'UYU' => 'Uruguay Peso',
			'UZS' => 'Uzbekistan Som',
			'VUV' => 'Vanuatu Vatu',
			'VEF' => 'Venezuela Bolivar',
			'VND' => 'Viet Nam Dong',
			'XAF' => 'Central African CFA Franc',
			'XOF' => 'West African CFA Franc',
			'YER' => 'Yemen Rial',
			'ZMK' => 'Zambian Kwacha',
			'ZWD' => 'Zimbabwe Dollar',
		);
	}

	/**
	 * Returns the currency symbol for a given currency code.
	 *
	 * @param Application $application
	 * @param string|null $currency
	 * @return string|null
	 */
	public function symbol( Application $application, $currency = null ) {
		if ( ( ! $format = $this->formats( $application, $currency ) )
			|| ! isset( $format[2] )
		) {
			return $currency;
		}

		return $format[2];
	}

	/**
	 * Returns the formatting array for a given currency code.
	 *
	 * @param Application $application
	 * @param string|null $currency
	 * @return array|null
	 */
	public function formats( Application $application, $currency = null ) {
		// Currencies each with an array of decimals, prepend = 0 or append = 1 symbol, symbol.
		$formats = array(
			'AUD' => array( 2, 0, 'AU$' ), // Australian Dollar
			'BHD' => array( 3 ), // Bahraini Dinar
			'BRL' => array( 2, 0, 'R$' ), // Brazilian Real
			'CAD' => array( 2, 0, 'CA$' ), // Canadian Dollar
			'CLP' => array( 0 ), // Chilean Peso
			'CNY' => array( 2, 0, 'CN&yen;' ), // China Yuan Renminbi
			'CZK' => array( 2, 1, 'Kc' ), // Czech Koruna
			'XCD' => array( 2, 0, 'EC$' ), // East Caribbean Dollar
			'EUR' => array( 2, 0, '&euro;' ), // Euro
			'HKD' => array( 2, 0, 'HK$' ), // Hong Kong Dollar
			'HUF' => array( 0 ), // Hungary Forint
			'ISK' => array( 0, 1, 'kr' ), // Iceland Krona
			'INR' => array( 2, 0, '&#2352;' ), // Indian Rupee
			'JPY' => array( 0, 0, '&yen;' ), // Japan Yen
			'JOD' => array( 3 ), // Jordanian Dinar
			'KWD' => array( 3 ), // Kuwaiti Dinar
			'LBP' => array( 0 ), // Lebanese Pound
			'LTL' => array( 2, 1, 'Lt' ), // Lithuanian Litas
			'MUR' => array( 0 ), // Mauritius Rupee
			'MXN' => array( 2, 0, 'MX$' ), // Mexican Peso
			'ILS' => array( 2, 0, '&#8362;' ), // New Israeli Shekel
			'NGN' => array( 0, 0, '&#8358;' ),
			'NZD' => array( 2, 0, 'NZ$' ), // New Zealand Dollar
			'NOK' => array( 2, 1, 'kr' ), // Norwegian Krone
			'GBP' => array( 2, 0, '&pound;' ), // Pound Sterling
			'OMR' => array( 3 ), // Rial Omani
			'ZAR' => array( 2, 0, 'R' ), // South Africa Rand
			'KRW' => array( 0, 0, '&#8361;' ), // Korea (South) Won
			'SEK' => array( 2, 1, 'kr' ), // Swedish Krona
			'CHF' => array( 2, 0, 'SFr ' ), // Swiss Franc
			'TWD' => array( 2, 0, 'NT$' ), // Taiwan Dollar
			'THB' => array( 2, 1, '&#3647;' ), // Thailand Baht
			'TRL' => array( 2, 0, '&#8378;' ), // Turkish Lira
			'TRY' => array( 2, 0, '&#8378;' ), // Turkish Lira
			'USD' => array( 2, 0, '$' ), // US Dollar
			'VUV' => array( 0 ), // Vanuatu Vatu
			'VND' => array( 0, 0, '&#x20ab;' ), // Viet Nam Dong
			'XAF' => array( 0 ), // Central African CFA Franc
			'XOF' => array( 0 ), // West African CFA Franc
		);
		if ( isset( $currency ) ) {
			return isset( $formats[ $currency = strtoupper( $currency ) ] ) ? $formats[ $currency ] : null;
		}
		return $formats;
	}

	/**
	 * Formats a value as a currency string, optionally attaching the symbol.
	 *
	 * @param Application $application
	 * @param mixed       $value
	 * @param string      $currency
	 * @param bool|int    $attachSymbol
	 * @param array|null  $format
	 * @return string
	 */
	public function format( Application $application, $value, $currency, $attachSymbol = true, ?array $format = null ) {
		$currency = strtoupper( $currency );
		if ( $currency_format = $this->formats( $application, $currency ) ) {
			$format = isset( $format ) ? array_merge( $currency_format, $format ) : $currency_format;
		} elseif ( ! isset( $format ) ) {
				$format = array( 2 );
		}
		$format = $application->Filter( 'system_currency_format', $format, array( $currency ) );
		$value  = $currency === 'INR' ?
			$this->numberFormatIndian( $application, $value, $format[0] ) :
			$application->getPlatform()->numberFormat( $value, $format[0] );
		if ( $attachSymbol !== false ) {
			if ( ! isset( $format[2] ) ) {
				// No symbol
				$value .= ' ' . $currency;
			} else {
				// Has symbol
				if ( is_numeric( $attachSymbol ) ) {
					$format[1] = $attachSymbol === 0 ? 0 : 1;
				}
				if ( empty( $format[1] ) ) {
					$value = $format[2] . $value; // prepend symbol
				} else {
					$value .= $format[2]; // append symbol
				}
			}
		}
		return $value;
	}

	/**
	 * Formats a number in the Indian numbering system.
	 *
	 * @param Application $application
	 * @param mixed       $value
	 * @param int         $decLength
	 * @return string
	 */
	public function numberFormatIndian( Application $application, $value, $decLength = 2 ) {
		if ( strpos( $value, '.' ) ) {
			list($value, $decimals) = explode( '.', $value );
			if ( strlen( $decimals ) > $decLength ) {
				$decimals = substr( $decimals, 0, $decLength );
			} else {
				while ( $decLength - strlen( $decimals ) ) {
					$decimals .= '0';
				}
			}
		}
		if ( strlen( $value ) > 5 ) {
			$last_three = substr( $value, -3 );
			$value      = substr( $value, 0, -3 ); // remove last three
			if ( strlen( $value ) % 2 === 1 ) {
				$value = '0' . $value; // prepend with extra digit to be able to split by 2 digits
			}
			$formatted = '';
			foreach ( str_split( $value, 2 ) as $_value ) {
				// Convert first 2 to int to remove prefixed 0 if any
				if ( $formatted === '' ) {
					$formatted = (int) $_value . ',';
				} else {
					$formatted .= $_value . ',';
				}
			}
			$formatted .= $last_three;
		} else {
			$formatted = number_format( $value, $decLength );
		}
		return isset( $decimals ) ? $formatted . '.' . $decimals : $formatted;
	}
}
