/*************************************************************************/
/*                                                                       */
/*                                                                       */
/*  File      : Value.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                             */
/*              Tue Jul 26 20:53:38 CEST 2005                            */
/*                                                                       */
/*************************************************************************/

#include <string>
#include <iostream>
#include <map>
#ifdef __GNUC__
#include <ext/hash_map>
using namespace __gnu_cxx;
#endif
#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:
  const type_info* myType;
  typedef void(Value::*FuncPointer)(void);
  FuncPointer fp_DELETE;
  typedef void(Value::*ClonePointer)(Value*) const;
  ClonePointer fp_CLONE;
  typedef ostream&(Value::*PrintPointer)(ostream&) const;
  PrintPointer fp_PRINT;
  enum Action { SET, GET, DELETE };
  template <class T> T& value(T t = T(), Action action = GET) 
    throw (Incompatible_Type_Exception&);
  template <class T> void deleteValue();
  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 (fp_DELETE != NULL) (this->*fp_DELETE)(); }

  const type_info& typeId() const throw (bad_typeid&);
  template <class T> void setValue(const T &t) { value(t, SET); }
  template <class T> T& getValue() const throw (Incompatible_Type_Exception&){ 
    return const_cast<Value*>(this)->template value<T>();
  }
  template <class T> operator T() const throw (Incompatible_Type_Exception&) { 
    return const_cast<Value*>(this)->template value<T>(); // const_cast is safe
  }
  //template <class T> operator T&() throw (Incompatible_Type_Exception&) { 
  //  return value<T>();
  //}
  template <class T> T& operator=(const T &t) { return value(t, SET); }
  template <class T> T* operator&() { return &value<T>(); }
#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() : fp_DELETE(NULL), fp_CLONE(NULL) { 
#ifdef DEBUG
    cerr << "Value::Value() (" << this << ")\n"; 
#endif
}

inline Value::Value(const Value &val) : fp_DELETE(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);
  }
  else fp_CLONE = NULL;
}

template <class T> 
inline Value::Value(const T &t) : fp_DELETE(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::deleteValue() { 
#ifdef DEBUG
  cerr << "Deleteing Value for type " << typeid(T).name() << " (" << this 
       << ")\n";
#endif
  static T t = T(); // Used only as type selector.
  value(t, DELETE);
}

template <class T> 
inline void Value::cloneValue(Value *val) const { 
#ifdef DEBUG
  cerr << "Cloning for type " << typeid(T).name() << " (" << this << ")\n";
#endif
  // const_cast<> is safe here, because we implicitly call only 'value(T, GET)'
  val->template value<T>(const_cast<Value*>(this)->template value<T>(), SET);
  // Alternative 2 :
  // val->value<T>(const_cast<Value*>(this)->value<T>(), SET); // StrStr C.13.6
  // Alternative 3 :
  //  T t = T();
  //  val->value(const_cast<Value*>(this)->value(t, GET), SET);
}

template <class T> 
ostream& Value::printValue(ostream& os) const {
  return os << const_cast<Value*>(this)->template value<T>();
  //  T t = T();
  //  return os << const_cast<Value*>(this)->value(t, GET);
}

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 (fp_DELETE) (this->*fp_DELETE)();
    fp_DELETE = NULL;
    fp_CLONE = NULL;
    fp_PRINT = NULL;
  }
 return *this; 
}

struct ValueHash {
  size_t operator()(Value *v) const { return (long)v; }
};

template <class T> inline 
T& Value::value(T t, Action action) throw (Incompatible_Type_Exception&) { 
#ifdef __GNUC__
  static hash_map<Value*, T, ValueHash > values(500000);
#else
  static map<Value*, T > values;
#endif
  static T ret;           // only to avoid compiler warnings about returning a 
  switch(action) {        //                     reference to a local variable
    case SET :  { 
      myType = &typeid(T);
      values[this] = t;
      fp_CLONE = &Value::cloneValue<T>;
      fp_PRINT = &Value::printValue<T>;
#ifdef DEBUG
      cerr << "Assigned type " << typeid(T).name() << " to fp_CLONE ("
	   << &fp_CLONE << "::" << this << ")\n";
#endif
      if (fp_DELETE == NULL) fp_DELETE = &Value::deleteValue<T>;
      else if (fp_DELETE != (FuncPointer)&Value::deleteValue<T>) {
	(this->*fp_DELETE)();    // Delete old value of type != T for this obj
        // Remember delete function of right type 
	fp_DELETE = &Value::deleteValue<T>;
      }
      return ret;
    }
    case DELETE : { // only called by destructor
      if (values.count(this)) values.erase(this); 
      return ret; 
    } 
    case GET : { 
      if (values.count(this)) return values[this]; 
      else throw Incompatible_Type_Exception(typeid(T).name());
    }
  }
  return ret; // only to avoid compiler warnings
}

} // namespace wsi
