// The Rounder class internally converts all currency into cents
// eg:  $123 -> 12300 cents, $123.45 -> 12345 cents, $0.05 -> 5 cents
// this is done to get around float point anomalies when dealing with 
// precise money values. In fact never use floating point with currency.
// Values returned from this class are always in two decimal place values
// as in monetary values.
  
function Rounder(value)
{ 
  this.totalCents = 0;
  this.dollars    = 0;
  this.cents      = 0;
  this.decPrecision    = 2;
  this.minDecPrecision = 2;//0;
   
  this.set          = rounder_set;
  
  if ((value != "") && (typeof(value) != "undefined")) { this.set( value); }
    
  this.getDollars    = rounder_getDollars;
  this.getCents      = rounder_getCents; 
  this.getPrecision  = rounder_getPrecision;

  this.toNearest     = rounder_toNearest;  
  this.upToNearest   = rounder_upToNearest;
  this.downToNearest = rounder_downToNearest;
  
  this.truncatePrecision2 = rounder_truncatePrecision2;
}

// example of code usage:
//
// var oRound = new Rounder();
// 
// var value = .....some arithmetic calculation.
// // now round value down to nearest 5 cents.
// var roundedValue = oRound.set(value).downToNearest(0.05);

function rounder_set( value)
{
  // if decimal point supplied multiply by 100 to convert to cents
  // otherwise assume amount is supplied as converted to cents.
  
  // eg:  123 -> 12300 cents, 123.45 -> 12345 cents, 0.05 -> 5 cents
  
  this.totalCents = 0;
  this.dollars    = 0;
  this.cents      = 0;
  this.decPrecision    = 2;
    
  if (typeof(value) != "undefined") {
    	  
    	var numberString;
    	
        if (typeof(value) == "number") {
            numberString = new String(value);
        }
        else {
            numberString = value;
        }
        
        var matchArray  = null;
        var DecimalPat  = /-?[0-9]+/g;   // match all numeric combinations
        
        // split array into numberic and decimal
               
        matchArray = numberString.match(DecimalPat); 
        
        if (matchArray == null) return this;
        
        if ((typeof(matchArray[0]) == "undefined") && (typeof(matchArray[1]) == "undefined")) return null;
         
        if (typeof(matchArray[0]) != "undefined") { this.dollars = parseInt(matchArray[0], 10);}
        
        this.decPrecision = this.minDecPrecision;
        
        if (typeof(matchArray[1]) != "undefined") {
                          
             // accomodate for numbers 12.5, 12.50 and 12.5022222
             // all precision is always brought back to 2.
             
             if (matchArray[1].length < this.minDecPrecision) {
                 this.cents   = parseInt((matchArray[1] + "0"), 10);
             }
             else {
                 if (matchArray[1].length > this.minDecPrecision) {
                 
                     var tmp = parseInt(matchArray[1], 10);
                     tmp = tmp/Math.pow(10, (matchArray[1].length-this.minDecPrecision))
                     this.cents = Math.round(tmp);
                 }
                 else {
                     this.cents = parseInt(matchArray[1], 10);
                 }
             }
             
             if (matchArray[0] == 0 || matchArray[0] == "") {
                 this.totalCents   = parseInt(this.cents, 10);
             }
             else {
                 this.totalCents   = (this.dollars*100) + this.cents;
             }
        }
        else {
             this.totalCents    = (this.dollars*100);
        }            
      
		     
      if ((typeof(value) == "object") && (value instanceof Rounder)) {
          this.totalCents = value.totalCents;
          this.dollars    = value.getDollars();
          this.cents      = value.getCents();
          this.decPrecision  = value.decPrecision;
      }
      
      if (isNaN(this.dollars) || this.dollars < 0 ||
          isNaN(this.cents) || this.cents < 0) {
      
          this.totalCents = 0;
          this.dollars = 0;
          this.cents   = 0; 
      }
      
   //   return this;
  }  
  
  return this;
}

function rounder_getDollars()
{
   return this.dollars;
}

function rounder_getCents()
{
   return this.cents;
}

function rounder_getPrecision()
{
   return this.decPrecision;
}

function rounder_toNearest( roundingFactor)
{
  var round = 0;
  
  if ((roundingFactor != "") && (roundingFactor != null) && (typeof(roundingFactor) != "undefined")) {
	  if (typeof(roundingFactor) == "string") {
	      //round    = parseInt (roundingFactor); 
	      round    = parseFloat (roundingFactor); 
	      if (isNaN (round)) return 0;
      }
	  
	  if (typeof(roundingFactor) == "number") {
	      round = roundingFactor; 
	  }
  }
  
  round = round * Math.pow(10, this.decPrecision);
      
  var mod   = this.totalCents % round;
  
  if (mod == 0) return this.totalCents/Math.pow(10, this.decPrecision);
  
  var lower = this.totalCents - mod;
  var upper = lower + round;
  
  return (Math.abs(this.totalCents-lower) > Math.abs(this.totalCents-upper)) ? upper/Math.pow(10, this.decPrecision) : lower/Math.pow(10, this.decPrecision);
}

function rounder_upToNearest( roundingFactor)
{
  var round = 0;
  
  if ((roundingFactor != "") && (roundingFactor != null) && (typeof(roundingFactor) != "undefined")) {
	  if (typeof(roundingFactor) == "string") {
	      //round    = parseInt (roundingFactor); 
	      round    = parseFloat (roundingFactor); 
	      if (isNaN (round)) return 0;
      }
	  
	  if (typeof(roundingFactor) == "number") {
	      round = roundingFactor; 
	  }
  }
  
  round = round * Math.pow(10, this.decPrecision);
      
  var mod   = this.totalCents % round;
  
  if (mod == 0) return this.totalCents/Math.pow(10, this.decPrecision);
  
  var lower = this.totalCents - mod;
  var upper = lower + round;
 
  return upper/Math.pow(10, this.decPrecision);
}

function rounder_downToNearest( roundingFactor)
{
  var round = 0;
  
  if ((roundingFactor != "") && (roundingFactor != null) && (typeof(roundingFactor) != "undefined")) {
	  if (typeof(roundingFactor) == "string") {
	      //round    = parseInt (roundingFactor); 
	      round    = parseFloat (roundingFactor); 
	      if (isNaN (round)) return 0;
      }
	  
	  if (typeof(roundingFactor) == "number") {
	      round = roundingFactor; 
	  }
  }
  
  round = round * Math.pow(10, this.decPrecision);
    
  var mod   = this.totalCents % round;
  
  if (mod == 0) return this.totalCents/Math.pow(10, this.decPrecision);
  
  var lower = this.totalCents - mod;
  
  return lower/Math.pow(10, this.decPrecision);
}

// cuts off all digits after two decimal palces, doesn't round

function rounder_truncatePrecision2(obj)
{
  return (parseInt(" " +(obj*100)) / 100);
}