#if !defined(_VARIENT_H)
#define _VARIENT_H

#include "stdio.h"
#include "PubHeader.h"
#include "otstr.h"
#include "ObArray.h"

//////////////////////////////////////////////////////
typedef char		    INT1;
typedef unsigned char	UINT1;
typedef short			INT2;
typedef unsigned short	UINT2;
typedef long			INT4;
typedef unsigned long	UINT4;
typedef void*           PVOID;
typedef double          DOUBLE;

//////////////////////////////////////////////////////////////
// VarAttr      属性定义类, 定义基本数据类型    
//
// CVarient     动态数据类型对象数值容器, 用于数据值的保存(set)和读取(get),
//
//              支持数据运算, 赋值时动态确定数据类型
//  
//              不支持数组, T_PVOID
//
// TVarient     变量定义类, 不定长字符串及常用数据类型(支持数组)容器综合类
//
//////////////////////////////////////////////////////////////

#ifdef _DLL_PROJECT
class CLASS_EXPORT VarAttr: public TName
#else
class VarAttr: public TName
#endif
{
public:
    enum type_
    { 
        T_INT1   = 0,   T_INT2    = 1,   T_INT4  = 2, 
        T_UINT1  = 3,   T_UINT2   = 4,   T_UINT4 = 5,
        T_OCTET  = 7,   T_DOUBLE  = 8,
        T_PVOID  = 10, 
        T_NULL   = -1   // VOID 
    };

protected:
    int    m_type;
    long   m_size;
    
public:
    VarAttr();
    virtual ~VarAttr();

    bool  setAttr(char* varname,int type,long size=1);
    
    void  clone(VarAttr& Object);
    void  clear();
    
    int   getType() { return m_type; }
    int   getSize() { return m_size; }

protected:
    void  setSize(long size=1)  { m_size=size; }
    void  setType(int type)     { m_type=type; }
    int   getTypesize(int type);
    
public:
    bool  isNumber(bool includeDoubleType);
    bool  isUnsignedNumber();
    bool  isSignedNumber();
    bool  isDouble();
    bool  isOctstr();

    static bool  isNumber(int type, bool includeDoubleType);
    static bool  isUnsignedNumber(int type);
    static bool  isSignedNumber(int type);
    static bool  isDouble(int type);
    static bool  isOctstr(int type);

    static int   getBitsLen(int type);
    static int   calcCompatibleType(int type1,int type2);
    static bool  isValidType(int type); 
    static char* getTypeDefaultName(int type); 
    
    static int   Get_NumberType(char* buf, int len=-1); // SYM_INVALID, SYM_NUMBER_DEX, SYM_NUMBER_HEX, SYM_NUMBER_DOUBLE

private:
    static char* cDefaultFormat[];
};

#ifdef _DLL_PROJECT
class CLASS_EXPORT CVarient: public VarAttr
#else
class CVarient: public VarAttr
#endif
{
protected:
    UINT4  m_Value;         // WHEN T_OCTET,  m_Value=strlen
                            // WHEN T_DOUBLE, m_Value=sizeof(double)
    char*  m_pData;
    bool   m_bDataSeted;
    bool   m_bEditable;  
    
public:
    CVarient();
    CVarient(const char* lpstring,int len=-1);
    CVarient(INT4  data, int type=T_INT4);
    CVarient(double data);
    virtual ~CVarient();

    bool clone(CVarient& VarientObject);

    ////////////////////////////////////////////////
    // Varient对象赋值操作(根据值类型会改变Varient_type类型)
    bool set(const char* lpstring,int len=-1);
    bool set(OTSTR& str);
    bool set(INT4   data, int type=T_INT4);
    bool set(double data);

    // SetValue From String  (INT,UINT,DOUBLE,OCTET)
    // if OCTET: 'strValue' (39) or "strValue"
    // if HEX  : -> UINT4 
    bool sets(char* szValueString,char* szSeperatorChars="\""); 
    
    // operator= only change data of CVarient
    const bool operator=(OTSTR& right);
    const bool operator=(const char* right);
    const bool operator=(const CVarient& right);
    const bool operator=(signed   data);
    const bool operator=(unsigned data);
    const bool operator=(double   data);

    bool  isDataSeted() { return m_bDataSeted;  }
    void  setEditable(bool bEditable) { m_bEditable=bEditable; }
    bool  getEditable() { return m_bEditable; }
    
    ////////////////////////////////////////////////
    // Varient对象读取操作
    bool get(char**  return_string,int* return_len=NULL);
    bool get(OTSTR&  str);
    bool get(INT1&   return_data);
    bool get(INT2&   return_data);
    bool get(INT4&   return_data);
    bool get(UINT1&  return_data);
    bool get(UINT2&  return_data);
    bool get(UINT4&  return_data);
    bool get(double& return_data);

    operator const INT1  ();
    operator const INT2  ();
    operator const INT4  ();
    operator const UINT1 ();
    operator const UINT2 ();
    operator const UINT4 ();
    operator const DOUBLE();
    operator char* ();

    friend bool operator==(CVarient &left, CVarient &right);
    
    // 运算(自动计算结果类型)
    CVarient& Operate(CVarient& left, char* szOperator, CVarient& right, bool bCaseForStringOperate=true);
    CVarient& Operate(char* szOperator, CVarient& right);  //单目 +正,-负,~否 (右结合)
    
    OTSTR dump(char* cFormat=NULL); // INT, UINT, DOUBLE, OCTET->"string"

    void  clear(bool bClearOnlyData);

    /////////////////////////////////////////////////////////////////////
    static int vsprintf_(char *buf, int buflen, const char *fmt, TObArray<CVarient>& pVarientList);
              // return: -1  get param error
              //         -2  buf overflow
              //         -3  value type illegal

              // fmt SYNTAX: %[flags] [width] [.precision] [{ l }]type
              //       flag: +|-|0| |
              //       type: c|C|s|d|u|f|e|o|x|X
};

