#include <iostream>
#include <iomanip>

#include "JLang/JComparable.hh"

#include "Jeep/JParser.hh"
#include "Jeep/JMessage.hh"


namespace {

  using namespace JPP;
  
  struct __A__ :
    public JComparable<__A__>
  {
    __A__(int __value) :
      value(__value)
    {}

    bool less(const __A__& object) const
    {
      return this->value < object.value;
    }
    
    friend std::ostream& operator<<(std::ostream& out, const __A__& object)
    {
      return out << object.value;
    }

    int value;
  };
  

  struct __B__ :
    public JComparable<__B__>,
    public JComparable<__B__, int>
  {
    __B__(const int __value) :
      value(__value)
    {}

    bool less(const __B__& object) const
    {
      return this->value < object.value;
    }

    bool less(const int value) const
    {
      return this->value < value;
    }
    
    bool more(const int value) const
    {
      return this->value > value;
    }
    
    friend std::ostream& operator<<(std::ostream& out, const __B__& object)
    {
      return out << object.value;
    }

    int value;
  };
  
  /**
   * Print.
   *
   * \param  OUT     output stream
   * \param  OP      operator
   * \param  A       first  object
   * \param  B       second object
   */
#define PRINT(OUT,OP,A,B) \
  OUT << "(" << A << ") " << #OP " (" << B << ") => " << (A OP B) << std::endl;
}

/**
 * \file
 *
 * Example program to test JLANG::JComparable class.
 * \author mdejong
 */
int main(int argc, char **argv)
{
  using namespace std;
  using namespace JPP;

  int         debug;

  try {

    JParser<> zap("Example program to test comparisons of objects.");

    zap['d'] = make_field(debug)     = 3;

    zap(argc, argv);
  }
  catch(const exception &error) {
    FATAL(error.what() << endl);
  }

  
  __A__ a1(0);
  __A__ a2(1);

  PRINT(cout, ==, a1, a2);
  PRINT(cout, !=, a1, a2);
  PRINT(cout, <,  a1, a2);
  PRINT(cout, <=, a1, a2);
  PRINT(cout, >,  a1, a2);
  PRINT(cout, >=, a1, a2);

  __B__ b1(0);
  __B__ b2(1);

  PRINT(cout, ==, b1, b1);
  PRINT(cout, !=, b1, b2);
  PRINT(cout, <,  b1, b2);
  PRINT(cout, <=, b1, b2);
  PRINT(cout, >,  b1, b2);
  PRINT(cout, >=, b1, b2);

  PRINT(cout, ==, b1, 1);
  PRINT(cout, !=, b1, 1);
  PRINT(cout, <,  b1, 1);
  PRINT(cout, <=, b1, 1);
  PRINT(cout, >,  b1, 1);
  PRINT(cout, >=, b1, 1);

  ASSERT(a1 == a1);
  ASSERT(a1 != a2);
  ASSERT(a1 <  a2);
  ASSERT(a1 <= a2);
  ASSERT(! (a1 >  a2));
  ASSERT(! (a1 >= a2));

  ASSERT(b1 == b1);
  ASSERT(b1 != b2);
  ASSERT(b1 <  b2);
  ASSERT(b1 <= b2);
  ASSERT(! (b1 >  b2));
  ASSERT(! (b1 >= b2));

  ASSERT(b1 == 0);
  ASSERT(b1 != 1);
  ASSERT(b1 <  1);
  ASSERT(b1 <= 1);
  ASSERT(! (b1 >  1));
  ASSERT(! (b1 >= 1));
  
  return 0;
}