//
//%TITLE  IDI Money class:  implementation of non-in-line functions
//  Copyright 1995, Information Disciplines, Inc., Chicago 

//  See Money.hpp for documentation and declarations
//%SPACE 3
#include 
#include "Money.hpp"
//%SPACE 3
//  The static member data are public, allowing user overrides without 
//  incurring the overhead of member functions.  This is acceptable, 
//  because any user errors will be immediately obvious, and are 
//  unlikely to affect computational integrity.
//%SPACE 3
// Initial (default) constant values for U.S. currency
// ---------------------------------------------------

//  The user-program may override these values.  To avoid inconsistencies,
//  this should be done only before any Money objects are created.

char       Money::pfx_symbol[]    = "$";
char       Money::sfx_symbol[]    = "" ;
char       Money::decimal_point   = '.';
char       Money::group_separator = ',';
char       Money::unit_name[]     = "dollar";
char       Money::cent_name[]     = "cent";
MoneyIType Money::scale           = 100;        //  Cents
//%SPACE 4
//double     Money::dummy;                                
double Money::round(const double x)            //  Static internal function
 {double dummy;                                //    to round and truncate
  return modf(x + (x<0 ? -.5 : .5),&dummy), dummy;
 }
//%EJECT
//  Output display (stream insertion) operator
//  ------------------------------------------

//  This version displays a Money object in the form:

//   -  leading minus sign, if negative
//   -  floating prefix currency symbol (if symbol_pfx = 1)
//   -  whole amount in groups of three digits separated by punctuation
//   -  decimal point
//   -  2-digit (or more when needed) decimal fraction

 ostream& operator<< (ostream& ls, MONEY rs)
 {Money absx = rs > 0 ? rs : - rs;      //  Get magnitude of argument
  double whole = absx.MoneyInt();       //  Isolate whole monetary units
  short  cents = absx.MoneyCents();     //  Isolate fractional units
  Money  remdr = absx - Money((whole * 100 + cents) / 100);

  if  (rs < 0) ls << '-';               //  Print prefix minus, if needed
  ls << Money::pfx_symbol;              //  Insert dollar sign

//  Print groups of 3 digits separated by punctuation
//  -------------------------------------------------

  const float group_divisors[6] = {1E0f, 1E3f, 1E6f, 1E9f, 1E12f, 1E15f};
  short  grpNum = (whole == 0) ? 0 : short(log10(whole) / 3);
  int    grpVal =  int(whole / group_divisors[grpNum]);

  ls << grpVal;                // Print leftmost 3-digits (no leading 0's)
  while (grpNum != 0)          // For remaining 3-digit groups
   {ls << rs.group_separator;                     // Print group separator
    whole -= grpVal * group_divisors[grpNum--];   // Compute new remainder
    grpVal  = int(whole / group_divisors[grpNum]);// Get next 3-digit value
       
    if   (grpVal < 100) ls  << '0';               // Insert embedded 0's
    if   (grpVal < 10)  ls  << '0';               //   as needed
    ls << grpVal;}                                // Print 3-digit value

//  Print cents portion
//  -------------------

  ls <<  rs.decimal_point              //  Append decimal point
     << (cents < 10 ? "0" : "")        //  Append leading 0 if needed
     <<  cents;                        //  Append cents value

//  Append any additional fractional digits
//  ---------------------------------------

  for (int i = int(Money::scale/100 -1); i&&(remdr>0); i--, remdr/=10)
       ls << (10 * remdr).MoneyCents();
  ls << Money::sfx_symbol;             //    Insert trailing currency symbol

  return ls;}                          //    Allow nested stream operations
//