///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
class CLASS_EXPORT NullVarientObject;
#else
class NullVarientObject;
#endif

#ifdef _DLL_PROJECT
class CLASS_EXPORT TVarient: public VarAttr
#else
class TVarient: public VarAttr
#endif
{
public:
    TVarient();
    TVarient(char* name,int type,long size=1);
    virtual ~TVarient();

    bool  init(char* name,int type,long size=1);

    bool  clone(TVarient& VarientObject);     // 所有属性和数据克隆 !! for T_PVOID, only the pointer is cloned, data in PVOID will not be cloned
    bool  cloneData(TVarient& VarientObject); // 只复制数据 !! for T_PVOID, only the pointer is cloned, data in PVOID will not be cloned
    bool  resize(long new_size);              // resize and keep the old data

    ////////////////////////////////////////////
    bool  PassAddressClone(TVarient& SrcVarient,long nIndex); // 属性克隆, 但m_pData数据区直接应用, nIndex>=0表示数组中的一个元素

    ////////////////////////////////////////////
    bool  setAt(long nIndex,char  *buffer, int length);  // length==-1, length=strlen(buffer)
    bool  setAt(long nIndex,signed data);
    bool  setAt(long nIndex,double data);
    bool  setAt(long nIndex,PVOID  pVoid);
    bool  setAt(long nIndex,CVarient& Varient);

    bool  setsAt(long nIndex, char* szValueString,char* szSeperatorChars="\"");  
              // SetValue From String  (INT,UINT,DOUBLE,OCTET)
              // if OCTET: 'strValue' (39) or "strValue"
              // if HEX  : -> UINT4 

    bool  setn(signed data, ...);
    bool  setn(double data, ...);
    bool  setn(char*  lpstring, ...);  // 对数组,必须保证个数一致
    bool  setn(OTSTR* lpOtstr, ...);
    
    bool  getAt(long nIndex,OTSTR&  str);
    bool  getAt(long nIndex,INT1&   return_data);
    bool  getAt(long nIndex,INT2&   return_data);
    bool  getAt(long nIndex,INT4&   return_data);
    bool  getAt(long nIndex,UINT1&  return_data);
    bool  getAt(long nIndex,UINT2&  return_data);
    bool  getAt(long nIndex,UINT4&  return_data);
    bool  getAt(long nIndex,double& return_data);
    bool  getAt(long nIndex,PVOID*  pVoid);
    bool  getAt(long nIndex,CVarient& return_data);

    bool  isDataSeted() { return m_bDataSeted;  }
    void  setEditable(bool bEditable) { m_bEditable=bEditable; }
    bool  getEditable() { return m_bEditable; }
    
    /////////////////
    bool  set_as_string(char* buffer); // "string" -> INT1, UINT1 
    OTSTR get_as_string();             //  INT1, UINT1 ->"string"
    
    ////////////////////////////////////////////
    OTSTR dump(long nIndex,char* cFormat[]);
    OTSTR dump(long nIndex,char* cFormat=NULL); // INT, UINT, DOUBLE, OCTET->"string"

    void  clear(bool bClearAttrAlso=true);

protected:
    bool    m_bPassAddressData;
    bool*   m_pPassAddressDataSeted;
    void*   m_pData;
    bool    m_bDataSeted;
    bool    m_bEditable;  
    
    void    setDataSeted(bool bSeted);
    
    ///////////////////////////////////////////
    static  NullVarientObject NullObject_;

public:
    ////////////////////////////////////////////
    //不推荐使用以下模式
    INT1&   DataINT1  (long nIndex=0);
    INT2&   DataINT2  (long nIndex=0);
    INT4&   DataINT4  (long nIndex=0);
    UINT1&  DataUINT1 (long nIndex=0);
    UINT2&  DataUINT2 (long nIndex=0);
    UINT4&  DataUINT4 (long nIndex=0);
    double& DataDOUBLE(long nIndex=0);
    PVOID&  DataPVOID (long nIndex=0);
    OTSTR&  DataOTSTR (long nIndex=0);

    INT4    getAt_as_long  (long nIndex=0);
    UINT4   getAt_as_ulong (long nIndex=0);
    double  getAt_as_double(long nIndex=0);
}; 



#endif 
