  // ComponentClass.h: interface for the CComponentClass class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_COMPONENTCLASS_H__5F1978A2_67C1_4AAB_8C12_44790D3700B2__INCLUDED_)
#define AFX_COMPONENTCLASS_H__5F1978A2_67C1_4AAB_8C12_44790D3700B2__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "stdafx.h"

#include "MapDefMethod.h"
#include "CodeDecodeFile.h"
#include "paramdefs.h"
#include "AddIn.h"
#include "ModuleString.h"
#include "BLModuleWrapper.h"
#include "OXY_Value.h"
#include "SetOfHierarchy.h"
//#include "BaseClassContext.h"

//kms
#include "SafeContext.h"

extern CBkEndUI * pBkEndUI;

// пока закомментарил
//typedef class CArray<CBLModule7*,CBLModule7*> CBLModuleArray;
/*
// простой класс-указатель
template <class Type>
class TPtr{
  Type* p;
public:
  TPtr(Type* src){p=src;}
  Type* operator ->(){return p;}
  operator Type*(){return p;}
};

// умный класс-указатель
// автоматически создает объекты через new
// а в деструкторе удаляет
// удобно использовать для стековых локальных объектов
//
template <class Type>
class TMP{
  Type* p;
public:
  TMP(){
  p=new Type();
  }
  TMP(const Type& value)
  { p=new Type(value); }
  ~TMP(){
  delete p;
  }
  Type* operator ->(){if (!p) puts("NULL обращение"); return p;}
  operator Type*(){if (!p) puts("NULL обращение"); return p;}
};
*/

//void RuntimeError(const char *msg, ...);
//void Msg(char *msg, ...);

// класс для работы с исключениями 1С
class CRuntimeExceptionClass
{
private:
	CRuntimeExceptionClass() {}; // класс нельзя создать
	
	static bool isExceptionStatus;
	static CString strTextException;
	static CValue* ExceptionValue;
	
	//static CBLModule7* pMod;
	static CSafeModulePtr pMod;
	static int iRuntimeErrLineNum;
	static CString m_strModulePath;
	static DWORD m_nID; // -1 или 0
	static bool m_bStatusOfTryingBlock; // флаг, находимся ли в блоке Попытка-Исключение
public:
  static void Init(void);
  static void Destroy(void);
  
  static void Empty(void);

  // запомнить исключение и данные о нем
  static void SetException(const CString& strExceptionA);
  static void SetException(const CString& strExceptionA, CBLModule7* pModA, 
	  DWORD m_nIDA, const CString& m_strModulePathA, int iRuntimeErrLineNumA);

  // выбросить исключение для пользовательских классов 1C++
  static void ThrowException(bool isThrow = true);
  static void ThrowException(const CString& strException);
  static void IfNeedExceptionThenThrowException(void);

  // выбросить исключение, запомнив переданный объект. Сообщение об ошибке будет пустое
  static void RuntimeError(const CValue& param);
  // выбросить исключение, запомнив переданный объект. Сообщение об ошибке будет равно указанному
  static void RuntimeError(const CValue& param, const CString& strTextException);
  // получить ранее сохраненный объект-исключение
  static void GetException(class CValue & rValue);

  // получить флаг, находимся ли в блоке Попытка-Исключение
  static void SaveStatusOfTryingBlock(void);
  static bool GetStatusOfTryingBlock(void);

  // проверить, не находимся ли мы в блоке Попытка-Исключение
  static bool IsInsideTryingBlock(void);

};

// класс С++ для работы с пользовательскими классами (КОП)
class CComponentClass : public CBLContext
{
friend class CImplicitParams;

DECLARE_DYNCREATE(CComponentClass);

private:

	static void GetFullTypeName(CBLContext *pCont, CString& rus, CString& eng, bool bAddKind = true);
	static void GetFullTypeName(CBLContext *pCont, CString& rus, CString& eng,
		CString& rusKind, bool bAddKind = true); // artbear

	inline int ReplaceInstBaseClasses(const CValue &NameClass, const CValue &Instance, CValue &rValue);

	inline int IsObject(const CValue &NameClass, CValue &rValue) const;

public:

