/*===========================================================================
 *
 * File:	Variant.H
 * Author:	Dave Humphrey (uesp@m0use.net)
 * Created On:	Thursday, December 07, 2000
 *
 * Defines the CVariant class for working with a varient variable.
 *
 *=========================================================================*/
#ifndef __VARIANT_H
#define __VARIANT_H

	/* Required Includes */
#include "genutil.h"


/*===========================================================================
 *
 * Begin Structure and Type Definitions
 *
 *=========================================================================*/
	
	/* Storage union for the variant type */
  typedef union {
    char	cValue;
    boolean	bValue;
    short	sValue;
    int		iValue;
    long	lValue;
    float	fValue;
    double	dValue;
    char*	pcValue;		
    void*	pvValue;
   } variant_t;

	/* Enumeration for identifying the type of variant */
  typedef enum {
    VT_NONE,
    VT_CHAR,
    VT_BOOLEAN,
    VT_SHORT,
    VT_INTEGER,
    VT_LONG,
    VT_FLOAT,
    VT_DOUBLE,
    VT_CHARP,
    VT_PCHAR = VT_CHARP,
    VT_VOIDP,
    VT_PVOID = VT_VOIDP
   } vartype_t;

/*===========================================================================
 *		End of Structure and Type Definitions
 *=========================================================================*/


/*===========================================================================
 *
 * Begin Class CVariant Definition
 *
 * A simple class for working with varient variables.
 *
 *=========================================================================*/
class CVariant {

  /*---------- Begin Protected Class Members --------------------*/
protected:
  variant_t Variant;		/* The variable value */
  vartype_t Type;		/* The type of value stored in the variant */
  boolean   Allocated;		/* Is the variant data allocated (for pointers only) */

  /*---------- Begin Protected Class Methods --------------------*/
protected:


  /*---------- Begin Public Class Methods -----------------------*/
public:

	/* Class Constructors for each type */
  CVariant() { Type = VT_NONE; Variant.dValue = 0; Allocated = FALSE; }
  CVariant(const char    Value) { Type = VT_CHAR; Variant.cValue = Value; Allocated = FALSE; }
  CVariant(const boolean Value) { Type = VT_BOOLEAN; Variant.bValue = Value; Allocated = FALSE; }
  CVariant(const short   Value) { Type = VT_SHORT; Variant.sValue = Value; Allocated = FALSE; }
  CVariant(const int     Value) { Type = VT_INTEGER;  Variant.iValue = Value; Allocated = FALSE; }
  CVariant(const long    Value) { Type = VT_LONG; Variant.lValue = Value; Allocated = FALSE; }
  CVariant(const float   Value) { Type = VT_FLOAT; Variant.fValue = Value; Allocated = FALSE; }
  CVariant(const double  Value) { Type = VT_DOUBLE; Variant.dValue = Value; Allocated = FALSE; }
  CVariant(const char*  pValue) { Type = VT_CHARP; Variant.pcValue = CreateString(pValue); Allocated = TRUE; }
  CVariant(      void*  pValue) { Type = VT_VOIDP; Variant.pvValue = pValue; Allocated = FALSE; }

	/* Class Destructors */
  virtual ~CVariant() { Destroy(); }
  virtual void Destroy (void);
  virtual void DestroyAllocated (void);

	/* Get class members */
        vartype_t  GetType    (void) const { return (Type); }
  const variant_t& GetVariant (void) const { return (Variant); }

	/* Get the variant value */
  char	  GetChar     (void) const { if (IsChar())    return (Variant.cValue);  else if (IsPChar() && Variant.pcValue != NULL) return (Variant.pcValue[0]); else return ((char) GetIntegral()); }
  boolean GetBoolean  (void) const { if (IsBoolean()) return (Variant.bValue);  else if (IsPChar()) return (StringToBoolean(Variant.pcValue)); else return ((boolean) GetIntegral()); }
  short   GetShort    (void) const { if (IsShort())   return (Variant.sValue);  else return ((short) GetIntegral()); }
  int     GetInt      (void) const { if (IsInt())     return (Variant.iValue);  else return ((int) GetIntegral()); }
  long    GetLong     (void) const { if (IsLong())    return (Variant.lValue);  else return ((long) GetIntegral()); }
  float   GetFloat    (void) const { if (IsFloat())   return (Variant.fValue);  else return ((float) GetDecimal()); }
  double  GetDouble   (void) const { if (IsDouble())  return (Variant.dValue);  else return ((double) GetDecimal()); }
  char*   GetPChar    (void) const { if (IsPChar())   return (Variant.pcValue);  else if (IsPVoid()) return (char*) (Variant.pvValue); else return ((char*)NULL); }
  char*   GetString   (void) const { return GetPChar(); }
  void*   GetPVoid    (void) const { if (IsPVoid())   return (Variant.pvValue);  else if (IsPChar()) return (void*) (Variant.pcValue); else return ((void*)NULL); }
  long    GetIntegral (void) const;
  double  GetDecimal  (void) const;

