// ----------------------------------------------------------------------------
// sample_userType.cc :  example usage of format with a user-defined type
// ----------------------------------------------------------------------------

//  Copyright Samuel Krempp 2003. Use, modification, and distribution are
//  subject to the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/format for library home page

// ----------------------------------------------------------------------------


#include <iostream>
#include <iomanip>
#include "boost/format.hpp"
#include <boost/cast.hpp>

#if !(BOOST_WORKAROUND(__GNUC__, < 3) && defined(__STL_CONFIG_H) ) 
  // not for broken gcc stdlib
#include <boost/io/ios_state.hpp>

#else
// not as complete, but compatible with gcc-2.95 :

void copyfmt(ios& left, const ios& right) {
    left.fill(right.fill());
    left.flags(right.flags() );
    left.exceptions(right.exceptions());
    left.width(right.width());
    left.precision(right.precision());
}

namespace boost { namespace io {
class ios_all_saver {
    std::basic_ios<char>  ios_;
    std::ios & target_r;
public:
    ios_all_saver(std::ios& right) : ios_(0), target_r(right) {
        copyfmt(ios_, right);
    }
    ~ios_all_saver() {
        copyfmt(target_r, ios_);
    }
};

} } // N.S. boost::io


// define showpos and noshowpos : 
class ShowPos {
public:
    bool showpos_;
    ShowPos(bool v) : showpos_(v) {}
};
std::ostream& operator<<(std::ostream& os, const ShowPos& x) { 
    if(x.showpos_) 
        os.setf(ios_base:: showpos);
    else
        os.unsetf(ios_base:: showpos);
    return os; 
}
ShowPos noshowpos(false);
ShowPos showpos(true);

#endif // -end gcc-2.95 workarounds



//---------------------------------------------------------------------------//
//  *** an exemple of UDT : a Rational class ****
class Rational {
public:
  Rational(int n, unsigned int d) : n_(n), d_(d) {}
  Rational(int n, int d);    // convert denominator to unsigned
  friend std::ostream& operator<<(std::ostream&, const Rational&);
private:
  int n_;               // numerator
  unsigned int d_;      // denominator
};

Rational::Rational(int n, int d) : n_(n) 
{
  if(d < 0) { n_ = -n_; d=-d; } // make the denominator always non-negative.
    d_ = static_cast<unsigned int>(d);
}

std::ostream& operator<<(std::ostream& os, const Rational& r) {
  using namespace std;
  streamsize  n, s1, s2, s3;
  streamsize w = os.width(0); // width has to be zeroed before saving state.
//  boost::io::ios_all_saver  bia_saver (os); 
 
  boost::io::basic_oaltstringstream<char> oss;
  oss.copyfmt(os );
  oss << r.n_; 
  s1 = oss.size();
  oss << "/" << noshowpos; // a rational number needs only one sign !
  s2 = oss.size();
  oss << r.d_ ;
  s3 = oss.size();

  n = w - s3;
  if(n <= 0) {
      os.write(oss.begin(), oss.size());
  }
  else if(os.flags() & std::ios_base::internal) {
    std::streamsize n1 = w/2, n2 = w - n1,  t;
    t = (s3-s1) - n2; // is 2d part '/nnn' bigger than 1/2 w ?
    if(t > 0)  {
      n1 = w -(s3-s1); // put all paddings on first part.
      n2 = 0; // minimal width (s3-s2)
    } 
    else {
      n2 -= s2-s1; // adjust for '/',   n2 is still w/2.
    }
    os << setw(n1) << r.n_ << "/" << noshowpos << setw(n2) << r.d_;
  }
  else {
    if(! (os.flags() & std::ios_base::left)) { 
        // -> right align. (right bit is set, or no bit is set)
        os << string(boost::numeric_cast<std::string::size_type>(n), ' ');
    }
    os.write(oss.begin(), s3);
    if( os.flags() & std::ios_base::left ) {
      os << string(boost::numeric_cast<std::string::size_type>(n), ' ');
    }
  }

  return os;
}



int main(){
    using namespace std;
    using boost::format;
    using boost::io::group; 
    using boost::io::str;
    string s;

    Rational  r(16, 9);

    cout << "bonjour ! " << endl;
    // "bonjour !"

    cout << r << endl;
    // "16/9" 

    cout << showpos << r << ", " << 5 << endl;
    // "+16/9, +5"

    cout << format("%02d : [%0+9d] \n") % 1 % r ;
    // "01 : [+016 / 0009]"

    cout << format("%02d : [%_+9d] \n") % 2 % Rational(9,160);
    // "02 : [+9 / 160]"

    cout << format("%02d : [%_+9d] \n") % 3 % r;
    // "03 : [+16 / 9]"
		
    cout << format("%02d : [%_9d] \n") % 4 % Rational(8,1234);
    // "04 : [8 / 1234]"
    
    cout << format("%02d : [%_9d] \n") % 5 % Rational(1234,8);
    // "05 : [1234 / 8]"

    cout << format("%02d : [%09d] \n") % 6 % Rational(8,1234);
    // "06 : [0008 / 1234]"

    cout << format("%02d : [%0+9d] \n") % 7 % Rational(1234,8);
    // "07 : [+1234 / 008]"

    cout << format("%02d : [%0+9d] \n") % 8 % Rational(7,12345);
    // "08 : [+07 / 12345]"


    cerr << "\n\nEverything went OK, exiting. \n";
    return 0;
}
