#if !defined(_RUNTIMEENV_H)
#define _RUNTIMEENV_H

#include "PubHeader.h"
#include "Callback.h"
#include "otstr.h"
#include "CPlusbase.h"

/////////////////////////////////////////////////
// 变量运行环境
//
class ExecuteEnv;
class Program;
class Procedure;

#ifdef _DLL_PROJECT
template class CLASS_EXPORT TObArray<CVariableItem>;
template class CLASS_EXPORT TObArray<CVarient>;
template class CLASS_EXPORT TObArray<RunTimeStk>;
template class CLASS_EXPORT TObList<RunTimeStk>;
#endif


#ifdef _DLL_PROJECT
class CLASS_EXPORT RunTimeStk: public RunEnv
#else
class RunTimeStk: public RunEnv
#endif
{
public:
    RunTimeStk(RunTimeStk* pUpLinkedStk=NULL,RunTimeStk* pParentStk=NULL,Program* pProgram=NULL);
   ~RunTimeStk();

    /////////////////////////////////////////////////////
    void Attach(Program* pProgram);    // Attach后, 首先可以共享其全局数据, prepare后, 可以共享其变量
    void setExecuteEnv(ExecuteEnv* pExecuteEnv) { m_pExecuteEnv=pExecuteEnv; }
    
    Program* getProgram() { return m_pProgram; }
    Program* getAdjacentProgram();
    
    /////////////////////////////////////////////////////
    bool setn(char* varString, char*  lpstring, ...);  // 对数组,必须保证个数一致
    bool setn(char* varString, signed data, ...);
    bool setn(char* varString, double data, ...);
    bool setn(char* varString, OTSTR* lpOtstr, ...);
    
    bool sets(char* varString, char* szdata);  // " { {.. , ..}, ... } "
    bool sets(CVariableItem* pVariableItem, long nLastIdx, char* szdata);
        
    bool get(char* varString, OTSTR&  str,          bool* bDataSeted=NULL);
    bool get(char* varString, INT1&   return_data,  bool* bDataSeted=NULL);
    bool get(char* varString, INT2&   return_data,  bool* bDataSeted=NULL);
    bool get(char* varString, INT4&   return_data,  bool* bDataSeted=NULL);
    bool get(char* varString, UINT1&  return_data,  bool* bDataSeted=NULL);
    bool get(char* varString, UINT2&  return_data,  bool* bDataSeted=NULL);
    bool get(char* varString, UINT4&  return_data,  bool* bDataSeted=NULL);
    bool get(char* varString, double& return_data,  bool* bDataSeted=NULL);
    bool get(char* varString, CVarient& return_data,bool* bDataSeted=NULL);

    /////////////////////////////////////////////////////
    // Create and Get TVarientItem in Environment
    virtual CVariableItem* CreateVarInstance(VariableDefinition* pVariableDefinition,char* szNewname=NULL);
    virtual CVariableItem* CreateVarInstance(StructDefinition*   pStructDefinition,  char* varname); // varname[..]
    virtual CVariableItem* CreateVarInstance(VariableItemAttr::type_ nType, char* varname);          // varname[..]

    virtual bool           AddVarInstance(CVariableItem* pVariableItem);
    virtual CVariableItem* RemoveVarInstance(char* varname, bool bOnlyInCurrentEnv, bool bCaseSensitive=false); 
    virtual bool           RemoveVarInstance(CVariableItem* pVariableItem, bool bOnlyInCurrentEnv); 
    
    virtual CVariableItem* Get_VarInstance  (char* varname,bool bOnlyInCurrentEnv, bool bCaseSensitive=false); // varname为第一层的变量名 // Pri: cur > parent > include
    TObArray<CVarient>&    Get_ProcedureArgList() { return m_ProcedureArgList; }
        
    /////////////////////////////////////////////////////
    // RunTime CVariableItem Function
    CVariableItem* GetItem(char* varString,long* retlastIdx=NULL);  // lastIdx=-1 mean noIdx or All array[], when lastIdx==NULL, 最后一个不能有[...]
    CVariableItem* GetRootVariableItem(char* varString,bool bPrintErrorInfo=true);

    /////////////////////////////////////////////////////
    static DWORD   RunTimeProc(void* pParent, unsigned int params_num, DWORD params[]);
    cCallback::tFunction GetRunTimeProc() { return RunTimeStk::RunTimeProc; }
    
protected:
    Program*    m_pProgram;    
    ExecuteEnv* m_pExecuteEnv;
    RunTimeStk* m_pParentStk; 

    ///////////////////////////////////////////////
    bool                    m_bPrepared;
    bool                    m_bPreExecuted;

    TObArray<CVariableItem> m_VarInstanceList;
    TObArray<CVarient>      m_ProcedureArgList;

    TObArray<RunTimeStk>    m_RunTimeStkList;         // 指针(相互引用时,指针可以有多个,实体只能有一个)
    TObArray<RunTimeStk>    m_RunTimeStkObjectList;   // 实体
    
private:
    RunTimeStk* GetParentStk() { return m_pParentStk; }
    RunTimeStk* FindRunTimeStk(Program* pProgram);
    
    bool Prepare(TObArray<CVariableItem>* pProcedureParamsList,TObArray<CVarient>* pProcedureArgList,bool bClearListAfterPrepare=true);    // 用于创建全局变量
    bool PreExecute(ExecuteEnv* pExecuteEnv); // 执行全局语句
    
    void Dump(FILE* fp, OTSTR strHeader);
    void Clear();

    friend class CVariableItem;
    friend class CStruct;
    friend class ExecuteEnv;
};