	/* Check state of variant */
  boolean IsAllocated (void) const { return (Allocated); }
  boolean IsPointer   (void) const { return (Type == VT_CHARP || Type == VT_VOIDP); }
  boolean IsNumeric   (void) const { return (!IsPointer()); }
  boolean IsIntegral  (void) const { return (IsNumeric() && Type != VT_FLOAT && Type != VT_DOUBLE); }
  boolean IsDecimal   (void) const { return (IsNumeric() && !IsIntegral()); }

	/* Check the type of the variant */
  boolean IsChar    (void) const { return (Type == VT_CHAR); }
  boolean IsBoolean (void) const { return (Type == VT_BOOLEAN); }
  boolean IsShort   (void) const { return (Type == VT_SHORT); }
  boolean IsInt     (void) const { return (Type == VT_INTEGER); }
  boolean IsLong    (void) const { return (Type == VT_LONG); }
  boolean IsFloat   (void) const { return (Type == VT_FLOAT); }
  boolean IsDouble  (void) const { return (Type == VT_DOUBLE); }
  boolean IsPChar   (void) const { return (Type == VT_PCHAR); }
  boolean IsString  (void) const { return IsPChar(); }
  boolean IsPVoid   (void) const { return (Type == VT_PVOID); }
  boolean IsType    (const vartype_t NewType) const { return (Type == NewType); }

	/* Set the variant value to the specified type */
  void SetChar    (const char    Value) { DestroyAllocated(); Type = VT_CHAR;	 Variant.cValue = Value; }
  void SetBoolean (const boolean Value) { DestroyAllocated(); Type = VT_BOOLEAN; Variant.bValue = Value; }
  void SetShort   (const short   Value) { DestroyAllocated(); Type = VT_SHORT;	 Variant.sValue = Value; }
  void SetInt     (const int     Value) { DestroyAllocated(); Type = VT_INTEGER; Variant.iValue = Value; }
  void SetLong    (const long    Value) { DestroyAllocated(); Type = VT_LONG;	 Variant.lValue = Value; }
  void SetFloat   (const float   Value) { DestroyAllocated(); Type = VT_FLOAT;	 Variant.fValue = Value; }
  void SetDouble  (const double  Value) { DestroyAllocated(); Type = VT_DOUBLE;	 Variant.dValue = Value; }
  void SetPChar   (const char*  pValue) { DestroyAllocated(); Type = VT_CHARP;	 Variant.pcValue = CreateString(pValue);  Allocated = TRUE; }
  void SetString  (const char*  pValue) { SetPChar(pValue); }
  void SetPVoid   (      void*  pValue) { DestroyAllocated(); Type = VT_VOIDP;	 Variant.pvValue = pValue; }
  void SetVariant (const CVariant& SrcVar);

	/* Overload the copy constructor */
  CVariant& operator = (const char    Value) { SetChar(Value);	  return (*this); }
  CVariant& operator = (const boolean Value) { SetBoolean(Value); return (*this); }
  CVariant& operator = (const short   Value) { SetShort(Value);	  return (*this); }
  CVariant& operator = (const int     Value) { SetInt(Value);	  return (*this); }
  CVariant& operator = (const long    Value) { SetLong(Value);	  return (*this); }
  CVariant& operator = (const float   Value) { SetFloat(Value);	  return (*this); }
  CVariant& operator = (const double  Value) { SetDouble(Value);  return (*this); }
  CVariant& operator = (const char*  pValue) { SetPChar(pValue);  return (*this); }
  CVariant& operator = (      void*  pValue) { SetPVoid(pValue);  return (*this); }
  CVariant& operator = (const CVariant& SrcVar) { SetVariant(SrcVar); return (*this); }

	/* Overload the equality operator */
  int operator == (const CVariant& SrcVar) const;
  int operator == (const char    Value) const { if (!IsChar())    return (0); return (int)(Variant.cValue == Value); }
  int operator == (const boolean Value) const { if (!IsBoolean()) return (0); return (int)(Variant.bValue == Value); }
  int operator == (const short   Value) const { if (!IsShort())   return (0); return (int)(Variant.sValue == Value); }
  int operator == (const int     Value) const { if (!IsInt())     return (0); return (int)(Variant.iValue == Value); }
  int operator == (const long    Value) const { if (!IsLong())    return (0); return (int)(Variant.lValue == Value); }
  int operator == (const float   Value) const { if (!IsFloat())   return (0); return (int)(Variant.fValue == Value); }
  int operator == (const double  Value) const { if (!IsDouble())  return (0); return (int)(Variant.dValue == Value); }
  int operator == (const char*  pValue) const { if (!IsPChar())   return (0); return (int)(Variant.pcValue == pValue); }
  int operator == (const void*  pValue) const { if (!IsPVoid())   return (0); return (int)(Variant.pvValue == pValue); }
  
 };
