// Copyright (C) 2010-2013  MarketFactory, Inc. All Rights Reserved.
#ifndef __MF_FIXFLOAT__
#define __MF_FIXFLOAT__

#include <iosfwd>
#include <stdint.h>

namespace MFAPI {

/** Fixed-point integer representation for fractional numbers.
*This class also supports a small number of special values: NMA, N/A, etc. See
*below.
*/
// Internally, we store the vlaue as an int64_t x 10^9.
// This provides 9 digits of precision, which is good enough, and strikes a good
// compromise between flexibility and the performance of a fixed representation.

class MFFloat {
 public:
  // Stream to an ostream.
  friend std::ostream& operator<<(std::ostream& output, const MFFloat& p);

  // Default constructors, constructs an N/A value.
  explicit MFFloat() { *this = NA; }

  // Constructor from its native representation.
  explicit MFFloat(int64_t value) : _value(value) {}

  // Constructor from a float and a desired precision for rounding. You should
  // prefer to use the integ/frac constructors instead of this.
  explicit MFFloat(double dvalue, int precision);

  // Constructors from a string representation. No loss of precision here, but
  // this is obviously slower than using an integer representation.
  explicit MFFloat(const char* val);
  explicit MFFloat(const std::string& val);

  // Copy constructors.
  MFFloat(const MFFloat& o) : _value(o._value) {}
  MFFloat& operator=(const MFFloat& o) {
    _value = o._value;
    return *this;
  }

  // Conversions to other numerical types.
  int64_t toInt() const { return _value; }
  double toDouble() const;

#if defined(__GXX_EXPERIMENTAL_CXX0X__) && \
    (__GNUC__ * 100 + __GNUC_MINOR__) > 404
  // C++0x allows explicit keyword on cast operators.
  explicit operator int64_t() const { return _value; }
  explicit operator double() const;
#endif

  // Conversion to string.
  std::string toString() const;

  // (Writes to 'buf', returns the nb. of characters written.)
  size_t toString(char* buf) const;

  //  Comparison operators
  bool operator==(const MFFloat& o) const { return _value == o._value; }

  bool operator!=(const MFFloat& o) const { return _value != o._value; }

  bool operator<=(const MFFloat& o) const { return _value <= o._value; }

  bool operator>=(const MFFloat& o) const { return _value >= o._value; }

  bool operator<(const MFFloat& o) const { return _value < o._value; }

  bool operator>(const MFFloat& o) const { return _value > o._value; }

  int compare(const MFFloat& o) {
    if (_value > o._value) {
      return 1;
    } else if (_value < o._value) {
      return -1;
    }
    return 0;
  }

  // Mathematical operations.
  MFFloat operator+(const MFFloat& o) const {
    MFFloat r = *this;
    r._value += o._value;
    return r;
  }
  MFFloat operator-(const MFFloat& o) const {
    MFFloat r = *this;
    r._value -= o._value;
    return r;
  }
  MFFloat& operator+=(const MFFloat& o) {
    _value += o._value;
    return *this;
  }
  MFFloat& operator-=(const MFFloat& o) {
    _value -= o._value;
    return *this;
  }

  // (Multiplication with integer value.)
  MFFloat operator*(int32_t o) const {
    MFFloat r = *this;
    r._value *= o;
    return r;
  }
  MFFloat& operator*=(int32_t o) {
    _value *= o;
    return *this;
  }
  MFFloat operator*(int64_t o) const {
    MFFloat r = *this;
    r._value *= o;
    return r;
  }
  MFFloat& operator*=(int64_t o) {
    _value *= o;
    return *this;
  }

  /**
   * Check if MFFloat object has valid value.
   */
  static bool isValid(const MFFloat& o) {
    if (o == MFFloat::NMA || o == MFFloat::NDA || o == MFFloat::NA) {
      return false;
    } else {
      return true;
    }
  }

 public:
  // Special values.

  // Special value: "No Market Activity". This is used in entries for which we
  // are
  // provided an explicit value but the value is known to be empty. For example,
  // an exchange may be always publishing a single local price, but this local
  // price may not exist at the moment.
  static const MFFloat NMA;

  // Special value: "No Data Available". This is used to fill some market data
  // messages where the exchange or connection is known to be down. This
  // provides
  // an explicit history of data availability.
  static const MFFloat NDA;

  // Special value: "Not Applicable". This is used to initialize slots where
  // the values are irrelevant given the context.
  static const MFFloat NA;

  // A constant for a value of 0.
  static const MFFloat ZERO;

 private:
  int64_t _value;
};

// Typedefs for commonly-used classes.
typedef MFFloat Price;
typedef MFFloat Amount;

// Streaming operator.
std::ostream& operator<<(std::ostream& os, const MFFloat& f);
}
#endif
// InclKwds: MFFloat Price Amount