///////////////////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
class CLASS_EXPORT ExecuteEnv: public TObject
#else
class ExecuteEnv: public TObject
#endif
{
public:
    ExecuteEnv();
   ~ExecuteEnv();

    bool  Prepare(Program* pRootProgram);           // 创建全局变量, 执行全局语句

    bool  ExecuteProgram  (Program* pProgram);      // 在自身环境或ROOT环境下运行, 创建StackList, 调用Execute
    bool  ExecuteProcedure(Procedure* pProcedure,char* szParams,CVarient* pVarientReturn=NULL);  // 在Procedure的父环境下运行, 创建StackList, 调用Execute

    bool  Execute(Procedure* pProcedure,char* szParams,CVarient* pVarientReturn);  // 在当前环境下运行
    
    ////////////////////////////////////////////////////
    // CALLBACK Procedure: [0] pEnv 
    //                     [1] pProcedure
    //                     [2] nParam
    //          Ident      [0] pEnv
    //                     ...
    // bRunIndependent: true  不使用当前环境stk
    //                  false 在当前环境下运行
    void  setCallback_ExternalProcedure(void* handler, bool bRunIndependent, cCallback::tFunction pFunctionPointer,DWORD nParam=0);
    void  setCallback_ExternalIdent(void* handler, cCallback::tFunction pFunctionPointer,DWORD nParam=0);

    bool  Dump(char* filename,bool bOverWrite);

    char* GetLastError()   { return m_strLastError.GetBuffer(); }
    void  ClearLastError() { m_strLastError=""; }
    
protected:
    bool  Execute(Program*   pProgram);   // 在当前环境下运行
    
    //////////////////////////////////////////////////
    //////////////////////////////////////////////////
    // Used For Execute
    TObList<RunTimeStk>  m_RunTimeStackList;

public:    
    Waiter*              m_pWaiter;
    OTSTR                m_strlevel;
    bool                 m_bRunning;
    
    bool                 m_bCanceled;
    
    /////////////////////////////////////////
    // for Procedure
    bool                 m_bReturned;
    CVarient             m_VarientReturn;   
    
    /////////////////////////////////////////
    // for While
    bool                 m_bBreaked;
    bool                 m_bContinue;

    /////////////////////////////////////////
    void setWait(Waiter* pWaiter) { m_pWaiter=pWaiter; }

    void setCanceled();
    
    void PushStk(RunTimeStk* pRunTimeStk);
    bool PushStk(RunTimeStk* pRunTimeStk, bool bPrePareIt); // For add external stack
    bool PopStk (RunTimeStk* pRunTimeStk, bool bDelObject);
    RunTimeStk* GetTopStk(int OffsetFromTop=0);

    RunTimeStk* GetRootEnvStk() { return m_pRootStk; }
    
    void SetLastError(const char* pszFormat, ...);
    
protected:
    //////////////////////////////////////////////////
    RunTimeStk* m_pRootStk;

    OTSTR       m_strLastError;
    
    cCallback   m_Callback_ExternalProcedure;
    cCallback   m_Callback_ExternalIdent;

    bool        m_bExternalProceRunIndependent;
    DWORD       m_nParam_ExternalProcedure;
    DWORD       m_nParam_ExternalIdent;
    
    //////////////////////////////////////////////////
    bool DumpStackList(TObList<RunTimeStk>& stackList, char* filename,bool bOverWrite);

    void Clear(bool bClearPreparedEnv=true,bool bClearLastError=true);

private:
    friend class RunTimeStk;
    friend class Procedure;
    friend class Program;
    friend class TVariableItem;
    friend class Statement_if;
    friend class Statement_while;
};


#endif
