/**
 * jquery.numberformatter - Formatting/Parsing Numbers in jQuery
 * Written by Michael Abernethy (mike@abernethysoft.com)
 *
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Date: 2/6/08
 *
 * @author Michael Abernethy
 * @version 1.1.2
 *
 * many thanks to advweb.nanasi.jp for his bug fixes
 *
 * This plugin can be used to format numbers as text and parse text as Numbers
 * Because we live in an international world, we cannot assume that everyone
 * uses "," to divide thousands, and "." as a decimal point.
 *
 * The format() function will take the text within any selector by calling
 * text() or val() on them, getting the String, and applying the specified format to it.
 * It will return the jQuery object
 *
 * The parse() function will take the text within any selector by calling text()
 * or val() on them, turning the String into a Number, and returning these
 * values in a Number array.
 * It WILL BREAK the jQuery chain, and return an Array of Numbers.
 *
 * The syntax for the formatting is:
 * 0 = Digit
 * # = Digit, zero shows as absent
 * . = Decimal separator
 * - = Negative sign
 * , = Grouping Separator
 * % = Percent (multiplies the number by 100)
 * For example, a format of "#,###.00" and text of 4500.20 will
 * display as "4.500,20" with a locale of "de", and "4,500.20" with a locale of "us"
 *
 *
 * As of now, the only acceptable locales are 
 * United States -> "us"
 * Arab Emirates -> "ae"
 * Egypt -> "eg"
 * Israel -> "il"
 * Japan -> "jp"
 * South Korea -> "kr"
 * Thailand -> "th"
 * China -> "cn"
 * Hong Kong -> "hk"
 * Taiwan -> "tw"
 * Australia -> "au"
 * Canada -> "ca"
 * Great Britain -> "gb"
 * India -> "in"
 * Germany -> "de"
 * Vietnam -> "vn"
 * Spain -> "es"
 * Denmark -> "dk"
 * Austria -> "at"
 * Greece -> "gr"
 * Brazil -> "br"
 * Czech -> "cz"
 * France  -> "fr"
 * Finland -> "fi"
 * Russia -> "ru"
 * Sweden -> "se"
 * Switzerland -> "ch"
 * 
 * TODO
 * Separate positive and negative patterns separated by a ":" (e.g. use (#,###) for accounting)
 * More options may come in the future (currency)
 **/
     
 (function(jQuery) {

     function FormatData(dec, group, neg) {
       this.dec = dec;
       this.group = group;
       this.neg = neg;
     };

     function formatCodes(locale) {

         // default values
         var dec = ".";
         var group = ",";
         var neg = "-";

         if (locale == "us" ||
             locale == "ae" ||
             locale == "eg" ||
             locale == "il" ||
             locale == "jp" ||
             locale == "sk" ||
             locale == "th" ||
             locale == "cn" ||
             locale == "hk" ||
             locale == "tw" ||
             locale == "au" ||
             locale == "ca" ||
             locale == "gb" ||
             locale == "in"
            )
         {
              dec = ".";
              group = ",";
         }

         else if (locale == "de" ||
             locale == "vn" ||
             locale == "es" ||
             locale == "dk" ||
             locale == "at" ||
             locale == "gr" ||
             locale == "br"
            )
         {
              dec = ",";
              group = ".";
         }
         else if (locale == "cz" ||
              locale == "fr" ||
             locale == "fi" ||
             locale == "ru" ||
             locale == "se"
            )
         {
              group = " ";
              dec = ",";
         }
         else if (locale == "ch")
          {
              group = "'";
              dec = ".";
          }
     
        return new FormatData(dec, group, neg);

    };

 jQuery.formatNumber = function(number, options) {
     var options = jQuery.extend({},jQuery.fn.parse.defaults, options);
     var formatData = formatCodes(options.locale.toLowerCase());

     var dec = formatData.dec;
     var group = formatData.group;
     var neg = formatData.neg;
     
     var numString = new String(number);
     numString = numString.replace(".",dec).replace("-",neg);
     return numString;
 };

 jQuery.fn.parse = function(options) {

     var options = jQuery.extend({},jQuery.fn.parse.defaults, options);

     var formatData = formatCodes(options.locale.toLowerCase());

     var dec = formatData.dec;
     var group = formatData.group;
     var neg = formatData.neg;

     var valid = "1234567890.-";

     var array = [];
     this.each(function(){

         var text = new String(jQuery(this).text());
         if (jQuery(this).is(":input"))
            text = new String(jQuery(this).val());

         // now we need to convert it into a number
         while (text.indexOf(group)>-1)
               text = text.replace(group,'');
         text = text.replace(dec,".").replace(neg,"-");
         var validText = "";
         var hasPercent = false;
         if (text.charAt(text.length-1)=="%")
             hasPercent = true;
         for (var i=0; i<text.length; i++)
         {
            if (valid.indexOf(text.charAt(i))>-1)
               validText = validText + text.charAt(i);
         }
         var number = new Number(validText);
         if (hasPercent)
         {
            number = number / 100;
            number = number.toFixed(validText.length-1);
         }
         array.push(number);
     });

     return array;
 };

 jQuery.fn.format = function(options) {

     var options = jQuery.extend({},jQuery.fn.format.defaults, options);
     
     var formatData = formatCodes(options.locale.toLowerCase());

     var dec = formatData.dec;
     var group = formatData.group;
     var neg = formatData.neg;
     
     var validFormat = "0#-,.";

     return this.each(function(){

         var text = new String(jQuery(this).text());
         if (jQuery(this).is(":input"))
            text = new String(jQuery(this).val());               

         // strip all the invalid characters at the beginning and the end
         // of the format, and we'll stick them back on at the end
         // make a special case for the negative sign "-" though, so 
         // we can have formats like -$23.32
         var prefix = "";
         var negativeInFront = false;
         for (var i=0; i<options.format.length; i++)
         {
            if (validFormat.indexOf(options.format.charAt(i))==-1)
                prefix = prefix + options.format.charAt(i);
            else if (i==0 && options.format.charAt(i)=='-')
            {
               negativeInFront = true;
               continue;
            }
            else
                break;
         }
         var suffix = "";
         for (var i=options.format.length-1; i>=0; i--)
         {
            if (validFormat.indexOf(options.format.charAt(i))==-1)
                suffix = options.format.charAt(i) + suffix;
            else
                break;
         }

         options.format = options.format.substring(prefix.length);
         options.format = options.format.substring(0, options.format.length - suffix.length);


        // now we need to convert it into a number
        while (text.indexOf(group)>-1)
               text = text.replace(group,'');
        var number = new Number(text.replace(dec,".").replace(neg,"-"));

        // special case for percentages
        if (suffix == "%")
           number = number * 100;

        var returnString = "";
        
        var decimalValue = number % 1;
        if (options.format.indexOf(".") > -1)
        {
           var decimalPortion = dec;
           var decimalFormat = options.format.substring(options.format.lastIndexOf(".")+1);
           var decimalString = new String(decimalValue.toFixed(decimalFormat.length));
           decimalString = decimalString.substring(decimalString.lastIndexOf(".")+1);
           for (var i=0; i<decimalFormat.length; i++)
           {
              if (decimalFormat.charAt(i) == '#' && decimalString.charAt(i) != '0')
              {
                 decimalPortion += decimalString.charAt(i);
                  continue;
               }
               else if (decimalFormat.charAt(i) == '#' && decimalString.charAt(i) == '0')
               {
                  var notParsed = decimalString.substring(i);
                  if (notParsed.match('[1-9]'))
                  {
                      decimalPortion += decimalString.charAt(i);
                      continue;
                  }
                  else
                  {
                      break;
                  }
              }
              else if (decimalFormat.charAt(i) == "0")
              {
                 decimalPortion += decimalString.charAt(i);
              }
           }
           returnString += decimalPortion
        }
        else
           number = Math.round(number);
        
        var ones = Math.floor(number);
        if (number < 0)
            ones = Math.ceil(number);

        var onePortion = "";
        if (ones == 0)
        {
           onePortion = "0";
        }
        else
        {
           // find how many digits are in the group
           var onesFormat = "";
           if (options.format.indexOf(".") == -1)
              onesFormat = options.format;
           else
              onesFormat = options.format.substring(0, options.format.indexOf("."));
           var oneText = new String(Math.abs(ones));
           var groupLength = 9999;
           if (onesFormat.lastIndexOf(",") != -1)
               groupLength = onesFormat.length - onesFormat.lastIndexOf(",")-1;
           var groupCount = 0;
           for (var i=oneText.length-1; i>-1; i--)
           {
             onePortion = oneText.charAt(i) + onePortion;

             groupCount++;

             if (groupCount == groupLength && i!=0)
             {
                 onePortion = group + onePortion;
                 groupCount = 0;
             }

           }
        }
        returnString = onePortion + returnString;

        // handle special case where negative is in front of the invalid
        // characters
        if (number < 0 && negativeInFront && prefix.length > 0)
        {
           prefix = neg + prefix;
        }
        else if (number < 0)
        {
           returnString = neg + returnString;
        }

        if (! options.decimalSeparatorAlwaysShown) {
            if (returnString.lastIndexOf(dec) == returnString.length - 1) {
                returnString = returnString.substring(0, returnString.length - 1);
            }
        }
        returnString = prefix + returnString + suffix;

        if (jQuery(this).is(":input"))
           jQuery(this).val(returnString);
        else
           jQuery(this).text(returnString);

     });
 };

 jQuery.fn.parse.defaults = {
      locale: "us",
      decimalSeparatorAlwaysShown: false
 };

 jQuery.fn.format.defaults = {
      format: "#,###.00",
      locale: "us",
      decimalSeparatorAlwaysShown: false
 };


 })(jQuery);
