/*************************************************************************/
/*                                                                       */
/*                                                                       */
/*  File      : Value_void.hpp                                           */
/*  Author    : Volker H. Simonis  (simonis@sun.com)                     */
/*  Copyright : Volker H. Simonis  (simonis@sun.com)                     */
/*  Date      : Wed Oct 21 12:11:50 MEST 1998                            */
/*              Sat Jan 23 01:17:39 CET 1999                             */
/*              Fri Feb 12 17:56:55 CET 1999                             */
/*              Tue Jul 26 20:53:38 CEST 2005                            */
/*                                                                       */
/*************************************************************************/

#include <string>
#include <iostream>
#include <typeinfo>

using namespace std;

namespace wsi {

class Value;

class Incompatible_Type_Exception {
private:
  string errorType;
public:
  Incompatible_Type_Exception(const string& s) { errorType = s; }
  string getError() const { return errorType; }
};

class Value {
private:
  void *data;
  const type_info* myType;
  typedef void(Value::*ClonePointer)(Value*) const;
  ClonePointer fp_CLONE;
  typedef ostream&(Value::*PrintPointer)(ostream&) const;
  PrintPointer fp_PRINT;
  template <class T> void cloneValue(Value*) const;
  template <class T> ostream& printValue(ostream&) const;
public:
  Value();                            // Default constructor 
  Value(const Value&);                // Copy constructor
  template <class T> Value(const T&); // Generic constructor
  ~Value() { if (data) delete data; }

  const type_info& typeId() const throw (bad_typeid&);
  template <class T> void setValue(const T &t) { 
    myType = &typeid(T);
    fp_CLONE = &Value::cloneValue<T>;
    fp_PRINT = &Value::printValue<T>;
    if (data) delete data;
    data = new T(t);
  }
  template <class T> T& getValue() const throw (Incompatible_Type_Exception&){ 
    if (myType == 0 || *myType != typeid(T)) 
      throw Incompatible_Type_Exception(typeid(T).name());
    return *((T*)data);
  }
  template <class T> operator T() const throw (Incompatible_Type_Exception&) {
    if (myType == 0 || *myType != typeid(T)) 
      throw Incompatible_Type_Exception(typeid(T).name());
    return *((T*)data);
  }
  //template <class T> operator T&() throw (Incompatible_Type_Exception&) { 
  //  return value<T>();
  //}
  template <class T> T& operator=(const T &t) { 
    myType = &typeid(T);
    fp_CLONE = &Value::cloneValue<T>;
    fp_PRINT = &Value::printValue<T>;
    if (data) delete data;
    data = new T(t);
    return *((T*)data);
  }
  template <class T> T* operator&() { return (T*)data; }
#ifdef _MSC_VER
  Value* operator&() { return const_cast<Value*>(this); }
#endif
  Value& operator=(const Value&);

  friend ostream& operator<<(ostream&, const Value&);
};

ostream& operator<<(ostream& os, const Value& e) {
  if (e.fp_PRINT) return (e.*e.fp_PRINT)(os);
  else return (os << "nil");
}

inline Value::Value() : data(NULL), fp_CLONE(NULL) { 
#ifdef DEBUG
    cerr << "Value::Value() (" << this << ")\n"; 
#endif
}

inline Value::Value(const Value &val) : data(NULL) {
#ifdef DEBUG
  cerr << "Assigning Value(" << &val.fp_CLONE << "::" << &val 
       << ") to Value(" << &this->fp_CLONE << "::" << this << ")\n";
#endif
  if (val.fp_CLONE != NULL) {
    (val.*val.fp_CLONE)(this);
  }
}

template <class T> 
inline Value::Value(const T &t) : data(NULL) {
#ifdef DEBUG
  cerr << "Value::Value(" << typeid(t).name() << ") (" << this << ")\n";
#endif
  setValue(t);
}

const type_info& Value::typeId() const throw (bad_typeid&) { 
  if (myType) return *myType;
  else throw bad_typeid();
}

template <class T> 
inline void Value::cloneValue(Value *val) const { 
#ifdef DEBUG
  cerr << "Cloning for type " << typeid(T).name() << " (" << this << ")\n";
#endif
  val->myType = &typeid(T);
  val->fp_CLONE = &Value::cloneValue<T>;
  val->fp_PRINT = &Value::printValue<T>;
  if (val->data) delete val->data;
  val->data = new T(*((T*)data));  
}
 
template <class T> 
ostream& Value::printValue(ostream& os) const {
  return os << *((T*)data);
}

inline Value& Value::operator=(const Value &val) { 
#ifdef DEBUG
  cerr << "Assigning Value(" << &val.fp_CLONE << "::" << &val 
       << ") to Value(" << &this->fp_CLONE << "::" << this << ")\n";
#endif
  if (this != &val && val.fp_CLONE != NULL) {
    (val.*val.fp_CLONE)(this);
    // this syntax means : dereference the member function pointer fp_CLONE
    //                     of object 'val', for the object 'val' itself.
    // ATTENTION !!! 'val.*fp_CLONE' means dereference fp_CLONE of 'this' for
    //                     the object 'val', what in general will be false,
    //                     since fp_CLONE of this can hold another type.
  }
  else {  // if we were assigned a bare Value object
    if (data) delete data;
    data = NULL;
    fp_CLONE = NULL;
    fp_PRINT = NULL;
  }
  return *this; 
}

} // namespace wsi