	inline int GetBaseClass(const CValue &NameClass, CValue & rValue) const;
	BOOL GetBaseClass(const CRuntimeClass* pRTClass, CBLContext** ppBaseObj) const;
    template <class T>
    BOOL GetBaseClass(T** ppT) const
    {
        for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != vecOfBaseCont.end(); ++iter)
        {
			CBLContext *pCont = *iter;
            if ((pCont)->GetRuntimeClass() == RUNTIME_CLASS(CComponentClass))
            {
				// artbear
                //if (static_cast<CComponentClass*>(*iter)->GetBaseClass(ppT))
//				PCBLContext pCont = *iter;
                if (static_cast<CComponentClass*>(pCont)->GetBaseClass(ppT))
                    return TRUE;
            }
            else
            {
				// artbear
                //T* p = dynamic_cast<T*>(*iter);
//				PCBLContext pCont = **iter;
                T* p = dynamic_cast<T*>(pCont);
                if (p)
                {
                    *ppT = p;
                    return TRUE;
                }
            }
        }
        return FALSE;
    };
	CBLModule * GetModule() const;
	CBLModule * GetHostModule() const;

private:
	void InvokeConstructor();

  virtual CBLModule* Init(const char* file);
  virtual CComponentClassModulePtr FirstInit(const CString& FullFileName);

public:
	CComponentClass();
	virtual ~CComponentClass();

private:
  enum {
	  funcGetBaseClass,
	  procAssignFriendModule,

	  // этот функционал закрыт общее решение artbear
	  // TODO возможно, в дальнейшем он должен быть открыт внутри класса, а снаружи невидим
	  //
	  //procAddBaseClass,

	  funcSendMessageOwnMod,
	  funcGetPathName,

	  funcGetEnvContext,
	  funcGetParamsList,

	  funcReplaceInstBaseClasses,
	  funcReplaceInstBaseClasses_SYN1,

	  funcSetOnIndexParams,
	  procOnOpen,
	  procThrow,
	  funcIsObject,
	  //procDoWrapEventsOfGroupContext,
	  lastMethod
	};
public:

  virtual int  CallAsFunc(int,class CValue &,class CValue * *);	//935
	virtual int  CallAsProc(int,class CValue * *);	//937
	virtual void  DecrRef(void);	//1086
	virtual int  FindMethod(char const *)const;	//1366
	virtual int  FindProp(char const *)const;	//1369
	virtual char const *  GetCode(void)const;	//1544
	//virtual int  GetDestroyUnRefd(void)const;	//1657
	//virtual void  GetExactValue(class CValue &);	//1708
	virtual class CObjID   GetID(void)const;	//1804
	virtual class CBLContextInternalData *  GetInternalData(void);	//1826
	virtual char const *  GetMethodName(int,int)const;	//1964
	virtual int  GetNMethods(void)const;	//2005
	virtual int  GetNParams(int)const;	//2008
	virtual int  GetNProps(void)const;	//2015
	virtual int  GetParamDefValue(int,int,class CValue *)const;	//2122
	virtual char const *  GetPropName(int,int)const;	//2187
	virtual int  GetPropVal(int,class CValue &)const;	//2221
	virtual long  GetTypeID(void)const;	//2505
	virtual char const *  GetTypeString(void)const;	//2513
	virtual class CType   GetValueType(void)const;	//2547
	virtual int  HasRetVal(int)const;	//2657
	virtual void  IncrRef(void);	//2668
	// virtual void  InitObject(class CType const &);	//2721 // artbear не нужно - там стоит тупой вызов метода из базового класса
	virtual void  InitObject(char const *);	//2722
	virtual int  IsExactValue(void)const;	//2808
	virtual int  IsOleContext(void)const;	//2846
	virtual int  IsPropReadable(int)const;	//2863
	virtual int  IsPropWritable(int)const;	//2865
	virtual int  IsSerializable(void);	//2874
	virtual int  SaveToString(class CString &);	//3295
	virtual void  SelectByID(class CObjID,long);	//3350
	virtual int  SetPropVal(int,class CValue const &);	//3694

	static CComponentClass* GetComponentClassCurExModule(CBLModule* pModWrapper = NULL);

	static bool StillInitInstanceComp() {return pCreatedCompModule != NULL;}

	static void ClearOptimizationData(void);

	// метод для вызова пользовательского конструктора с несколькими параметрами
	// используется в методе ФабрикаОбъектов::Новый()
	void CallUserConstructor(const CString&  strConstructorName, int nParamsCount, CValue **ppValue) const;

	// флаг создания без вызова дефолтного конструктора, даже если он есть в модуле
	// удобно для использования с методом ФабрикаОбъектов::Новый()
	//
	static void SetFlagCreateWithoutConstructor(void) { bFlagCreateWithoutConstructor = true; }
	static void ClearFlagCreateWithoutConstructor(void) { bFlagCreateWithoutConstructor = false; }
