/*==LICENSE==*

CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011  Cyan Worlds, Inc.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Additional permissions under GNU GPL version 3 section 7

If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.

You can contact Cyan Worlds, Inc. by email legal@cyan.com
 or by snail mail at:
      Cyan Worlds, Inc.
      14617 N Newport Hwy
      Mead, WA   99021

*==LICENSE==*/
#ifndef plSDL_DESC_inc
#define plSDL_DESC_inc

//
// Code for State Description Language (SDL) Descriptors.
// These define a schema representing an object's saveState buffer.
//

#include "HeadSpin.h"

#include "hsStlUtils.h"

//
// Describes a variable in a state descriptor.
// Every variable is actually a list, either fixed or variable length.
// Abstract base class.
//
class hsStream;
class plSimpleVarDescriptor;
class plSDVarDescriptor;
class plVarDescriptor
{
public:
    enum Type
    {
        kNone   = -1,

        // atomic types
        kInt,
        kFloat,
        kBool,
        kString32,
        kKey,       // plKey - basically a uoid
        kStateDescriptor,   // this var refers to another state descriptor
        kCreatable, // plCreatable - basically a classIdx and a read/write buffer
        kDouble,
        kTime,      // double which is automatically converted to server clock and back, use for animation times
        kByte,
        kShort,
        kAgeTimeOfDay,  // float which is automatically set to the current age time of day (0-1)
        
        // the following are a vector of floats
        kVector3=50,// atomicCount=3
        kPoint3,    // atomicCount=3
        kRGB,       // atomicCount=3
        kRGBA,      // atomicCount=4
        kQuaternion,    // atomicCount=4
        kRGB8,      // atomicCount=3
        kRGBA8,     // atomicCount=4
    };
    typedef char String32[32];
    
    enum Flags
    {
        kInternal   = 0x1,      // Don't allow access to this var in Vault Mgr
        kAlwaysNew  = 0x2,      // Treat this var as always having the latest timestamp when FlaggingNewerState
        kVariableLength = 0x4   // Var is defined as int foo[], so it's length is variable, starting at 0
    };
protected:
    static const uint8_t kVersion;    // for Read/Write format
    char*   fDefault;               // set by .sdl
    char*   fName;                  // set by .sdl
    int     fCount;                 // set by .sdl
    Type    fType;                  // set by .sdl
    char*   fTypeString;            // string version of fType
    uint32_t  fFlags;
    std::string fDisplayOptions;    // set by .sdl
public:
    plVarDescriptor();
    virtual ~plVarDescriptor();
    
    virtual void CopyFrom(const plVarDescriptor* v);
    
    // conversion ops
    virtual plSimpleVarDescriptor*  GetAsSimpleVarDescriptor() = 0;
    virtual plSDVarDescriptor* GetAsSDVarDescriptor() = 0;
    virtual const plSimpleVarDescriptor*    GetAsSimpleVarDescriptor() const = 0;
    virtual const plSDVarDescriptor* GetAsSDVarDescriptor() const = 0;

    // getters
    const char* GetDefault()    const   { return fDefault; }
    const char* GetName()   const       { return fName; }
    Type    GetType() const             { return fType; }
    const char* GetTypeString() const   { return fTypeString; }
    int     GetCount() const            { return fCount; }
    bool    IsInternal() const          { return (fFlags & kInternal) != 0; }
    bool    IsAlwaysNew() const         { return (fFlags & kAlwaysNew) != 0; }
    bool    IsVariableLength() const    { return (fFlags & kVariableLength) != 0; }
    const char* GetDisplayOptions() const { return fDisplayOptions.c_str(); }
    
    // setters
    void    SetDefault(const char* n)   { delete [] fDefault; fDefault= hsStrcpy(n); }
    void    SetName(const char* n)      { delete [] fName; fName = hsStrcpy(n); }
    void    SetCount(int c)             { fCount=c; }
    virtual bool    SetType(const char* type);
    void    SetType(Type t) { fType=t; }
    void    SetInternal(bool d)         { if (d) fFlags |= kInternal; else fFlags &= ~kInternal; }
    void    SetAlwaysNew(bool d)        { if (d) fFlags |= kAlwaysNew; else fFlags &= ~kAlwaysNew; }
    void    SetVariableLength(bool d)   { if (d) fFlags |= kVariableLength; else fFlags &= ~kVariableLength; }
    void    SetDisplayOptions(const char* s) { fDisplayOptions=s;   }