/*===========================================================================
 *		End of Class CVariant Definition
 *=========================================================================*/


/*===========================================================================
 *
 * Begin Class CVariant Inline Methods
 *
 *=========================================================================*/

  inline void CVariant::Destroy (void) {
	DestroyAllocated();
	Allocated = FALSE;
	Type = VT_NONE;
	Variant.dValue = 0;
   }

  inline void CVariant::DestroyAllocated (void) { 
	if (IsAllocated() && Type == VT_CHARP) {
	  DestroyPointerArray(Variant.pcValue);
	  Allocated = FALSE; 
	 } 
   }

  inline long CVariant::GetIntegral (void) const {
	switch (Type) {
	  case VT_CHAR:    return (long) Variant.cValue;
	  case VT_BOOLEAN: return (long) Variant.bValue;
	  case VT_SHORT:   return (long) Variant.sValue;
	  case VT_INTEGER: return (long) Variant.iValue;
	  case VT_LONG:    return (long) Variant.lValue;
	  case VT_FLOAT:   return (long) Variant.fValue;
	  case VT_DOUBLE:  return (long) Variant.dValue;
	  case VT_PCHAR:   if (Variant.pcValue == NULL) return (long)0; 
			   return (long) strtol(Variant.pcValue, NULL, 0);
	  case VT_PVOID:   return (long) Variant.pvValue;
	  default:	   return (long) 0;
	 }
   }

  inline double CVariant::GetDecimal (void) const {
	switch (Type) {
	  case VT_CHAR:    return (double) Variant.cValue;
	  case VT_BOOLEAN: return (double) Variant.bValue;
	  case VT_SHORT:   return (double) Variant.sValue;
	  case VT_INTEGER: return (double) Variant.iValue;
	  case VT_LONG:    return (double) Variant.lValue;
	  case VT_FLOAT:   return (double) Variant.fValue;
	  case VT_DOUBLE:  return (double) Variant.dValue;
	  case VT_PCHAR:   if (Variant.pcValue == NULL) return (double)0; 
			   return (double) strtod(Variant.pcValue, NULL);
	  case VT_PVOID:   return (double) (long) (Variant.pvValue);
	  default:	   return (double) 0;
	 }
   }

  inline void CVariant::SetVariant (const CVariant& SrcVar) {
	const variant_t& VarData = SrcVar.GetVariant();
    
		/* Delete any current allocated data */
	DestroyAllocated();
	Type = SrcVar.GetType();
	Allocated = SrcVar.IsAllocated();

        if (Type == VT_PCHAR) 
	  Variant.pcValue = CreateString(VarData.pcValue);
	else
	  Variant = VarData;
   }

  inline int CVariant::operator == (const CVariant& SrcVar) const {
	const variant_t& VarData = SrcVar.GetVariant();

	if (Type != SrcVar.GetType()) return (0);

	switch (Type) {
    	  case VT_CHAR:    return (int) (Variant.cValue == VarData.cValue);
	  case VT_BOOLEAN: return (int) (Variant.bValue == VarData.bValue);
	  case VT_SHORT:   return (int) (Variant.sValue == VarData.sValue);
	  case VT_INTEGER: return (int) (Variant.iValue == VarData.iValue);
	  case VT_LONG:    return (int) (Variant.lValue == VarData.lValue);
	  case VT_FLOAT:   return (int) (Variant.fValue == VarData.fValue);
	  case VT_DOUBLE:  return (int) (Variant.dValue == VarData.dValue);
	  case VT_PCHAR:   return (int) (Variant.pcValue == VarData.pcValue);
	  case VT_PVOID:   return (int) (Variant.pvValue == VarData.pvValue);
	  default:	   return (int) 1;
	 }
   }

  inline int operator == (const char    Value, const CVariant& VarData) { return VarData.operator ==(Value); }
  inline int operator == (const boolean Value, const CVariant& VarData) { return VarData.operator ==(Value); }
  inline int operator == (const short   Value, const CVariant& VarData) { return VarData.operator ==(Value); }
  inline int operator == (const int     Value, const CVariant& VarData) { return VarData.operator ==(Value); }
  inline int operator == (const long    Value, const CVariant& VarData) { return VarData.operator ==(Value); }
  inline int operator == (const float   Value, const CVariant& VarData) { return VarData.operator ==(Value); }
  inline int operator == (const double  Value, const CVariant& VarData) { return VarData.operator ==(Value); }
  inline int operator == (const char*  pValue, const CVariant& VarData) { return VarData.operator ==(pValue); }
  inline int operator == (const void*  pValue, const CVariant& VarData) { return VarData.operator ==(pValue); }
  
/*===========================================================================
 *		End of Class CVariant Inline Methods
 *=========================================================================*/

#endif
/*===========================================================================
 *		End of File Variant.H
 *=========================================================================*/