private:
	static bool bFlagCreateWithoutConstructor;

private:

	// карта методов, используется для оптимизации
	static class CMapDefMethod MapDef;

	// проверить, является ли текущий исполняемый модуль модулем базового класса для текущего класса
	// используется для исключения рекурсии
	CComponentClass* VerifyCurrentExecuteContextIsBaseClassForThisClass() const;

	// Выполняет инициализацию экземпляра класса на основе информации полученной
	// из файла составленного пользователем
	void InitInstanceComp(void);

	friend class CInitGuard;
	void OnStartInit(void);
	void OnEndInit(bool bIsBadExit = false);
	void FinishInit(void);

	bool m_bDonNotCallDestructor;
	void SetFlagDonNotCallDestructor() { m_bDonNotCallDestructor = true; };

	//CBLModule *pMod;
	CSafeModulePtr m_pMod;
	//CComponentClassModulePtr m_pModLocale;
	mutable CMapStringToPtr   m_BindInstaceValueList;

	static class CObjID ObjID;

	bool AddBaseClass(const CString& name);
	void ClearAllBasesClass();
	
	void ReplaceContextInModulesOfBaseClasses(CComponentClass* pMainCont =  NULL);

  // найти метод класса по названию
  // сначала ищется в модуле класса на случай, если задан без Экспорт
  // а затем в экспортируемых методах класса, затем в наследниках
  //
  // сначала ищется русское имя, а затем английское
  //
  static int FindMethod(CBLContext* pContext, CBLModule *pMod, LPCTSTR sNameRus, LPCTSTR sNameEng);

  // тоже самое, но для текущего класса
  inline int FindMethod(CBLModule *pMod, LPCTSTR sNameRus, LPCTSTR sNameEng) const
  {
	return CComponentClass::FindMethod((CBLContext*)this, pMod, sNameRus, sNameEng);
  };

public:

  //class CParamDefs * GetDefFnNamesPtr(void) const
  CParamDefsWithRefCountPtr GetDefFnNamesPtr(void) const
  { return defFnNames; }
  
  CMapStringToPtr& GetBindInstanceValueList() const
  { return m_BindInstaceValueList; }
	
//protected:

  //CBLModule  *pCurModule;
  CSafeModulePtr pCurModule; // модуль, в котором объект был создан
private:

	CString m_NameOfInstance;

  vector<CSafeContextPtr<CBLContext> > vecOfBaseCont;
  typedef vector<CSafeContextPtr<CBLContext> >::const_iterator CONST_ITER_CONT;
  typedef vector<CSafeContextPtr<CBLContext> >::iterator ITER_CONT;

  //class CParamDefs *defFnNames;
  CParamDefsWithRefCountPtr defFnNames;
  struct MethParamsDef
  {
    int nNumberOfMeth;
    int nRealNumberOfMeth;
    CBLContext* pContext;
  };
  mutable MethParamsDef m_MethParamsDef;
  //unsigned char *pPoint;

  inline int CallAsMethod(int iMethNum, CValue * *ppValue, bool bHasRetVal = false, CValue * pRetValue = NULL);

  bool m_isCreateOptimizeMode;

  // Карта с указателями на модули с их реальными контекстами
  // Ключ - указатель на модуль, Значение - указателя на контекст CComponentClass
  static CMapPtrToPtr m_MapOfModulesAndComp;

	// Указатель на текущий создаваемый объекта КОП
	// Необходим для установки его как контекста во всех модулях иерархии
	static CComponentClass* pCreatedCompModule;
