/** @fileoverview Javascript library for localised formatting of currency amounts.
 * 
 * @author Copyright (c) Vladimir Dzhuvinov <www.dzhuvinov.com>, 2008 - 2009
 * 
 * @version 2.1 (2009-03-12)
 */


/** @class Localised monetary formatter, based on standard POSIX LC_MONETARY definitions
 * (http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html#tag_07_03_03)
 *
 * @public
 * @constructor
 *
 * @param {object} posixMonDef A POSIX monetary locale definition object
 *        with properties:
 *
 *        @param {string} posixMonDef.int_curr_symbol
 *
 *        The first three letters signify the ISO-4217 currency code,
 *        the fourth letter is the international symbol separation character
 *        (normally a space).
 *
 *
 *        @param {string} posixMonDef.currency_symbol
 *
 *        The local shorthand currency symbol, e.g. "$" for the en_US locale
 *
 *
 *        @param {string} posixMonDef.mon_decimal_point
 *
 *        The symbol to be used as the decimal delimiter (radix character)
 *
 *
 *        @param {string} posixMonDef.mon_thousands_sep
 *
 *        The symbol to be used as a separator for groups of digits to the
 *        left of the decimal delimiter.
 *
 *
 *        @param {string} posixMonDef.mon_grouping
 *
 *        A string that defines the size of each group of digits. The
 *        perand is a sequence of integers separated by semicolons (";").
 *        Each integer specifies the number of digits in each group, with the
 *        initial integer defining the size of the group preceding the
 *        decimal delimiter, and the following integers defining the
 *        preceding groups. If the last integer is not -1, then the size of
 *        the previous group (if any) must be repeatedly used for the
 *        remainder of the digits. If the last integer is -1, then no
 *        further grouping is to be performed.
 *
 *
 *        @param {string} posixMonDef.positive_sign
 *
 *        The string to indicate a non-negative monetary amount.
 *
 *
 *        @param {string} posixMonDef.negative_sign
 *
 *        The string to indicate a negative monetary amount.
 *
 *
 *        @param {integer} posixMonDef.frac_digits
 *
 *        An integer representing the number of fractional digits (those to
 *        the right of the decimal delimiter) to be written in a formatted
 *        monetary quantity using currency_symbol.
 *
 *
 *        @param {integer} posixMonDef.int_frac_digits
 *
 *        An integer representing the number of fractional digits (those to
 *        the right of the decimal delimiter) to be written in a formatted
 *        monetary quantity using int_curr_symbol.
 *
 *
 *        @param {integer} posixMonDef.p_cs_precedes
 *
 *        An integer set to 1 if the currency_symbol precedes the value for a
 *        monetary quantity with a non-negative value, and set to 0 if the
 *        symbol succeeds the value.
 *
 *
 *        @param {integer} posixMonDef.n_cs_precedes
 *
 *        An integer set to 1 if the currency_symbol precedes the value for a
 *        monetary quantity with a negative value, and set to 0 if the symbol
 *        succeeds the value.
 *
 *
 *        @param {integer} posixMonDef.p_sep_by_space
 *
 *        Set to a value indicating the separation of the currency_symbol,
 *        the sign string, and the value for a non-negative formatted monetary
 *        quantity:
 *        
 *             <p>0 No space separates the currency symbol and value.</p>
 *
 *             <p>1 If the currency symbol and sign string are adjacent, a space
 *                  separates them from the value; otherwise, a space separates
 *                  the currency symbol from the value.</p>
 *
 *             <p>2 If the currency symbol and sign string are adjacent, a space
 *                  separates them; otherwise, a space separates the sign string
 *                  from the value.</p>
 *
 *
 *        @param {integer} posixMonDef.n_sep_by_space
 *
 *        Set to a value indicating the separation of the currency_symbol,
 *        the sign string, and the value for a negative formatted monetary
 *        quantity. Rules same as for p_sep_by_space.
 *
 *
 *        @param {integer} posixMonDef.p_sign_posn
 *
 *        An integer set to a value indicating the positioning of the
 *        positive_sign for a monetary quantity with a non-negative value:
 *	
 *	       <p>0 Parentheses enclose the quantity and the currency_symbol.</p>
 *
 *	       <p>1 The sign string precedes the quantity and the currency_symbol.</p>
 *
 *	       <p>2 The sign string succeeds the quantity and the currency_symbol.</p>
 *
 *	       <p>3 The sign string precedes the currency_symbol.</p>
 *
 *	       <p>4 The sign string succeeds the currency_symbol.</p>
 *
 *
 *	  @param {integer} posixMonDef.n_sign_posn
 *
 *	  An integer set to a value indicating the positioning of the
 *	  negative_sign for a negative formatted monetary quantity. Rules same
 *	  as for p_sign_posn.
 *
 *
 *	  @param {integer} posixMonDef.int_p_cs_precedes
 *
 *	  An integer set to 1 if the int_curr_symbol precedes the value for a
 *	  monetary quantity with a non-negative value, and set to 0 if the
 *	  symbol succeeds the value.
 *
 *
 *	  @param {integer} posixMonDef.int_n_cs_precedes
 *
 *	  An integer set to 1 if the int_curr_symbol precedes the value for a
 *	  monetary quantity with a negative value, and set to 0 if the symbol
 *	  succeeds the value.
 *
 *
 *	  @param {integer} posixMonDef.int_p_sep_by_space
 *
 *	  Set to a value indicating the separation of the int_curr_symbol,
 *	  the sign string, and the value for a non-negative internationally
 *	  formatted monetary quantity. Rules same as for p_sep_by_space.
 *
 *
 *	  @param {integer} posixMonDef.int_n_sep_by_space
 *
 *	  Set to a value indicating the separation of the int_curr_symbol,
 *	  the sign string, and the value for a negative internationally
 *	  formatted monetary quantity. Rules same as for p_sep_by_space.
 *
 *
 *	  @param {integer} posixMonDef.int_p_sign_posn
 *
 *	  An integer set to a value indicating the positioning of the
 *	  positive_sign for a positive monetary quantity formatted with the
 *	  international format. Rules same as for p_sign_posn.
 *
 *
 *	  @param {integer} posixMonDef.int_n_sign_posn
 *
 *	  An integer set to a value indicating the positioning of the
 *	  negative_sign for a negative monetary quantity formatted with the
 *	  international format. Rules same as for p_sign_posn.
 *
 * @param {string} [currencyCode] Set the currency explicitly by
 *        passing its international ISO-4217 code, e.g. "USD", "EUR", "GBP".
 *        Use this optional parameter to override the default local currency
 * 
 * @param {string} [altIntSymbol] Non-local currencies are formatted
 *        with their international ISO-4217 code to minimise ambiguity.
 *        Use this optional argument to apply a different symbol, such as the
 *        currency's shorthand sign. This is mostly useful when the shorthand
 *        sign is both internationally recognised and identifies the currency
 *        uniquely (e.g. the Euro or British Pound signs).
 *
 * @throws Error on undefined or invalid LC_MONETARY property
 */