    // IO
    virtual bool    Read(hsStream* s);  
    virtual void    Write(hsStream* s) const;
};

//
// Simple, non-nested var descriptors.  These are comprised of single types, as opposed to 
// referring to another state descriptor.
//
class plSimpleVarDescriptor : public plVarDescriptor
{
protected:
    Type    fAtomicType;            // base type (it. quaternion == kFloat)
    int     fAtomicCount;           // computed from type in .sdl (ie. quaternion == 4)
public:
    plSimpleVarDescriptor();
    virtual ~plSimpleVarDescriptor() {  }
        
    plSimpleVarDescriptor*  GetAsSimpleVarDescriptor() { return this; }
    plSDVarDescriptor* GetAsSDVarDescriptor() { return nil; }
    const plSimpleVarDescriptor*    GetAsSimpleVarDescriptor() const { return this; }
    const plSDVarDescriptor* GetAsSDVarDescriptor() const { return nil; }

    void CopyFrom(const plSimpleVarDescriptor* v);
    void CopyFrom(const plVarDescriptor* v) { plVarDescriptor::CopyFrom(v); }   // lame compiler

    // getters
    int     GetSize() const;
    int     GetAtomicSize() const;      // size of one item in bytes (regardless of count)
    Type    GetAtomicType() const       { return fAtomicType; }
    int     GetAtomicCount() const      { return fAtomicCount; }    
    
    // setters
    bool    SetType(const char* type);
    void    SetType(Type t) { plVarDescriptor::SetType(t); }    // for lame compiler
    void    SetAtomicType(Type t) { fAtomicType=t; }    

    // IO
    virtual bool    Read(hsStream* s);  
    virtual void    Write(hsStream* s) const;
};

//
// A var descriptor which references another state descriptor.
//
class plStateDescriptor;
class plSDVarDescriptor : public plVarDescriptor
{
protected:
    plStateDescriptor* fStateDesc;      
public:
    plSDVarDescriptor(plStateDescriptor* sd=nil) : fStateDesc(sd) { }

    plSimpleVarDescriptor*  GetAsSimpleVarDescriptor() { return nil; }
    plSDVarDescriptor* GetAsSDVarDescriptor() { return this; }
    const plSimpleVarDescriptor*    GetAsSimpleVarDescriptor() const { return nil; }
    const plSDVarDescriptor* GetAsSDVarDescriptor() const { return this; }

    // getters
    plStateDescriptor* GetStateDescriptor() const { return fStateDesc; }

    // setters
    void SetStateDesc(plStateDescriptor* sd) { fStateDesc=sd; }

    void CopyFrom(const plSDVarDescriptor* v);
    void CopyFrom(const plVarDescriptor* v) { plVarDescriptor::CopyFrom(v); }   // lame compiler

    // IO
    bool    Read(hsStream* s);  
    void    Write(hsStream* s) const;
};

//
// A state descriptor - describes the contents of a type of state buffer.
// There is one of these for each persistent object type.
// These descriptors are defined in a user-created .sdl file.
//
class plKey;
class plStateDescriptor
{
private:
    static const uint8_t kVersion;        // for Read/Write format
    typedef std::vector<plVarDescriptor*> VarsList; 
    VarsList fVarsList;
    int fVersion;
    char* fName;
    std::string fFilename;  // the filename this descriptor was read from

    void IDeInit();
public:
    plStateDescriptor() : fVersion(-1),fName(nil) {}
    ~plStateDescriptor(); 

    // getters
    const char* GetName() const { return fName; }
    int GetNumVars() const { return fVarsList.size(); }
    plVarDescriptor* GetVar(int i) const { return fVarsList[i]; }
    int GetVersion() const { return fVersion; }
    const char * GetFilename() const { return fFilename.c_str();}
    
    // setters
    void SetVersion(int v) { fVersion=v; }
    void SetName(const char* n) { delete [] fName; fName=hsStrcpy(n); }
    void AddVar(plVarDescriptor* v) { fVarsList.push_back(v); }
    void SetFilename( const char * n ) { fFilename=n;}
    
    plVarDescriptor* FindVar(const char* name, int* idx=nil) const;

    // IO
    bool Read(hsStream* s); 
    void Write(hsStream* s) const;
};

#endif  // plSDL_DESC_inc