#ifndef PROPERTY_H
#define PROPERTY_H


struct Property
{
  Property() : m_type(PT_Invalid) {}
  ~Property() {}

  explicit Property(Boolean    a_bool  ) : m_type(PT_Boolean   ) { m_basicType.m_bool   = a_bool  ; }
  explicit Property(Byte       a_uint8 ) : m_type(PT_Byte      ) { m_basicType.m_uint8  = a_uint8 ; }
  explicit Property(Char       a_int8  ) : m_type(PT_Char      ) { m_basicType.m_int8   = a_int8  ; }
  explicit Property(Unsigned32 a_uint32) : m_type(PT_Unsigned32) { m_basicType.m_uint32 = a_uint32; }
  explicit Property(Unsigned64 a_uint64) : m_type(PT_Unsigned64) { m_basicType.m_uint64 = a_uint64; }
  explicit Property(Integer32  a_int32 ) : m_type(PT_Integer32 ) { m_basicType.m_int32  = a_int32 ; }
  explicit Property(Integer64  a_int64 ) : m_type(PT_Integer64 ) { m_basicType.m_int64  = a_int64 ; }
  explicit Property(Float32    a_flt32 ) : m_type(PT_Float32   ) { m_basicType.m_flt32  = a_flt32 ; }
  explicit Property(Float64    a_flt64 ) : m_type(PT_Float64   ) { m_basicType.m_flt64  = a_flt64 ; }
  explicit Property(const Array<Property>& a_array ) : m_type(PT_Array ) { m_array      = a_array ; }
  explicit Property(const String&          a_string) : m_type(PT_String) { m_string     = a_string; }
  explicit Property(const char*            a_string) : m_type(PT_String) { m_string     = a_string; }

  enum PropertyType
  {
    // Uninitialize state
    PT_Invalid    = 0,
    // Basic types
    PT_Boolean    = 1, 
    PT_Byte       = 2, 
    PT_Char       = 3, 
    PT_Unsigned32 = 4,
    PT_Unsigned64 = 5,
    PT_Integer32  = 6, 
    PT_Integer64  = 7, 
    PT_Float32    = 8, 
    PT_Float64    = 9, 
    // Complex types
    PT_Array      = 10,
    PT_String     = 11,
  };

  PropertyType     m_type;

  union {
    Boolean        m_bool;
    Byte           m_uint8;
    Char           m_int8;
    Unsigned32     m_uint32;
    Unsigned64     m_uint64;
    Integer32      m_int32;
    Integer64      m_int64;
    Float32        m_flt32;
    Float64        m_flt64;
  } m_basicType;

  Array<Property>  m_array;
  String           m_string;

  // This can do both the serializing and de-serializing
  // This might be good to have generated, but possibly being more explicit could be better too
  // Also note the members could be private and this will still work
  template <class V>
  void Visit(V& v)
  {
    v.Enter("Property");
    Integer32 t = m_type;
    v.Visit("type", t);
    switch (m_type)
    {
      case PT_Boolean:
        v.Visit("value", m_basicType.m_bool); break;
      case PT_Byte:
        v.Visit("value", m_basicType.m_uint8); break;
      case PT_Char:
        v.Visit("value", m_basicType.m_int8); break;
      case PT_Unsigned32:
        v.Visit("value", m_basicType.m_uint32); break;
      case PT_Unsigned64:
        v.Visit("value", m_basicType.m_uint64); break;
      case PT_Integer32:
        v.Visit("value", m_basicType.m_int32); break;
      case PT_Integer64:
        v.Visit("value", m_basicType.m_int64); break;
      case PT_Float32:
        v.Visit("value", m_basicType.m_flt32); break;
      case PT_Float64:
        v.Visit("value", m_basicType.m_flt64); break;
      case PT_Array:
        v.Visit("value", m_array); break;
      case PT_String:
        v.Visit("value", m_string); break;
    }
    v.Exit("Property");
  }
};


#endif // PROPERTY_H