function MonetaryFormatter(posixMonDef, currencyCode, altIntSymbol) {
	
	/** @private
	 * @description <p>Lookup table to determine the fraction digits for a specific
	 * currency; most currencies have 2 digits, so we store only those that
	 * deviate from the default.</p>
	 * <p>The data is from Unicode's CLDR version 1.6.1.</p>
	 * <p>It is "hard-wired" for referential convenience and is only looked up
	 * when an overriding currencyCode parameter is supplied.</p>
	 */
	this.currencyFractionDigits = {
		"ADP" : 0, "AFN" : 0, "ALL" : 0, "AMD" : 0, "BHD" : 3, "BIF" : 0,
		"BYR" : 0, "CLF" : 0, "CLP" : 0, "COP" : 0, "CRC" : 0, "DJF" : 0,
		"ESP" : 0, "GNF" : 0, "GYD" : 0, "HUF" : 0, "IDR" : 0, "IQD" : 0,
		"IRR" : 0, "ISK" : 0, "ITL" : 0, "JOD" : 3, "JPY" : 0, "KMF" : 0,
		"KPW" : 0, "KRW" : 0, "KWD" : 3, "LAK" : 0, "LBP" : 0, "LUF" : 0,
		"LYD" : 3, "MGA" : 0, "MGF" : 0, "MMK" : 0, "MNT" : 0, "MRO" : 0,
		"MUR" : 0, "OMR" : 3, "PKR" : 0, "PYG" : 0, "RSD" : 0, "RWF" : 0,
		"SLL" : 0, "SOS" : 0, "STD" : 0, "SYP" : 0, "TMM" : 0, "TND" : 3,
		"TRL" : 0, "TWD" : 0, "TZS" : 0, "UGX" : 0, "UZS" : 0, "VND" : 0,
		"VUV" : 0, "XAF" : 0, "XOF" : 0, "XPF" : 0, "YER" : 0, "ZMK" : 0,
		"ZWD" : 0
	};
	
	// save the LC_MONETARY definition and validate it
	this.def = posixMonDef;
	
	if (typeof this.def.int_curr_symbol != "string")
		throw "Error: undefined int_curr_symbol";
	
	if (! /[A-Za-z]{3}.?/.test(this.def.int_curr_symbol))
		throw "Error: invalid int_curr_symbol";

	if (typeof this.def.currency_symbol != "string")
		throw "Error: undefined currency_symbol";
	
	// may be empty string for currencies with no fractional part
	if (typeof this.def.mon_decimal_point != "string")
		throw "Error: undefined mon_decimal_point";
	
	if (typeof this.def.mon_thousands_sep != "string")
		throw "Error: undefined mon_thousands_sep";
	
	if (typeof this.def.mon_grouping != "string")
		throw "Error: undefined mon_grouping";
	
	if (typeof this.def.positive_sign != "string")
		throw "Error: undefined positive_sign";
	
	if (typeof this.def.negative_sign != "string")
		throw "Error: undefined negative_sign";
	
	if (typeof this.def.frac_digits != "number")
		throw "Error: undefined frac_digits";
	
	if (typeof this.def.frac_digits < 0)
		throw "Error: invalid frac_digits";
	
	if (typeof this.def.p_cs_precedes != "number")
		throw "Error: undefined p_cs_precedes";
	
	if (this.def.p_cs_precedes != 0 && this.def.p_cs_precedes != 1)
		throw "Error: invalid p_cs_precedes, must be 0 or 1";
	
	if (typeof this.def.n_cs_precedes != "number")
		throw "Error: undefined n_cs_precedes";

	if (this.def.n_cs_precedes != 0 && this.def.n_cs_precedes != 1)
		throw "Error: invalid n_cs_precedes, must be 0 or 1";
		

	if (typeof this.def.p_sep_by_space != "number")
		throw "Error: undefined p_sep_by_space";
	
	if (this.def.p_sep_by_space != 0 &&
	    this.def.p_sep_by_space != 1 &&
	    this.def.p_sep_by_space != 2)
		throw "Error: invalid p_sep_by_space, must be 0, 1 or 2";
		

	if (typeof this.def.n_sep_by_space != "number")
		throw "Error: undefined n_sep_by_space";
	
	if (this.def.n_sep_by_space != 0 &&
	    this.def.n_sep_by_space != 1 &&
	    this.def.n_sep_by_space != 2)
		throw "Error: invalid n_sep_by_space, must be 0, 1, or 2";
		

	if (typeof this.def.p_sign_posn != "number")
		throw "Error: undefined p_sign_posn";
	
	if (this.def.p_sign_posn != 0 &&
	    this.def.p_sign_posn != 1 &&
	    this.def.p_sign_posn != 2 &&
	    this.def.p_sign_posn != 3 &&
	    this.def.p_sign_posn != 4)
		throw "Error: invalid p_sign_posn, must be 0, 1, 2, 3 or 4";
		
	if (typeof this.def.n_sign_posn != "number")
		throw "Error: undefined n_sign_posn";
	
	if (this.def.n_sign_posn != 0 &&
	    this.def.n_sign_posn != 1 &&
	    this.def.n_sign_posn != 2 &&
	    this.def.n_sign_posn != 3 &&
	    this.def.n_sign_posn != 4)
		throw "Error: invalid n_sign_posn, must be 0, 1, 2, 3 or 4";
	

	if (typeof this.def.int_frac_digits != "number")
		throw "Error: undefined int_frac_digits";
	
	if (typeof this.def.int_frac_digits < 0)
		throw "Error: invalid int_frac_digits";
	
	if (typeof this.def.int_p_cs_precedes != "number")
		throw "Error: undefined int_p_cs_precedes";
	
	if (this.def.int_p_cs_precedes != 0 && this.def.int_p_cs_precedes != 1)
		throw "Error: invalid int_p_cs_precedes, must be 0 or 1";
	
	if (typeof this.def.int_n_cs_precedes != "number")
		throw "Error: undefined int_n_cs_precedes";

	if (this.def.int_n_cs_precedes != 0 && this.def.int_n_cs_precedes != 1)
		throw "Error: invalid int_n_cs_precedes, must be 0 or 1";
		

	if (typeof this.def.int_p_sep_by_space != "number")
		throw "Error: undefined int_p_sep_by_space";
	
	if (this.def.int_p_sep_by_space != 0 &&
	    this.def.int_p_sep_by_space != 1 &&
	    this.def.int_p_sep_by_space != 2)
		throw "Error: invalid int_p_sep_by_space, must be 0, 1 or 2";
		

	if (typeof this.def.int_n_sep_by_space != "number")
		throw "Error: undefined int_n_sep_by_space";
	
	if (this.def.int_n_sep_by_space != 0 &&
	    this.def.int_n_sep_by_space != 1 &&
	    this.def.int_n_sep_by_space != 2)
		throw "Error: invalid int_n_sep_by_space, must be 0, 1, or 2";
		

	if (typeof this.def.int_p_sign_posn != "number")
		throw "Error: undefined int_p_sign_posn";
	
	if (this.def.int_p_sign_posn != 0 &&
	    this.def.int_p_sign_posn != 1 &&
	    this.def.int_p_sign_posn != 2 &&
	    this.def.int_p_sign_posn != 3 &&
	    this.def.int_p_sign_posn != 4)
		throw "Error: invalid int_p_sign_posn, must be 0, 1, 2, 3 or 4";
		
	if (typeof this.def.int_n_sign_posn != "number")
		throw "Error: undefined int_n_sign_posn";
	
	if (this.def.int_n_sign_posn != 0 &&
	    this.def.int_n_sign_posn != 1 &&
	    this.def.int_n_sign_posn != 2 &&
	    this.def.int_n_sign_posn != 3 &&
	    this.def.int_n_sign_posn != 4)
		throw "Error: invalid int_n_sign_posn, must be 0, 1, 2, 3 or 4";
	
	
	// optional currencyCode argument?
	if (typeof currencyCode == "string") {
		// user wanted to override the local currency
		this.currencyCode = currencyCode.toUpperCase();
		
		// must override the frac digits too, for some
		// currencies have 0, 2 or 3!
		var numDigits = this.currencyFractionDigits[this.currencyCode];
		if (typeof numDigits != "number")
			numDigits = 2; // default for most currencies
		this.def.frac_digits = numDigits;
		this.def.int_frac_digits = numDigits;
	}
	else {
		// use local currency
		this.currencyCode = this.def.int_curr_symbol.substring(0,3).toUpperCase();
	}
	
	// extract intl. currency separator
	this.intSep = this.def.int_curr_symbol.charAt(3);
	
	// flag local or intl. sign formatting?
	if (this.currencyCode == this.def.int_curr_symbol.substring(0,3)) {
		// currency matches the local one? ->
		// formatting with local symbol and parameters
		this.internationalFormatting = false;
		this.curSym = this.def.currency_symbol;
	}
	else {
		// currency doesn't match the local ->
		
		// do we have an overriding currency symbol?
		if (typeof altIntSymbol == "string") {
			// -> force formatting with local parameters, using alt symbol
			this.curSym = altIntSymbol;
			this.internationalFormatting = false;
		}
		else {
			// -> force formatting with intl. sign and parameters
			this.internationalFormatting = true;
		}
	}
	
	
	/** @public
	 *
	 * @description Format a monetary amount according to the POSIX monetary locale
	 * definition
	 * <pre>
	 * For local currencies the native shorthand symbol will be used for
	 * formatting.
	 * Example:
	 *        locale is en_US
	 *        currency is USD
	 *        -> the "$" symbol will be used, e.g. $123.45
	 *        
	 * For non-local currencies the international ISO-4217 code will be
	 * used for formatting.
	 * Example:
	 *       locale is en_US (which has USD as currency)
	 *       currency is EUR
	 *       -> the ISO three-letter code will be used, e.g. EUR 123.45
	 *
	 * If the currency is non-local, but an alternative currency symbol was
	 * provided, this is will be used instead.
	 * Example
	 *       locale is en_US (which has USD as currency)
	 *       currency is EUR
	 *       an alternative symbol is provided - "€"
	 *       -> the alternative symbol will be used, e.g. €123.45
	 * </pre>
	 * 
	 * @param {number|string} amount The amount to format as currency
	 * 
	 * @param {string} [flags] Flags to modify the formatted output:
	 *       ^ suppress grouping
	 *       ! suppress the currency symbol
	 *       ~ suppress the currency symbol and the sign (positive or negative)
	 *       i force international sign (ISO-4217 code) formatting
	 *       
	 * @returns The formatted currency amount as string
	 *
	 * @throws "Error: invalid amount" on bad amount
	 */
	this.format = function(amount, flags) {
		
		// check if we have a valid amount (number or string parsable to float)
		if (typeof amount == "string")
			amount = parseFloat(amount);
		
		if (isNaN(amount))
			amount = 0;
		
		if (typeof amount != "number")
			throw "Error: invalid amount: " + amount + " type: " + typeof amount;

		// Round the amount to nearest integer (.5) 
		amount = Math.round(amount * 100) / 100

		// convert amount to string
		amount = String(amount);
		
		// parse amount into object with properties sign, integer and fraction
		var parsedAmount = this._parseAmount(amount);
		
		// format integer part with grouping chars
		var formattedIntegerPart = (this._hasFlag("^", flags)) ?
			(parsedAmount.integer) : (this._formatIntegerPart(parsedAmount.integer));
		
		// format fractional part
		var formattedFractionPart = this._formatFractionPart(parsedAmount.fraction);
		
		// join integer and decimal parts using the mon_decimal_point property
		// while regarding the frac_digits flag
		// Note: preserve extra precision if user wished so
		if (this.def.frac_digits > 0 || formattedFractionPart.length)
			var quantity = formattedIntegerPart + this.def.mon_decimal_point + formattedFractionPart;
		else
			var quantity = formattedIntegerPart;
		
		// do final formatting with sign and symbol
		if (this._hasFlag("~", flags)) {
			return quantity;
		}
		else {
			var suppressSymbol = this._hasFlag("!", flags) ? true : false;
			
			if (this.internationalFormatting || this._hasFlag("i", flags)) {
				
				// format with ISO-4217 code (suppressed or not)
				if (suppressSymbol)
					return this._formatAsInternationalCurrencyWithNoSym(parsedAmount.sign, quantity);
				else
					return this._formatAsInternationalCurrency(parsedAmount.sign, quantity);
			}
			else {
				// format with local currency code (suppressed or not)
				if (suppressSymbol)
					return this._formatAsLocalCurrencyWithNoSym(parsedAmount.sign, quantity);
				else
					return this._formatAsLocalCurrency(parsedAmount.sign, quantity);
			}
		}
	}
	
	
	/** @private
	 *
	 * @description Check if flag is contained in flag string
	 *
	 * Note: this function was written to compensate for the lack of indexOf() in IE
	 * 
	 * @param {string} flag The flag to search for
	 * @param {string} flagString The flag string
	 *
	 * @returns true if the flag is found, else false
	 */
	this._hasFlag = function (flag, flagString) {
		
		if (typeof flag != "string" || typeof flagString != "string")
			return false;
		
		for (var i=0; i < flagString.length; i++) {
			if (flagString.charAt(i) == flag)
				return true;
		}
		return false;
	}
	
	
	/** @private
	 *
	 * @description Take a monetary amount (as string) and return
	 * its sign, integer and fractional parts packed as an object
	 *
	 * @param {string} amount The amount, e.g. "123.45" or "-56.78"
	 * 
	 * @returns {object} Parsed amount object with properties sign,
	 *          integer and fraction
	 */
	this._parseAmount = function (amount) {
		
		var obj = {};
		
		// extract sign
		if (amount.charAt(0) == "-") {
			obj.sign = "-";
			amount = amount.substring(1);
		}
		else {
			obj.sign = "+";
		}
		
		// split amount into integer and decimal parts
		var amountParts = amount.split(".");
		if (!amountParts[1])
			amountParts[1] = ""; // we need "" instead of null
		
		obj.integer = amountParts[0];
		obj.fraction = amountParts[1];
		
		return obj;
	}
	
	
	/** @private
	 *
	 * @description Format the integer part using the mon_grouping and mon_thousands_sep
	 * parameters
	 * 
	 * @param {string} intPart The integer part of the amount, as string
	 * 
	 * @returns {string} The formatted integer part, as string
	 */
	this._formatIntegerPart = function (intPart) {
		
		// empty separator string? no grouping?
		// -> return immediately with no formatting!
		if (this.def.mon_thousands_sep == "" || this.def.mon_grouping == "-1")
			return intPart;
		
		// turn the semicolon-separated string of integers into an array
		var groupSizes = this.def.mon_grouping.split(";");
		
		// the formatted output string
		var out = "";
		
		// the intPart string position to process next,
		// start at string end, e.g. "10000000<starts here"
		var pos = intPart.length;
		
		// process the intPart string backwards
		//     "1000000000"
		//            <---\ direction
		while (pos > 0) {
			
			// get next group size (if any, otherwise keep last)
			if (groupSizes.length > 0)
				var size = parseInt(groupSizes.shift());
			
			// int parse error?
			if (isNaN(size))
				throw "Error: invalid mon_grouping";
			
			// size is -1? -> no more grouping, so just copy string remainder
			if (size == -1) {
				out = intPart.substring(0, pos) + out;
				break;
			}
			
			pos -= size; // move to next sep. char. position
			
			// position underrun? -> just copy string remainder
			if (pos < 1) {
				out = intPart.substring(0, pos + size) + out;
				break;
			}
			
			// extract group and apply sep. char.
			out = this.def.mon_thousands_sep + intPart.substring(pos, pos + size) + out;
		}
		
		return out;
	}
	
	
	/** @private
	 *
	 * Format the fractional part using the appropriate frac_digits or
	 * int_frac_digits flag
	 *
	 * @param {string} fracPart The fractional part of the amount
	 * @returns {string} The formatted fractional part
	 */
	this._formatFractionPart = function (fracPart) {
		
		// append zeroes up to (int_)frac_digits if necessary
		if (this.internationalFormatting) {
			
			if (this.def.int_frac_digits == 0) {
				return "";
			}
			
			for (var i=0; fracPart.length < this.def.int_frac_digits; i++)
				fracPart = fracPart + "0";
		}
		else {

			if (this.def.frac_digits == 0) {
				return "";
			}

			for(var i=0; fracPart.length < this.def.frac_digits; i++)
				fracPart = fracPart + "0";
		}
		return fracPart;
	}
	
	
	/** @private
	 *
	 * @description Assemble the final string with sign, separator and symbol as local
	 * currency
	 *
	 * @param {string} sign The amount sign: "+" or "-"
	 * @param {string} q The formatted quantity (unsigned)
	 *
	 * @returns {string} The final formatted string
	 */
	this._formatAsLocalCurrency = function (sign, q) {
		
		// assemble final formatted amount by going over all possible value combinations of:
		// sign {+,-} , sign position {0,1,2,3,4} , separator {0,1,2} , symbol position {0,1}
		if (sign == "+") {
			
			// parentheses
			if      (this.def.p_sign_posn == 0 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 0) {
				return "(" + q + this.curSym + ")";
			}
			else if (this.def.p_sign_posn == 0 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 1) {
				return "(" + this.curSym + q + ")";
			}
			else if (this.def.p_sign_posn == 0 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 0) {
				return "(" + q + " " + this.curSym + ")";
			}
			else if (this.def.p_sign_posn == 0 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 1) {
				return "(" + this.curSym + " " + q + ")";
			}
			
			// sign before q + sym
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 0) {
				return this.def.positive_sign + q + this.curSym;
			}
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + this.curSym + q;
			}
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 0) {
				return this.def.positive_sign + q + " " + this.curSym;
			}
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + this.curSym + " " + q;
			}
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 0) {
				return this.def.positive_sign + " " + q + this.curSym;
			}
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + " " + this.curSym + q;
			}
			
			// sign after q + sym
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 0) {
				return q + this.curSym + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 1) {
				return this.curSym + q + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 0) {
				return  q + " " + this.curSym + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 1) {
				return this.curSym + " " + q + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 0) {
				return q + this.curSym + " " + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 1) {
				return this.curSym + q + " " + this.def.positive_sign;
			}
			
			// sign before sym
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 0) {
				return q + this.def.positive_sign + this.curSym;
			}
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + this.curSym + q;
			}
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 0) {
				return q + " " + this.def.positive_sign + this.curSym;
			}
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + this.curSym + " " + q;
			}
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 0) {
				return q + this.def.positive_sign + " " + this.curSym;
			}
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + " " + this.curSym + q;
			}
			
			// sign after symbol
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 0) {
				return q + this.curSym + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 1) {
				return this.curSym + this.def.positive_sign + q;
			}
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 0) {
				return  q + " " + this.curSym + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 1) {
				return this.curSym + this.def.positive_sign + " " + q;
			}
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 0) {
				return q + this.curSym + " " + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 1) {
				return this.curSym + " " + this.def.positive_sign + q;
			}
			
		}
		else if (sign == "-") {
			
			// parentheses enclose q + sym
			if      (this.def.n_sign_posn == 0 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 0) {
				return "(" + q + this.curSym + ")";
			}
			else if (this.def.n_sign_posn == 0 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 1) {
				return "(" + this.curSym + q + ")";
			}
			else if (this.def.n_sign_posn == 0 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 0) {
				return "(" + q + " " + this.curSym + ")";
			}
			else if (this.def.n_sign_posn == 0 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 1) {
				return "(" + this.curSym + " " + q + ")";
			}
			
			// sign before q + sym
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 0) {
				return this.def.negative_sign + q + this.curSym;
			}
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + this.curSym + q;
			}
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 0) {
				return this.def.negative_sign + q + " " + this.curSym;
			}
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + this.curSym + " " + q;
			}
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 0) {
				return this.def.negative_sign + " " + q + this.curSym;
			}
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + " " + this.curSym + q;
			}
			
			// sign after q + sym
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 0) {
				return q + this.curSym + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 1) {
				return this.curSym + q + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 0) {
				return  q + " " + this.curSym + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 1) {
				return this.curSym + " " + q + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 0) {
				return q + this.curSym + " " + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 1) {
				return this.curSym + q + " " + this.def.negative_sign;
			}
			
			// sign before sym
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 0) {
				return q + this.def.negative_sign + this.curSym;
			}
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + this.curSym + q;
			}
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 0) {
				return q + " " + this.def.negative_sign + this.curSym;
			}
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + this.curSym + " " + q;
			}
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 0) {
				return q + this.def.negative_sign + " " + this.curSym;
			}
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + " " + this.curSym + q;
			}
			
			// sign after symbol
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 0) {
				return q + this.curSym + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 1) {
				return this.curSym + this.def.negative_sign + q;
			}
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 0) {
				return  q + " " + this.curSym + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 1) {
				return this.curSym + this.def.negative_sign + " " + q;
			}
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 0) {
				return q + this.curSym + " " + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 1) {
				return this.curSym + " " + this.def.negative_sign + q;
			}
		}
		
		// throw error if we fall through
		throw "Error: invalid POSIX LC MONETARY definition";
	}
	
	
	/** @private
	 *
	 * @description Assemble the final string with sign, separator and ISO-4217
	 * currency code
	 *
	 * @param {string} sign The amount sign: "+" or "-"
	 * @param {string} q The formatted quantity (unsigned)
	 *
	 * @returns {string} The final formatted string
	 */
	this._formatAsInternationalCurrency = function (sign, q) {
		
		// assemble the final formatted amount by going over all possible value combinations of:
		// sign {+,-} , sign position {0,1,2,3,4} , separator {0,1,2} , symbol position {0,1}
		
		if (sign == "+") {
			
			// parentheses
			if      (this.def.int_p_sign_posn == 0 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 0) {
				return "(" + q + this.currencyCode + ")";
			}
			else if (this.def.int_p_sign_posn == 0 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 1) {
				return "(" + this.currencyCode + q + ")";
			}
			else if (this.def.int_p_sign_posn == 0 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 0) {
				return "(" + q + this.intSep + this.currencyCode + ")";
			}
			else if (this.def.int_p_sign_posn == 0 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 1) {
				return "(" + this.currencyCode + this.intSep + q + ")";
			}
			
			// sign before q + sym
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 0) {
				return this.def.positive_sign + q + this.currencyCode;
			}
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.currencyCode + q;
			}
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 0) {
				return this.def.positive_sign + q + this.intSep + this.currencyCode;
			}
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.currencyCode + this.intSep + q;
			}
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 0) {
				return this.def.positive_sign + this.intSep + q + this.currencyCode;
			}
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.intSep + this.currencyCode + q;
			}
			
			// sign after q + sym
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 0) {
				return q + this.currencyCode + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 1) {
				return this.currencyCode + q + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 0) {
				return  q + this.intSep + this.currencyCode + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 1) {
				return this.currencyCode + this.intSep + q + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 0) {
				return q + this.currencyCode + this.intSep + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 1) {
				return this.currencyCode + q + this.intSep + this.def.positive_sign;
			}
			
			// sign before sym
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 0) {
				return q + this.def.positive_sign + this.currencyCode;
			}
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.currencyCode + q;
			}
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 0) {
				return q + this.intSep + this.def.positive_sign + this.currencyCode;
			}
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.currencyCode + this.intSep + q;
			}
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 0) {
				return q + this.def.positive_sign + this.intSep + this.currencyCode;
			}
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.intSep + this.currencyCode + q;
			}
			
			// sign after symbol
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 0) {
				return q + this.currencyCode + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 1) {
				return this.currencyCode + this.def.positive_sign + q;
			}
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 0) {
				return  q + this.intSep + this.currencyCode + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 1) {
				return this.currencyCode + this.def.positive_sign + this.intSep + q;
			}
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 0) {
				return q + this.currencyCode + this.intSep + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 1) {
				return this.currencyCode + this.intSep + this.def.positive_sign + q;
			}
			
		}
		else if (sign == "-") {
			
			// parentheses enclose q + sym
			if      (this.def.int_n_sign_posn == 0 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 0) {
				return "(" + q + this.currencyCode + ")";
			}
			else if (this.def.int_n_sign_posn == 0 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 1) {
				return "(" + this.currencyCode + q + ")";
			}
			else if (this.def.int_n_sign_posn == 0 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 0) {
				return "(" + q + this.intSep + this.currencyCode + ")";
			}
			else if (this.def.int_n_sign_posn == 0 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 1) {
				return "(" + this.currencyCode + this.intSep + q + ")";
			}
			
			// sign before q + sym
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 0) {
				return this.def.negative_sign + q + this.currencyCode;
			}
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.currencyCode + q;
			}
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 0) {
				return this.def.negative_sign + q + this.intSep + this.currencyCode;
			}
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.currencyCode + this.intSep + q;
			}
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 0) {
				return this.def.negative_sign + this.intSep + q + this.currencyCode;
			}
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.intSep + this.currencyCode + q;
			}
			
			// sign after q + sym
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 0) {
				return q + this.currencyCode + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 1) {
				return this.currencyCode + q + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 0) {
				return  q + this.intSep + this.currencyCode + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 1) {
				return this.currencyCode + this.intSep + q + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 0) {
				return q + this.currencyCode + this.intSep + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 1) {
				return this.currencyCode + q + this.intSep + this.def.negative_sign;
			}
			
			// sign before sym
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 0) {
				return q + this.def.negative_sign + this.currencyCode;
			}
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.currencyCode + q;
			}
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 0) {
				return q + this.intSep + this.def.negative_sign + this.currencyCode;
			}
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.currencyCode + this.intSep + q;
			}
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 0) {
				return q + this.def.negative_sign + this.intSep + this.currencyCode;
			}
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.intSep + this.currencyCode + q;
			}
			
			// sign after symbol
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 0) {
				return q + this.currencyCode + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 1) {
				return this.currencyCode + this.def.negative_sign + q;
			}
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 0) {
				return  q + this.intSep + this.currencyCode + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 1) {
				return this.currencyCode + this.def.negative_sign + this.intSep + q;
			}
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 0) {
				return q + this.currencyCode + this.intSep + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 1) {
				return this.currencyCode + this.intSep + this.def.negative_sign + q;
			}
		}
		
		// throw error if we fall through
		throw "Error: invalid POSIX LC MONETARY definition";
	}
	
	
	/** @private
	 *
	 * @description Assemble the final string with sign and separator, but suppress the
	 * local currency symbol
	 *
	 * @param {string} sign The amount sign: "+" or "-"
	 * @param {string} q The formatted quantity (unsigned)
	 *
	 * @returns {string} The final formatted string
	 */
	this._formatAsLocalCurrencyWithNoSym = function (sign, q) {
		
		// assemble the final formatted amount by going over all possible value combinations of:
		// sign {+,-} , sign position {0,1,2,3,4} , separator {0,1,2} , symbol position {0,1}
		
		if (sign == "+") {
			
			// parentheses
			if      (this.def.p_sign_posn == 0) {
				return "(" + q + ")";
			}
			
			// sign before q + sym
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 0) {
				return this.def.positive_sign + q;
			}
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + q;
			}
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 0) {
				return this.def.positive_sign + q;
			}
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + q;
			}
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 0) {
				return this.def.positive_sign + " " + q;
			}
			else if (this.def.p_sign_posn == 1 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + " " + q;
			}
			
			// sign after q + sym
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 0) {
				return q + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 1) {
				return q + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 0) {
				return  q + " " + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 1) {
				return q + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 0) {
				return q + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 2 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 1) {
				return q + " " + this.def.positive_sign;
			}
			
			// sign before sym
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 0) {
				return q + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + q;
			}
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 0) {
				return q + " " + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + " " + q;
			}
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 0) {
				return q + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 3 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + " " + q;
			}
			
			// sign after symbol
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 0) {
				return q + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 0 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + q;
			}
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 0) {
				return  q + " " + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 1 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + " " + q;
			}
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 0) {
				return q + " " + this.def.positive_sign;
			}
			else if (this.def.p_sign_posn == 4 && this.def.p_sep_by_space == 2 && this.def.p_cs_precedes == 1) {
				return this.def.positive_sign + q;
			}
			
		}
		else if (sign == "-") {
			
			// parentheses enclose q + sym
			if      (this.def.n_sign_posn == 0) {
				return "(" + q + ")";
			}
			
			// sign before q + sym
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 0) {
				return this.def.negative_sign + q;
			}
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + q;
			}
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 0) {
				return this.def.negative_sign + q;
			}
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + " " + q;
			}
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 0) {
				return this.def.negative_sign + " " + q;
			}
			else if (this.def.n_sign_posn == 1 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + " " + q;
			}
			
			// sign after q + sym
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 0) {
				return q + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 1) {
				return q + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 0) {
				return  q + " " + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 1) {
				return q + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 0) {
				return q + " " + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 2 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 1) {
				return q + " " + this.def.negative_sign;
			}
			
			// sign before sym
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 0) {
				return q + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + q;
			}
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 0) {
				return q + " " + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + " " + q;
			}
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 0) {
				return q + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 3 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + " " + q;
			}
			
			// sign after symbol
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 0) {
				return q + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 0 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + q;
			}
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 0) {
				return  q + " " + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 1 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + " " + q;
			}
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 0) {
				return q + " " + this.def.negative_sign;
			}
			else if (this.def.n_sign_posn == 4 && this.def.n_sep_by_space == 2 && this.def.n_cs_precedes == 1) {
				return this.def.negative_sign + q;
			}
		}
		
		// throw error if we fall through
		throw "Error: invalid POSIX LC MONETARY definition";
	}
	
	/** @private
	 *
	 * @description Assemble the final string with sign and separator, but suppress
	 * the ISO-4217 currency code
	 *
	 * @param {string} sign The amount sign: "+" or "-"
	 * @param {string} q The formatted quantity (unsigned)
	 *
	 * @returns {string} The final formatted string
	 */
	this._formatAsInternationalCurrencyWithNoSym = function (sign, q) {
		
		// assemble the final formatted amount by going over all possible value combinations of:
		// sign {+,-} , sign position {0,1,2,3,4} , separator {0,1,2} , symbol position {0,1}
		
		if (sign == "+") {
			
			// parentheses
			if      (this.def.int_p_sign_posn == 0) {
				return "(" + q + ")";
			}
			
			// sign before q + sym
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 0) {
				return this.def.positive_sign + q;
			}
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + q;
			}
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 0) {
				return this.def.positive_sign + q;
			}
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.intSep + q;
			}
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 0) {
				return this.def.positive_sign + this.intSep + q;
			}
			else if (this.def.int_p_sign_posn == 1 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.intSep + q;
			}
			
			// sign after q + sym
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 0) {
				return q + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 1) {
				return q + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 0) {
				return  q + this.intSep + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 1) {
				return q + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 0) {
				return q + this.intSep + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 2 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 1) {
				return q + this.intSep + this.def.positive_sign;
			}
			
			// sign before sym
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 0) {
				return q + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + q;
			}
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 0) {
				return q + this.intSep + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.intSep + q;
			}
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 0) {
				return q + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 3 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.intSep + q;
			}
			
			// sign after symbol
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 0) {
				return q + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 0 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + q;
			}
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 0) {
				return  q + this.intSep + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 1 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + this.intSep + q;
			}
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 0) {
				return q + this.intSep + this.def.positive_sign;
			}
			else if (this.def.int_p_sign_posn == 4 && this.def.int_p_sep_by_space == 2 && this.def.int_p_cs_precedes == 1) {
				return this.def.positive_sign + q;
			}
			
		}
		else if (sign == "-") {
			
			// parentheses enclose q + sym
			if      (this.def.int_n_sign_posn == 0) {
				return "(" + q + ")";
			}
			
			// sign before q + sym
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 0) {
				return this.def.negative_sign + q;
			}
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + q;
			}
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 0) {
				return this.def.negative_sign + q;
			}
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.intSep + q;
			}
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 0) {
				return this.def.negative_sign + this.intSep + q;
			}
			else if (this.def.int_n_sign_posn == 1 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.intSep + q;
			}
			
			// sign after q + sym
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 0) {
				return q + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 1) {
				return q + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 0) {
				return  q + this.intSep + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 1) {
				return q + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 0) {
				return q + this.intSep + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 2 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 1) {
				return q + this.intSep + this.def.negative_sign;
			}
			
			// sign before sym
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 0) {
				return q + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + q;
			}
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 0) {
				return q + this.intSep + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.intSep + q;
			}
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 0) {
				return q + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 3 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.intSep + q;
			}
			
			// sign after symbol
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 0) {
				return q + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 0 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + q;
			}
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 0) {
				return  q + this.intSep + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 1 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + this.intSep + q;
			}
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 0) {
				return q + this.intSep + this.def.negative_sign;
			}
			else if (this.def.int_n_sign_posn == 4 && this.def.int_n_sep_by_space == 2 && this.def.int_n_cs_precedes == 1) {
				return this.def.negative_sign + q;
			}
		}
		
		// throw error if we fall through
		throw "Error: invalid POSIX LC MONETARY definition";
	}
}


// end-of-file