/*
//public:
  // Карта с указателями на контексты с их модулями
  // Ключ - указатель на на контекст CComponentClass, Значение - указатель на модуль 
  //	pMod->GetInternalData()->pGeneralContext
  // pGeneralContext это будет ключ, а pMod - значение
  // нужно для правильного получения контекстов классов и их предков
  //static CMap<CBLContext*, CBLContext*, CBLModule*, CBLModule*> m_MapOfContextOnModules;
	typedef vector<CSafeModulePtr> CVectorModulePtr;
	typedef CMap<CComponentClass*, CComponentClass*, CVectorModulePtr*, CVectorModulePtr*> CMapOfContextToModules;
//private:	
	static CMapOfContextToModules m_mapOfContextToModules; // карта связанных модулей

	//void LinkContext(CBLModule* pMod);
	//void UnlinkContext();
	//void ClearModulePtr(CSafeModulePtr* ptr);
	
	void LinkContext(const CSafeModulePtr& pMod);
	void UnlinkContext();
	static void ClearContextFromModule(const CSafeModulePtr& ptr);
*/
  // работа с отладкой
	class CDebug
	{
	public:
		static void SetDebugObject(CComponentClass *pComp);
		static void ClearDebugObject();

		bool IsDebug() const
		{ return NULL != pDebugContext; }

		operator bool() const
		{ return IsDebug(); }

		bool operator !() const
		{ return !IsDebug(); }

		void Release(void);

		void OpenDebugForm(CComponentClass* pComponent);

		//void AssignDebugModule(CBLContext* pComponent, CBLModule*& pMod);
		void AssignDebugModule(CBLContext* pComponent, CSafeModulePtr& pMod);
	private:
 		CSafeContextPtr<CBLContext> pDebugContext;

		static CComponentClass* m_CurDebugObject;

	};

	CDebug m_DebugInfo;

	  // Увязывает указатели на экземпляры классов с указателями на список значений парметров 
	  // полученных вместо точек в методе (...)
	  struct InfoUnlimitsParams
	  {
		CBLContext* cont_ValueList;
		vector<CValue*> vecPointOfPars;
		int         nNumAllParams;
		int         nNumExplicitParams;
	  };

	// CComponentClass::CImplicitParams - работа с неопределенным числом параметров
	class CImplicitParams
	{
	private:
	public:

		CString m_strClassAndMethImplicit;
		CString m_strClassAndMethCurrent;
		int m_CountParametersInCallMethod;
		
	public:
		CImplicitParams();

	  CBLContext* GetImplicitParamsList(CComponentClass *pComp, const char* lpcsNameMeth);

	  bool GetImplicitParams(CComponentClass *pComp, CValue **ppPar, int nNumMeth);
	  int SetImplicitParamOfInd(CComponentClass *pComp, const char* lpcsNameMeth, int nIndex, CValue* pVal);

	  int GetNParams(const CComponentClass *pComp, int nNumMeth, int nNParams);

	  typedef CArray<CValue*, CValue*> ARRAY_VAL;
	  typedef CArray<NameBindOfType*, NameBindOfType*> ARR_TYPE_NAME;

  // Восстанавливает параметры которые переданны в метод по значению после вызова
	void RestoreValParam(CComponentClass *pComponentClass, int nNumMeth, CValue **ppParam, ARRAY_VAL *arrValOfMeth);
  // Сохраняет параметры, которые переданны в метод по значению перед вызовом
	bool SaveValParam(CComponentClass* pComponentClass, int nNumMeth, CValue** ppParam, ARRAY_VAL *arrValOfMeth);

	private:
	  BOOL LookupInBindInstanceValueList(const CComponentClass* pComp, const CString& m_strClassAndMethCurrent, InfoUnlimitsParams *&pInfo) const;
	  //InfoUnlimitsParams * 
	  void* GetImplicitParamsInfo(CComponentClass *pComp, const char* lpcsNameMeth) const;
	};

	static CImplicitParams* pImplicitParams;

};

// указатель на КОП ?
//#define IS_KINDOF_CComponentClass(pCont) (IS_KINDOF_RUNTIME_CLASS(pCont, CComponentClass))

#endif // !defined(AFX_COMPONENTCLASS_H__5F1978A2_67C1_4AAB_8C12_44790D3700B2__INCLUDED_)
