#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <ratio.h>
#include <talk.h>

/******************************************/
/* C++ Rational arithmetic implementation */
/******************************************/

/* Talk entry points */

static ILT_DEFINTERN(ilt_add, "+",2)
static ILT_DEFINTERN(ilt_sub, "-",2)
static ILT_DEFINTERN(ilt_mul, "*",2)
static ILT_DEFINTERN(ilt_div, "/",2)
static ILT_DEFINTERN(ilt_lt, "<",2)
static ILT_DEFINTERN(ilt_gt, ">",2)
static ILT_DEFINTERN(ilt_le, "<=",2)
static ILT_DEFINTERN(ilt_ge, ">=",2)
static ILT_DEFINTERN(ilt_eq, "=",2)
static ILT_DEFINTERN(ilt_string, "string",1)
static ILT_DEFINTERN(ilt_float, "float",1)
extern "C" int IltInit(int argc, char** argv, char** envp);

/* C++ Mechanics */

/* Memory management note: The current implementation relies on Talk
   GC to recycle Talk rationals (value of _r); therefore rationals
   should not be statically allocated (or their _r should be
   registered, and the entry point for that should be provided).  We
   could have done without Talk GC, overloading ratio's delete; to do
   that, we should make sure that two ratio will never refer to the
   same Talk rational, and for that effect, change the copy
   constructor. */

void ratio_init(int argc, char** argv, char** envp)
{
  int status = IltInit(argc, argv, envp);
  if (status)
    exit(status);
}

ratio::ratio() { _r = ILT_CLONG2TINT(0L); }
ratio::ratio(long l) { _r = ILT_CLONG2TINT(l); }
ratio::ratio(int l)  { _r = ILT_CLONG2TINT(l); } // because 0L
ratio::ratio(ratio r1, ratio r2) { _r = ilt_div(r1._r,r2._r); }
ratio::ratio(const ratio &r2) { _r = r2._r; }
ratio::operator double() 
  { return *(double*)(ilt_float(this->_r)); }
ratio::operator char*() 
  { return (char*)(ilt_string(this->_r)); }
int ratio::operator<(ratio r2) { return (int)ilt_lt(this->_r,r2._r); }
int ratio::operator>(ratio r2) { return (int)ilt_gt(this->_r,r2._r); }
int ratio::operator<=(ratio r2) { return (int)ilt_le(this->_r,r2._r); }
int ratio::operator>=(ratio r2) { return (int)ilt_ge(this->_r,r2._r); }
int ratio::operator==(ratio r2) { return (int)ilt_eq(this->_r,r2._r); }
ratio ratio::operator+() { return *this; }
ratio ratio::operator-() { return ilt_sub(ILT_CLONG2TINT(0L),this->_r); }
ratio ratio::operator+(ratio r2) { return ilt_add(this->_r,r2._r); }
ratio ratio::operator-(ratio r2) { return ilt_sub(this->_r,r2._r); }
ratio ratio::operator*(ratio r2) { return ilt_mul(this->_r,r2._r); }
ratio ratio::operator/(ratio r2) { return ilt_div(this->_r,r2._r); }
ratio ratio::operator+=(ratio r2) { this->_r = ilt_add(this->_r,r2._r); return *this; }
ratio ratio::operator-=(ratio r2) { this->_r = ilt_sub(this->_r,r2._r); return *this; }
ratio ratio::operator*=(ratio r2) { this->_r = ilt_mul(this->_r,r2._r); return *this; }
ratio ratio::operator/=(ratio r2) { this->_r = ilt_div(this->_r,r2._r); return *this; }

ratio operator+(ratio r1, long  i2) { return r1 + (ratio)i2; }
ratio operator+(long  i1, ratio r2) { return (ratio)i1 + r2; }
ratio operator+(ratio r1, int   i2) { return r1 + (ratio)i2; }
ratio operator+(int   i1, ratio r2) { return (ratio)i1 + r2; }
ratio operator-(ratio r1, long  i2) { return r1 - (ratio)i2; }
ratio operator-(long  i1, ratio r2) { return (ratio)i1 - r2; }
ratio operator-(ratio r1, int   i2) { return r1 - (ratio)i2; }
ratio operator-(int   i1, ratio r2) { return (ratio)i1 - r2; }
ratio operator*(ratio r1, long  i2) { return r1 * (ratio)i2; }
ratio operator*(long  i1, ratio r2) { return (ratio)i1 * r2; }
ratio operator*(ratio r1, int   i2) { return r1 * (ratio)i2; }
ratio operator*(int   i1, ratio r2) { return (ratio)i1 * r2; }
ratio operator/(ratio r1, long  i2) { return r1 / (ratio)i2; }
ratio operator/(long  i1, ratio r2) { return (ratio)i1 / r2; }
ratio operator/(ratio r1, int   i2) { return r1 / (ratio)i2; }
ratio operator/(int   i1, ratio r2) { return (ratio)i1 / r2; }
ratio operator+=(ratio &r1, long r2) { return r1 += ratio(r2); }
ratio operator+=(ratio &r1, int  r2) { return r1 += ratio(r2); }
ratio operator-=(ratio &r1, long r2) { return r1 -= ratio(r2); }
ratio operator-=(ratio &r1, int  r2) { return r1 -= ratio(r2); }
ratio operator*=(ratio &r1, long r2) { return r1 *= ratio(r2); }
ratio operator*=(ratio &r1, int  r2) { return r1 *= ratio(r2); }
ratio operator/=(ratio &r1, long r2) { return r1 /= ratio(r2); }
ratio operator/=(ratio &r1, int  r2) { return r1 /= ratio(r2); }
ratio operator++(ratio &r1) { return r1 += 1; }
ratio operator--(ratio &r1) { return r1 -= 1; }
