
/**
 * Tester is used for comparing 2 parameters depending if it's ascending or descending. It's internally used for table sorting atm
 * But more uses can be thought of :
 * - writing testers for the validator
 * - etc. etc.
 *
 * TODO : write more comparers and testers
 */
var Akyla_Prototype_Tester = Class.create(
{
	preferences :
	{
		minValidYear : 1800,
		maxValidYear : null
	},
	/**
	 * yawn
	 */
	initialize : function ()
	{
	},
	/**
	 * Compare two integers with each other
	 * @param integer a First integer
	 * @param integer b Second integer
	 * @param asc Ascending or descending order?
	 * @return boolean True if a > b and asc, fals otherwise
	 */
	integerCompare : function(a,b, asc)
	{
		//console.log(asc);
		var result = asc ? (parseInt(a,10) - parseInt(b,10)) :  (parseInt(b,10) -parseInt(a,10));
		return result;
	},
	/**
	 * Compare two unknowns with each other
	 * @param integer a First unknown
	 * @param integer b Second unknown
	 * @param asc Ascending or descending order?
	 * @return boolean True if a > b and asc, fals otherwise
	 */
	defaultCompare : function(a,b, asc)
	{
		if (a>b) {
			result = 1;
		} else if (a==b) {
			result = 0;
		} else if (a<b) {
			result = -1;
		}
		if (!asc) {
			result = result*-1;
		}
		return result;
	},
	/**
	 * Compare two strings with each other (this compare is not case sensitive)
	 * @param string First unknown
	 * @param string b Second unknown
	 * @param asc Ascending or descending order?
	 * @return boolean True if a > b and asc, fals otherwise
	 */
	stringCompare : function(a,b, asc)
	{
		a = a.toLowerCase();
		b = b.toLowerCase();
		if (a>b) {
			result = 1;
		} else if (a==b) {
			result = 0;
		} else if (a<b) {
			result = -1;
		}
		if (!asc) {
			result = result*-1;
		}
		return result;
	},
	/**
	 * Compare two strings with each other (this compare is case sensitive)
	 * @param string First unknown
	 * @param string b Second unknown
	 * @param asc Ascending or descending order?
	 * @return boolean True if a > b and asc, fals otherwise
	 */
	stringCaseCompare : function(a,b, asc)
	{
		if (a>b) {
			result = 1;
		} else if (a==b) {
			result = 0;
		} else if (a<b) {
			result = -1;
		}
		if (!asc) {
			result = result*-1;
		}
		return result;
	},
	/**
	 * Compare two datatypes of type with each other
	 * @param string Datatype. This parameter will get "Compare" concatenated to it and a function with that name
	 * will be searched for. If this exists, the result of that function will get returned
	 * @param integer a First datatype
	 * @param integer b Second datatype
	 * @param @optional asc Ascending or descending order?
	 * @return boolean Result of the comparer for the datatype
	 */
	compare : function (type, a, b, asc)
	{
		// no asc defined? Then we sort ascending
		if (typeof asc == "undefined")
		{
			asc = true;
		}
		// No function exists for this datatype. Try the default compare
		if (typeof this[type+"Compare"] != "function")
		{
			return this.defaultCompare(a,b,asc);
		}
		// Aha, found a comparer for this datatype, do magic plxor
		else
		{
			return this[type+"Compare"](a,b,asc);
		}
	},
	/**
	 * Check if a value is empty
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if empty, false otherwise
	 */
	isEmpty : function (v)
	{
		if (!v)
		{
			return true;
		}
		if (typeof v == "object") return v.size() < 1;
		return ((v === null) || v.replace(/^\s\s*/, '').replace(/\s\s*$/, '').length === 0);
	},
	/**
	 * Check if a value is a number : 1, 0, 0.1, 0.00001, -0.01, -200
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if v is a number, false otherwise
	 */
	isNumber : function (v)	
	{
		v=v.replace(',','.');
		return ( !isNaN(v) && !(/^\s+$/.test(v)) );
	},
	isXdigitNumber : function (v, digits)	
	{
		var exp = new RegExp('^\\d{'+digits+'}$'); 
		return (exp.test(v));
	},
	/**
	 * Check if a value is an integer, example : 1,2,3,10,-1,0
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if the value is an integer, false otherwise
	 */
	isInteger : function (v)
	{
		return (/^(\+|-)?\d+$/.test(v) && v >= -1*Math.pow(2,31) &&  v < Math.pow(2,31));
	},
	/**
	 * Check if a value is a phone number : 0609234098, +31 (6) 10-20-30
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if empty, false otherwise
	 */
	isPhoneNumber : function (v)
	{
		return (/^\+?[0-9\s-()]+$/.test(v));
	},
	/**
	 * Needs to be a number of 8 digits long
	 */
	isKVK : function (v)
	{
		return (/^\d{8}$/.test(v));
	},
	/**
	 * 4 characters - bank code (only letters)
	 * 2 characters - ISO 3166-1 alpha-2 country code (only letters)
	 * 2 characters - location code (letters and digits) (if the second character is '1', then it denotes a passive participant in the SWIFT network)
	 * 3 characters - branch code, optional ('XXX' for primary office) (letters and digits)
	 */
	isBIC : function (v)
	{
		return (/^\w{6}(\d|\w){2}((\d|\w){3})?$/.test(v));
	},
	/**
	 * The string either starts with a P/p for a postbank number or either 9 (betaalrekening) or 10 (overige) characters long
	 * The number must be bigger than 0
	 * Is the number 9 or 10 characters long : the "elfproef"
	 */
	isDutchBankNumber : function (v)
	{
		// postbanknumber
		if (v.length <= 8)
		{
			return /^(P|p)\d{0,7}$/.test(v);
		}
		// regular number
		else
		{
			if (v.length <9 || v.length >10 || !this.isDigitsOnly(v))
			{
				return false;
			}
			else
			{
				return (this.elevenTest(v));
			}
		}

	},
	/**
	 * The string either starts with a PL/pl for a polish number or either DE/de for a german number
	 * Polish has 26 numbers after the country identifier
	 * German has 20 numbers after the country identifier
	 */
	isForeignBankNumber : function (v)
	{
		if ( /^(PL|pl).*$/.test(v) ) //Polish
		{
			if ( /^(PL|pl)\d{26}$/.test(v) )
			{
				return true;
			}
		}

		if (/^(DE|de).*$/.test(v)) //German
		{
			if ( /^(DE|de)\d{20}$/.test(v) )
			{
				return true;
			}
		}
		return false;
	},
	/**
	 * Starts with NL
	 * 9 numbers to the "elfproef"
	 * B
	 * 2 numbers
	 */
	isBTW : function (v)
	{
		return (/^NL\d{9}B\d{2}$/.test(v) && this.elevenTest2(v.substring(2,11)));
	},
	/**
	 * eleventested string of 9 digits
	 */
	isBSN : function (v)
	{
		return (/^\d{9}$/.test(v) && this.elevenTest2(v));
	},
	/**
	 * Does the so called "elfproef"
	 */
	elevenTest : function(v)
	{
		var length = v.length;
		var total = 0;
		for (var i = 0; i < v.length; i++)
		{
			total += parseInt(v[i],10)*length;
			length--;
		}
		return ((total !== 0) && (total % 11 ===0));
	},
	/**
	 * Does the so called "elfproef"
	 */
	elevenTest2 : function(v)
	{
		var length = v.length;
		var total = 0;
		for (var i = 0; i < v.length; i++)
		{
			if (i == v.length-1)
			{
				total -= parseInt(v[i],10)*length;
			}
			else
			{
				total += parseInt(v[i],10)*length;
			}
			length--;
		}
		return ((total !== 0) && (total % 11 ===0));
	},
	/** 
	 * To validate the checksum:
	 * 1. Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid.
	 * 2. Move the four initial characters to the end of the string.
	 * 3. Replace each letter in the string with two digits, thereby expanding the string, where A=10, B=11, ..., Z=35.
	 * 4. Interpret the string as a decimal integer and compute the remainder of that number on division by 97.
	 */
	isIBAN : function (v)
	{
		var checkStr = v.substring(4)+v.substring(0,4);
		var converted = "";
		for (var i =0; i < checkStr.length; i++)
		{
			var charCode = checkStr.charCodeAt(i);
			if (charCode >= 48 && charCode <= 59)
			{
				converted = converted+checkStr[i];
			}
			else if (charCode >= 65 && charCode <= 90)
			{
				converted = converted+(charCode-55);
			}
		}
		return (this.moduloBig(converted,97) === 1);
	},
	/**
	 * Calculates the modulo of a very big number
	 * @param string big Big number represented by a string
	 * @param int modulo The modulo
	 */
	moduloBig : function (big, modulo)
	{
		var str = big;
		var remainder = modulo;
		do
		{
			var firstPart = str.substring(0,8);
			var lastPart = str.substring(8);
			str = ""+(parseInt(firstPart,10) % modulo)+lastPart;
			if (str.length < 8)
			{
				remainder = parseInt(str,10)%modulo;
			}

		} while (remainder >= modulo);
		return remainder;
	},
	/**
	 * Check if a value consists of digits only
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if value consists of digits only, false otherwise
	 */
	isDigitsOnly : function (v)
	{
		return !(/[^\d]/.test(v));
	},
	/**
	 * Check if a value consists of letters only
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if value consists of letters only, false otherwise
	 */
	isAlpha : function (v)
	{
		return (/^[a-zA-Z]+$/.test(v));
	},
	/**
	 * Check if a value consists of letters and digits
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if value consists of letters and digits, false otherwise
	 */
	isAlphaNummeric : function (v)
	{
		return !(/\W/.test(v));
	},
	/**
	 * Check if a value is a legitimate email
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if value is a legit email, false otherwise
	 */
	isEmail : function (v)
	{
		return (/[\w\-]{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(v));
	},
	/**
	 * Check if a value is a legit URL
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if value is a legit URL, false otherwise
	 */
	isURL : function (v)
	{
		return (/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i.test(v));
	},
	/**
	 * Check if a value is containing a currency in dollar format
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if value is a currency value in dollar format, false otherwise
	 */
	isDollar : function (v)
	{
		return (/^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/.test(v));
	},
	/**
	 * Check if a value is containing a currency in euro format 
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if value is a currency in euro format, false otherwise
	 */
	isEuro : function (v)
	{
		return (/^\$?\-?([1-9]{1}[0-9]{0,2}(\.[0-9]{3})*(\,[0-9]{0,2})?|[1-9]{1}\d*(\,[0-9]{0,2})?|0(\,[0-9]{0,2})?|(\,[0-9]{1,2})?)$/.test(v));
	},
	/**
	 * Check if a value is containing a currency in given localization
	 *
	 * @param [object|string] v Value to be tested
	 * @return boolean True if value is a valid currency , false otherwise
	 */
	isCurrency : function (v)
	{
		locale = Akyla.preferences.localization.currency;
		if (typeof this.i18n.currency[locale] == "undefined")
		{
			locale = "en_US";
		}
		var tester = new RegExp(this.i18n.currency[locale],"g");
		return v.match(tester);
	},
	/**
	 * i18n data
	 */
	i18n : 
	{
		date : 
		{
			"nl_NL" : 
			{
				format : "DMY" 
			},
			"en_US" : 
			{
				format : "YMD"
			},
			"ch_ZN" : 
			{
				format : "YMD"
			}
		},
		currency : 
		{
			"nl_NL" : "^\\$?\\-?([1-9]{1}[0-9]{0,2}(\\.[0-9]{3})*(\\,[0-9]{0,2})?|[1-9]{1}\\d*(\\,[0-9]{0,2})?|0(\\,[0-9]{0,2})?|(\\,[0-9]{1,2})?)$",
			"en_US" : "^\\$?\\-?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}\\d*(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$"
		}
	},
	/**
	 * Check if a value is a valid date
	 *
	 * @param [object|string] v Value to be tested
	 * @param string Format of the date, example : DMY, YMD
	 * @return boolean True if value is a valid date, false otherwise
	 */
	isValidDate : function(v, format) 
	{
		if (v.replace(/^\s\s*/, '').replace(/\s\s*$/, '').length === 0)
			return true;
		if (format === null) { format = "MDY"; }
		format = format.toUpperCase();
		if (format.length != 3) { format = "MDY"; }
		if ( (format.indexOf("M") == -1) || (format.indexOf("D") == -1) || (format.indexOf("Y") == -1) ) { format = "MDY"; }
		var reg1, reg2;
		var dd, mm, yy, dt;
		if (format.substring(0, 1) == "Y") { // If the year is first
			reg1 = /^\d{2}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
			reg2 = /^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
		} else if (format.substring(1, 2) == "Y") { // If the year is second
			reg1 = /^\d{1,2}(\-|\/|\.)\d{2}\1\d{1,2}$/;
			reg2 = /^\d{1,2}(\-|\/|\.)\d{4}\1\d{1,2}$/;
		} else { // The year must be third
			reg1 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{2}$/;
			reg2 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/;
		}
		// If it doesn"t conform to the right format (with either a 2 digit year or 4 digit year), fail
		if ( (reg1.test(v) === false) && (reg2.test(v) === false) ) { return false; }
		var parts = v.split(RegExp.$1); // Split into 3 parts based on what the divider was
		// Check to see if the 3 parts end up making a valid date
		if (format.substring(0, 1) == "M") 
			mm = parts[0]; 
		else if (format.substring(1, 2) == "M") 
			mm = parts[1]; 
		else 
			mm = parts[2]; 

		if (format.substring(0, 1) == "D") 
			dd = parts[0]; 
		else if (format.substring(1, 2) == "D") 
			dd = parts[1]; 
		else 
			dd = parts[2]; 

		if (format.substring(0, 1) == "Y") 
			yy = parts[0]; 
		else if (format.substring(1, 2) == "Y") 
			yy = parts[1]; 
		else 
			yy = parts[2]; 

		if (parseFloat(yy) <= 50) 
			yy = (parseFloat(yy) + 2000).toString();
		if (parseFloat(yy) <= 99) 
			yy = (parseFloat(yy) + 1900).toString();
		dt = new Date(parseFloat(yy), parseFloat(mm)-1, parseFloat(dd), 0, 0, 0, 0);
		if (parseFloat(dd) != dt.getDate()) 
			return false;
		if (parseFloat(mm)-1 != dt.getMonth()) 
			return false; 
		return true;
	},
	getDate : function(v) 
	{
		//if (format == null) { format = "MDY"; }
		var format = this.i18n.date[Akyla.preferences.localization.date]["format"];
		var reg1, reg2;
		var mm, dd, yy, dt;
		format = format.toUpperCase();
		if (format.length != 3) { format = "MDY"; }
		if ( (format.indexOf("M") == -1) || (format.indexOf("D") == -1) || (format.indexOf("Y") == -1) ) { format = "MDY"; }
		if (format.substring(0, 1) == "Y") { // If the year is first
			reg1 = /^\d{2}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
			reg2 = /^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
		} else if (format.substring(1, 2) == "Y") { // If the year is second
			reg1 = /^\d{1,2}(\-|\/|\.)\d{2}\1\d{1,2}$/;
			reg2 = /^\d{1,2}(\-|\/|\.)\d{4}\1\d{1,2}$/;
		} else { // The year must be third
			reg1 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{2}$/;
			reg2 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/;
		}
		// If it doesn"t conform to the right format (with either a 2 digit year or 4 digit year), fail
		if ( (reg1.test(v) === false) && (reg2.test(v) === false) ) { return false; }
		var parts = v.split(RegExp.$1); // Split into 3 parts based on what the divider was
		// Check to see if the 3 parts end up making a valid date
		if (format.substring(0, 1) == "M") 
			mm = parts[0]; 
		else if (format.substring(1, 2) == "M") 
			mm = parts[1]; 
		else 
			mm = parts[2]; 

		if (format.substring(0, 1) == "D") 
			dd = parts[0]; 
		else if (format.substring(1, 2) == "D") 
			dd = parts[1]; 
		else 
			dd = parts[2]; 

		if (format.substring(0, 1) == "Y") 
			yy = parts[0]; 
		else if (format.substring(1, 2) == "Y") 
			yy = parts[1]; 
		else 
			yy = parts[2]; 

		dt = new Date(parseFloat(yy), parseFloat(mm)-1, parseFloat(dd), 0, 0, 0, 0);
		return dt;
	},
	isValidDateI18n : function(v) 
	{
		if (v.replace(/^\s\s*/, '').replace(/\s\s*$/, '').length === 0)
			return true;
		//if (format == null) { format = "MDY"; }
		var format = this.i18n.date[Akyla.preferences.localization.date]["format"];
		format = format.toUpperCase();
		var reg1, reg2;
		var mm, dd, yy, dt;
		if (format.length != 3) { format = "MDY"; }
		if ( (format.indexOf("M") == -1) || (format.indexOf("D") == -1) || (format.indexOf("Y") == -1) ) { format = "MDY"; }
		if (format.substring(0, 1) == "Y") { // If the year is first
			reg1 = /^\d{2}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
			reg2 = /^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
		} else if (format.substring(1, 2) == "Y") { // If the year is second
			reg1 = /^\d{1,2}(\-|\/|\.)\d{2}\1\d{1,2}$/;
			reg2 = /^\d{1,2}(\-|\/|\.)\d{4}\1\d{1,2}$/;
		} else { // The year must be third
			reg1 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{2}$/;
			reg2 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/;
		}
		// If it doesn"t conform to the right format (with either a 2 digit year or 4 digit year), fail
		if ( (reg1.test(v) === false) && (reg2.test(v) === false) ) { return false; }
		var parts = v.split(RegExp.$1); // Split into 3 parts based on what the divider was
		// Check to see if the 3 parts end up making a valid date
		if (format.substring(0, 1) == "M") 
			mm = parts[0]; 
		else if (format.substring(1, 2) == "M") 
			mm = parts[1]; 
		else
			mm = parts[2]; 

		if (format.substring(0, 1) == "D") 
			dd = parts[0]; 
		else if (format.substring(1, 2) == "D") 
			dd = parts[1]; 
		else 
			dd = parts[2]; 

		if (format.substring(0, 1) == "Y") 
			yy = parts[0]; 
		else if (format.substring(1, 2) == "Y") 
			yy = parts[1]; 
		else 
			yy = parts[2]; 
		if (typeof(this.preferences.minValidYear) != "undefined" && this.preferences.minValidYear !== null)
		{
			if (parseFloat(yy) < this.preferences.minValidYear)
			{
				return false;
			}
		}
		if (typeof(this.preferences.maxValidYear) != "undefined" && this.preferences.maxValidYear !== null)
		{
			if (parseFloat(yy) > this.preferences.maxValidYear)
			{
				return false;
			}
		}
		dt = new Date(parseFloat(yy), parseFloat(mm)-1, parseFloat(dd), 0, 0, 0, 0);
		if (parseFloat(dd) != dt.getDate()) 
			return false;
		if (parseFloat(mm)-1 != dt.getMonth()) 
			return false; 
		return true;
	},
	isValidDateI18nFuture : function(v) 
	{
		if (v.replace(/^\s\s*/, '').replace(/\s\s*$/, '').length === 0)
			return true;
		//if (format == null) { format = "MDY"; }
		var format = this.i18n.date[Akyla.preferences.localization.date]["format"];
		format = format.toUpperCase();
		var reg1, reg2;
		var mm, dd, yy, dt;
		if (format.length != 3) { format = "MDY"; }
		if ( (format.indexOf("M") == -1) || (format.indexOf("D") == -1) || (format.indexOf("Y") == -1) ) { format = "MDY"; }
		if (format.substring(0, 1) == "Y") { // If the year is first
			reg1 = /^\d{2}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
			reg2 = /^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
		} else if (format.substring(1, 2) == "Y") { // If the year is second
			reg1 = /^\d{1,2}(\-|\/|\.)\d{2}\1\d{1,2}$/;
			reg2 = /^\d{1,2}(\-|\/|\.)\d{4}\1\d{1,2}$/;
		} else { // The year must be third
			reg1 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{2}$/;
			reg2 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/;
		}
		// If it doesn"t conform to the right format (with either a 2 digit year or 4 digit year), fail
		if ( (reg1.test(v) === false) && (reg2.test(v) === false) ) { return false; }
		var parts = v.split(RegExp.$1); // Split into 3 parts based on what the divider was
		// Check to see if the 3 parts end up making a valid date
		if (format.substring(0, 1) == "M") 
			mm = parts[0]; 
		else if (format.substring(1, 2) == "M") 
			mm = parts[1]; 
		else 
			mm = parts[2]; 

		if (format.substring(0, 1) == "D") 
			dd = parts[0]; 
		else if (format.substring(1, 2) == "D") 
			dd = parts[1]; 
		else 
			dd = parts[2]; 

		if (format.substring(0, 1) == "Y") 
			yy = parts[0]; 
		else if (format.substring(1, 2) == "Y") 
			yy = parts[1]; 
		else 
			yy = parts[2]; 

		if (typeof(this.preferences.minValidYear) != "undefined" && this.preferences.minValidYear !== null)
		{
			if (parseFloat(yy) < this.preferences.minValidYear)
			{
				return false;
			}
		}
		if (typeof(this.preferences.maxValidYear) != "undefined" && this.preferences.maxValidYear !== null)
		{
			if (parseFloat(yy) > this.preferences.maxValidYear)
			{
				return false;
			}
		}
		dt = new Date(parseFloat(yy), parseFloat(mm)-1, parseFloat(dd), 0, 0, 0, 0);
		if (parseFloat(dd) != dt.getDate()) 
			return false;
		if (parseFloat(mm)-1 != dt.getMonth()) 
			return false; 
		var today = new Date();
		if (dt > today)
		{
			return true;
		}
		else
		{
			return false;
		}
	},
	/**
	 * Will produce a localized date example
	 */
	dateExample : function ()
	{
		var examples = {
			"nl_NL" : "17-03-2009",
			"en_US" : "2009-03-17"
		};
		var locale = Akyla.preferences.localization.date;
		if (!examples[locale])
		{
			locale = "en_US";
		}
		return examples[locale];
	},
	/**
	 * Will produce a localizaed currency example
	 */
	currencyExample : function ()
	{
		var examples = {
			"nl_NL" : "1.000,00",
			"en_US" : "1,000.00"
		};
		var locale = Akyla.preferences.localization.currency;
		if (typeof examples[locale] == "undefined")
		{
			locale = "en_US";
		}
		return examples[locale];
	}

});


/**
*
*  Javascript sprintf
*  http://www.webtoolkit.info/
*
*
**/

sprintfWrapper = {

	init : function () {

		if (typeof arguments == "undefined") { return null; }
		if (arguments.length < 1) { return null; }
		if (typeof arguments[0] != "string") { return null; }
		if (typeof RegExp == "undefined") { return null; }

		var string = arguments[0];
		var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g);
		var matches = new Array();
		var strings = new Array();
		var convCount = 0;
		var stringPosStart = 0;
		var stringPosEnd = 0;
		var matchPosEnd = 0;
		var newString = '';
		var match = null;

		while (match = exp.exec(string)) {
			if (match[9]) { convCount += 1; }

			stringPosStart = matchPosEnd;
			stringPosEnd = exp.lastIndex - match[0].length;
			strings[strings.length] = string.substring(stringPosStart, stringPosEnd);

			matchPosEnd = exp.lastIndex;
			matches[matches.length] = {
				match: match[0],
				left: match[3] ? true : false,
				sign: match[4] || '',
				pad: match[5] || ' ',
				min: match[6] || 0,
				precision: match[8],
				code: match[9] || '%',
				negative: parseInt(arguments[convCount]) < 0 ? true : false,
				argument: String(arguments[convCount])
			};
		}
		strings[strings.length] = string.substring(matchPosEnd);

		if (matches.length == 0) { return string; }
		if ((arguments.length - 1) < convCount) { return null; }

		var code = null;
		var match = null;
		var i = null;

		for (i=0; i<matches.length; i++) {

			if (matches[i].code == '%') { substitution = '%' }
			else if (matches[i].code == 'b') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument,10)).toString(2));
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'c') {
				matches[i].argument = String(String.fromCharCode(parseInt(Math.abs(parseInt(matches[i].argument,10)),10)));
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'd') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument,10)));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'f') {
				matches[i].argument = String(Math.abs(parseFloat(matches[i].argument)).toFixed(matches[i].precision ? matches[i].precision : 6));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'o') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument,10)).toString(8));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 's') {
				matches[i].argument = matches[i].argument.substring(0, matches[i].precision ? matches[i].precision : matches[i].argument.length)
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'x') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument,10)).toString(16));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'X') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument,10)).toString(16));
				substitution = sprintfWrapper.convert(matches[i]).toUpperCase();
			}
			else {
				substitution = matches[i].match;
			}

			newString += strings[i];
			newString += substitution;

		}
		newString += strings[i];

		return newString;

	},

	convert : function(match, nosign){
		if (nosign) {
			match.sign = '';
		} else {
			match.sign = match.negative ? '-' : match.sign;
		}
		var l = match.min - match.argument.length + 1 - match.sign.length;
		var pad = new Array(l < 0 ? 0 : l).join(match.pad);
		if (!match.left) {
			if (match.pad == "0" || nosign) {
				return match.sign + pad + match.argument;
			} else {
				return pad + match.sign + match.argument;
			}
		} else {
			if (match.pad == "0" || nosign) {
				return match.sign + match.argument + pad.replace(/0/g, ' ');
			} else {
				return match.sign + match.argument + pad;
			}
		}
	}
}

sprintf = sprintfWrapper.init;

Akyla.Tester = new Akyla_Prototype_Tester();

