/*
 * Value.C - methods for class Value,  which stores reals and strings. 
 *
 * Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
 *                     University of Berne, Switzerland
 * Portions Copyright (C) 1990, Jonathan P. Leech
 * All rights reserved.
 *
 * This software may be freely copied, modified, and redistributed
 * provided that this copyright notice is preserved on all copies.
 *
 * You may not distribute this software, in whole or in part, as part of
 * any commercial product without the express consent of the authors.
 *
 * There is no warranty or other guarantee of fitness of this software
 * for any purpose.  It is provided solely "as is".
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include "Value.h"
#include "Error.h"

Value::Value() 
: type(REAL)
{
  realVal = 0.0;
}
      
Value::Value(real val)
: type(REAL)
{
  realVal = val;
}

Value::Value(const char* str)
: type(STRING)
{
  stringVal = new rcString(str);
}
      
Value::Value(const rcString& s)
: type(STRING)
{
  stringVal = new rcString(s);
}

Value::Value(const Value& v)
: type(v.type)
{
  if (v.type == REAL)
    realVal = v.realVal;
  else
    stringVal = new rcString(*v.stringVal);
}

Value::~Value()
{
  if (type == STRING)
    delete stringVal;
}

const Value& Value::operator=(const Value& v)
{
  if (this == &v)
    return *this;

  if (type == STRING)
    delete stringVal;

  type = v.type;
  if (v.type == REAL)
    realVal = v.realVal;
  else
    stringVal = new rcString(*v.stringVal);

  return *this;
}

Value::operator real() const
{
  if (type == REAL)
    return realVal;

  double retval;
  char *ptr;

  retval = strtod(stringVal->chars(), &ptr);
  if (*ptr == '\0')
    return retval;
  else 
    Error(ERR_PANIC, "Value::operator real(): Can't convert rcString '" +
	             *stringVal + "' to real");
  return 0;
}


Value::operator rcString() const
{
  if (type == STRING)
    return *stringVal;

  char ptr[100];
  sprintf(ptr, "%g", realVal);
  return rcString(ptr);
}

int Value::toReal(real& x) const
{
  if (type == REAL) {
    x = realVal;
    return 1;
  }

  double retval;
  char *ptr;

  retval = strtod(stringVal->chars(), &ptr);
  if (*ptr == '\0') {
    x = retval;
    return 1;
  }
  else
    return 0;
}

rcString Value::toString() const
{
  if (type == STRING)
    return *stringVal;

  char ptr[100];
  sprintf(ptr, "%g", realVal);
  return rcString(ptr);
}

ArgumentType Value::binary_type(const Value& v)
{
  switch(type) {
    case REAL: 
       if(v.type == REAL) return RR;
       else if (v.type == STRING) return RS;
       break;
    case STRING:
       if(v.type == STRING) return SS;
       else if (v.type == REAL) return SR;
       break;
    default:
       break;
  }

  Error(ERR_PANIC, "Value::binary_type: strange value for 'type'");

  return UNKNOWN;
}

Value Value::operator-() 
{
  switch (type) {
    case REAL: return Value(-realVal);
    default:   return *this;
  }
}

Value Value::operator+(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal + v.realVal);
    case SS: return Value(*stringVal + *v.stringVal);
    case RS: return Value(realVal + (real) v);
    case SR: return Value(*stringVal + (rcString) v);
    case UNKNOWN:
    default: return Value();
  }
}

Value Value::operator-(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal - v.realVal);
    default: return Value((real)*this - (real)v);
  }
}

Value Value::operator*(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal * v.realVal);
    default: return Value((real)*this * (real)v);
  }
}

Value Value::operator/(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal / v.realVal);
    default: return Value((real)*this / (real)v);
  }
}

Value Value::operator%(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value((long)realVal / (long)v.realVal);
    default: return Value((long)real(*this) / (long)real(v));
  }
}

Value Value::operator!() 
{
  switch (type) {
    case REAL: return Value(!realVal);
    case STRING: return Value(stringVal->empty());
    default:   return *this;
  }
}


Value Value::operator&&(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal && v.realVal);
    default: return Value((real)*this && (real)v);
  }
}

Value Value::operator||(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal || v.realVal);
    default: return Value((real)*this || (real)v);
  }
}

Value Value::operator==(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal == v.realVal);
    case SS: return Value(*stringVal == *v.stringVal);
    case RS: return Value((rcString) *this ==  *v.stringVal);
    case SR: return Value(*stringVal == (rcString) v);
    case UNKNOWN:
    default: return Value();
  }
}

Value Value::operator!=(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal != v.realVal);
    case SS: return Value(*stringVal != *v.stringVal);
    case RS: return Value((rcString) *this !=  *v.stringVal);
    case SR: return Value(*stringVal != (rcString) v);
    case UNKNOWN:
    default: return Value();
  }
}


Value Value::operator<(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal < v.realVal);
    case SS: return Value(*stringVal < *v.stringVal);
    case RS: return Value((rcString) *this <  *v.stringVal);
    case SR: return Value(*stringVal < (rcString) v);
    case UNKNOWN:
    default: return Value();
  }
}

Value Value::operator<=(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal <= v.realVal);
    case SS: return Value(*stringVal <= *v.stringVal);
    case RS: return Value((rcString) *this <=  *v.stringVal);
    case SR: return Value(*stringVal <= (rcString) v);
    case UNKNOWN:
    default: return Value();
  }
}

Value Value::operator>(const Value& v)
{
  switch (binary_type(v)) {
    case RR: return Value(realVal > v.realVal);
    case SS: return Value(*stringVal > *v.stringVal);
    case RS: return Value((rcString) *this >  *v.stringVal);
    case SR: return Value(*stringVal > (rcString) v);
    case UNKNOWN:
    default: return Value();
  }
}

Value Value::operator>=(const Value& v)
{
  switch (binary_type(v))
  {
    case RR: return Value(realVal >= v.realVal);
    case SS: return Value(*stringVal >= *v.stringVal);
    case RS: return Value((rcString) *this >=  *v.stringVal);
    case SR: return Value(*stringVal >= (rcString) v);
    case UNKNOWN:
    default: return Value();
  }
}

ostream& operator<<(ostream& os, const Value& v)
{
  if (v.type == REAL)
    os << v.realVal;
  else if (v.type == STRING)
    os << '\"' << *v.stringVal << '\"';
  else
    os << "Not know type of Value!\n";
 
  return os;
}
