// AXControl.cpp: implementation of the CAXControl class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "afxpriv2.h"
#include "AXControl.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

void DispatchToCValue(IUnknown* pUnk,CValue* pVal)
{
	pVal->Reset();
	IDispatchPtr pDisp;
	if(pUnk){
		pUnk->QueryInterface(IID_IDispatch,(void**)&pDisp);
		if(pDisp!=NULL)
		{
			VARIANT var;
			var.vt=VT_DISPATCH;
			var.pdispVal=pDisp;
			DISPPARAMS disp={&var,NULL,1,0};
			CValue* ppVal[]={pVal};
			UINT ui;
			((CBLMyEx*)NULL)->DispParamToValueEx(ppVal,&disp,&ui);
			VariantClear(&var);
		}
	}
}

extern CBkEndUI * pBkEndUI;

BEGIN_BL_METH_MAP(CAXControl)
    BL_METH("AssignAttrib", "УстановитьАтрибут", 2, methAssignAttrib, NULL, NULL)
    BL_METH("CreateControl", "СоздатьЭУ", 1, NULL, methCreateControl, NULL)
    BL_METH("SetFocus", "УстановитьФокус", 0, methSetFocus, NULL, NULL)
    BL_METH("Destroy", "Уничтожить", 0, methDestroy, NULL, NULL)
END_BL_METH_MAP()

BEGIN_BL_PROP_MAP(CAXControl)
    BL_PROP("Object", "Объект", GetPropObject, NULL)
    BL_PROP("EventProcessing", "ОбработкаСобытий", GetPropEventProcessing, SetPropEventProcessing)
END_BL_PROP_MAP()

IMPLEMENT_MY_CONTEXT(CAXControl, "AXControl", "АктивИкс", 1, NULL, NULL, 3);
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CAXControl::CAXControl()
{
	m_Form=NULL;
	m_pCtrlWnd=NULL;
	m_pParentWnd=NULL;
}

CAXControl::~CAXControl()
{
	if(m_Form) m_Form->DecrRef();
	m_Form = NULL;
	if(m_pCtrlWnd) m_pCtrlWnd->DestroyWindow();
	//CoFreeUnusedLibraries();
}

BOOL CAXControl::methAssignAttrib(CValue **params)
{
	CBLContext* pBLCont = params[0]->GetContext();
	if (pBLCont)
	{
		if(!strcmp(pBLCont->GetRuntimeClass()->m_lpszClassName,"CFormAllCtrlsContext"))
		{
			if(m_Form) m_Form->DecrRef();
			m_Form = (CFormAllCtrlsContext*)pBLCont;
			m_Form->IncrRef();
			CGetDoc7* pDoc = (CGetDoc7*)m_Form->m_GetDoc;
			CGetFieldsArray* pGetFieldsArray = (CGetFieldsArray*)(&(((CGetDoc77*)pDoc)->m_Array));
			char* str = (char*)(LPCSTR)params[1]->GetString();
			int num=-1;
			for(int i = 0; i<pGetFieldsArray->GetSize(); i++)
			{
				CGetField* pGetField = pGetFieldsArray->GetAt(i);
				char* pCodeName = (char*)pGetField->GetCtrlInfo()->GetCodeName();
				if(!strcmp(str,pCodeName)) num = i;
			}
			if(num<0)
			{
				num = 0;
				if(m_Form) m_Form->DecrRef();
				m_Form = NULL;
				RuntimeError("Неверный идентификатор атрибута");
				return S_FALSE;
			}
			CGetField* pGetField = pGetFieldsArray->GetAt(num);
		    m_pParentWnd = pDoc->GetFieldWnd(pGetField);
			m_pCtrlWnd=new CAXControlWnd();
			m_pCtrlWnd->m_iEventProcessing=1;
			m_pCtrlWnd->m_pDoc=pDoc;
		    CControlID* pControlID = pGetField->GetCtrlInfo();
			m_pCtrlWnd->m_ControlID = pControlID->GetCodeName();
		}else{
			RuntimeError("Неверно указана форма");
		}
	}else{
		RuntimeError("Не указана форма");
	}
	return TRUE;
}

BOOL CAXControl::methCreateControl(CValue &RetVal, CValue **params)
{
	CString className=params[0]->GetString();
	className.TrimRight();
	CRect rect;
	if(m_pParentWnd)
		m_pParentWnd->GetClientRect(&rect);
	else{
		RuntimeError("Не задан родительский элемент управления");
		return FALSE;
	}
	if(m_pCtrlWnd->CreateControl((LPCTSTR )className,NULL,WS_VISIBLE|WS_TABSTOP|WS_CHILD,rect,m_pParentWnd,1,NULL,FALSE,NULL))
	{
		LPUNKNOWN iUnkControl=m_pCtrlWnd->GetControlUnknown();
		iUnkControl->AddRef();
		DispatchToCValue(iUnkControl,&RetVal);
		m_pCtrlWnd->m_iEventProcessing=1;
		m_pCtrlWnd->SetupEventHandlers();
		
		return TRUE;
	}else{
		RuntimeError("Создание элемента управления %s не удалось",className);
		return FALSE;
	}
}

BOOL CAXControl::methDestroy(CValue **params)
{
	if(m_pCtrlWnd) m_pCtrlWnd->DestroyWindow();
	return TRUE;
}

BOOL CAXControl::methSetFocus(CValue **params)
{
	if(m_pCtrlWnd) SetFocus(m_pCtrlWnd->m_hWnd);
	return TRUE;
}

BOOL CAXControl::SetPropObject(CValue const& Value)
{
	if(IS_BLTYPE(Value,CStdOleBLContext)){
/*		CStdOleBLContext *cont=((CStdOleBLContext*)(Value.GetContext()));
		IOleObject *iOleObj;
		cont->m_IUnknown->QueryInterface(IID_IOleObject,(void**)&iOleObj);
		COleControlSite *pSite = afxOccManager->CreateSite(pControlWnd->m_pCtrlCont);
		pSite->m_pWndCtrl = m_pCtrlWnd;
		//pSite->m_hWnd= m_pCtrlWnd->m_hWnd;
		m_pCtrlWnd->m_pCtrlSite = pSite;
		_AFX_THREAD_STATE* pState = AfxGetThreadState();
		if (!pState->m_bNeedTerm && !AfxOleInit())
			return FALSE;
		pSite->m_pObject = iOleObj;
		pSite->QuickActivate();
		iOleObj->SetClientSite(&(pSite->m_xOleClientSite));
		HWND hWnd = NULL;
		cont->m_IUnknown->QueryInterface(IID_IOleInPlaceObject,
				(LPVOID*)&(pSite->m_pInPlaceObject));
		if (SUCCEEDED(pSite->m_pInPlaceObject->GetWindow(&hWnd)))
		{
			if (pSite->m_hWnd != hWnd)
			{
				pSite->m_hWnd = hWnd;
				if (pSite->m_pWndCtrl != NULL)
					pSite->m_pWndCtrl->Attach(pSite->m_hWnd);
			}
		}
		pControlWnd->m_pCtrlCont->m_siteMap.SetAt(pSite->m_hWnd, pSite);
		/**/
	}
	return TRUE;
}

BOOL CAXControl::GetPropObject(CValue &Value) const
{
	LPUNKNOWN iUnkControl=m_pCtrlWnd->GetControlUnknown();
	iUnkControl->AddRef();
	DispatchToCValue(iUnkControl,&Value);
	return TRUE;
}
/*
BOOL CAXControl::CreateControl(CWnd* pFrame, CGetDoc7* pDoc, CGetField* pGetField, CValue& vControl)
{
    if (pGetField == NULL || pGetField->GetCtrlInfo()->m_CtrlType != HOSTING_CONTROL_TYPE)
    {
        RuntimeError("Недопустимый атрибут формы.");
        return FALSE;
    }
    CAXControl* pAXControl = NULL;
    CBLContext* pControl = NULL;
	BOOL bIsComponentClass = FALSE;

    if (IS_BLTYPE(vControl,CComponentClass))
    {
        CBLContext* pAXControlCtx;
        if (static_cast<CComponentClass*>(vControl.GetContext())->GetBaseClass(RUNTIME_CLASS(CAXControl), &pAXControlCtx))
        {
            pAXControl = static_cast<CAXControl*>(pAXControlCtx);
			bIsComponentClass = TRUE;
        }
    }
	else if(IS_BLTYPE(vControl,CAXControl))
	{
		pAXControl=static_cast<CAXControl*>(vControl.GetContext());
	}
    else if (vControl.GetTypeCode() == UNDEFINE_TYPE_1C)
    {
        pAXControl = new CAXControl;
        vControl.AssignContext(pAXControl);
        pAXControl->DecrRef();
    }
    if (!pAXControl)
    {
        RuntimeError("Недопустимый объект ЭУ.", 0);
        return FALSE;
    }
    CControlID* pControlID = pGetField->GetCtrlInfo();
    pAXControl->m_pParentWnd = (CAXControlWnd*)pDoc->GetFieldWnd(pGetField);
	pAXControl->m_pCtrlWnd = new CAXControlWnd;
	if(bIsComponentClass)
		pAXControl->m_pCtrlWnd->m_pComponentBLModule=((CComponentClass*)(vControl.GetContext()))->GetModule();
	pAXControl->m_pCtrlWnd->m_pDoc=pDoc;
	pAXControl->m_pCtrlWnd->m_ControlID = pControlID->GetCodeName();
    return TRUE;
}
*/
BOOL CAXControl::CreateControlWnd(CWnd* pParent, CGetDoc7* pDoc, CGetField* pGetField, CBLContext* pUDC)
{
    if (pGetField == NULL || pGetField->GetCtrlInfo()->m_CtrlType != HOSTING_CONTROL_TYPE)
    {
        RuntimeError("Недопустимый атрибут формы.");
        return FALSE;
    }

    CControlID* pControlID = pGetField->GetCtrlInfo();
    m_pParentWnd = (CAXControlWnd*)pDoc->GetFieldWnd(pGetField);
	m_pCtrlWnd = new CAXControlWnd;
	if(pUDC)
		m_pCtrlWnd->m_pComponentBLModule=((CComponentClass*)(pUDC))->GetModule();
	m_pCtrlWnd->m_pDoc=pDoc;
	m_pCtrlWnd->m_ControlID = pControlID->GetCodeName();
    return TRUE;
}

BOOL CAXControl::_Create(CValue** ppValue)
{
	methAssignAttrib(ppValue);
	CValue RetVal;
	methCreateControl(RetVal,&ppValue[2]);
	return TRUE;
}

CAXControlWnd::CAXControlWnd()
{
	m_pComponentBLModule=NULL;
	m_EventHandlers = new CDispIdToProcIdMap(10);
	m_ComponentEventHandlers = new CDispIdToProcIdMap(10);
}

void CAXControlWnd::SetupEventHandlers(){
	IProvideClassInfoPtr pPCI;
	ITypeInfoPtr pClassInfo;
	ITypeInfoPtr pTypeInfo;
	TYPEATTR *pTypeAttr;

	LPUNKNOWN iUnkControl = GetControlUnknown();
	iUnkControl->QueryInterface(IID_IProvideClassInfo,(void**)&pPCI);
	pPCI->GetClassInfo( &pClassInfo );
	
	pClassInfo->GetTypeAttr( &pTypeAttr );
	BOOL tFoundDefaultSource = FALSE;
	UINT iType;
	HREFTYPE hRefType;
	HRESULT hResult;
	int iFlags;
	for( iType = 0; (iType < pTypeAttr->cImplTypes) && !tFoundDefaultSource; iType++ )
	{
		hResult = pClassInfo->GetImplTypeFlags( iType, &iFlags );
		if( SUCCEEDED( hResult ) )
		{
			if( (iFlags&IMPLTYPE_MASK) == IMPLTYPE_DEFAULTSOURCE )
			{
				tFoundDefaultSource = TRUE;
				hResult = pClassInfo->GetRefTypeOfImplType( iType, &hRefType );
				hResult = pClassInfo->GetRefTypeInfo( hRefType, &pTypeInfo );
				int iMethod;
				UINT nNames;
				
				TYPEATTR* pta;
				FUNCDESC* pfd;
				hResult = pTypeInfo->GetTypeAttr( &pta );
				
				for( iMethod = 0; iMethod < pta->cFuncs; iMethod++ )
				{
					hResult = pTypeInfo->GetFuncDesc( iMethod, &pfd );
					
					if( !(pfd->wFuncFlags&FUNCFLAG_FRESTRICTED) &&
						(pfd->funckind == FUNC_DISPATCH) )
					{
						BSTR pbstrNames[1]={NULL};
						hResult = pTypeInfo->GetNames( pfd->memid, pbstrNames, 1,&nNames );
						CBLModule7 *pMod = m_pDoc->m_pBLModule;
						int r = -1;
						if(pMod)
						{
							CString nameProc=m_ControlID;
							nameProc+="_";
							nameProc+=pbstrNames[0];
							r = pMod->FindProc((LPCTSTR)nameProc,0);
							if(r<0)
								r = pMod->FindFunc((LPCTSTR)nameProc);
							if(r>0){
								EventInfo ei={r,pfd->cParams};
								m_EventHandlers->SetAt(pfd->memid,ei);
							}
						}
						if(m_pComponentBLModule){
							CString nameProc=pbstrNames[0];
							r = m_pComponentBLModule->FindProc((LPCTSTR)nameProc,0);
							if(r<0)
								r = m_pComponentBLModule->FindFunc((LPCTSTR)nameProc);
							if(r>0){
								EventInfo ei={r,pfd->cParams};
								m_ComponentEventHandlers->SetAt(pfd->memid,ei);
							}
						}
					}
				}
			}
		}
	}
}

void CAXControlWnd::CallEventHandler(EventInfo ei, CValue** lArray, CBLModule7* pModule)
{
	if(ei.procid>0)
	{
		CBLProcInfo cblProcInfo;
		if(pModule->GetProcInfo(ei.procid,cblProcInfo))
		{
			int newArgNum = cblProcInfo.GetNParams();
			if(newArgNum > ei.argNum) newArgNum = ei.argNum;
			int t = cblProcInfo.GetType();

			CGetCtrl* pCurCtrl=m_pDoc->GetActiveCtl();
			if(pCurCtrl) pCurCtrl->DeActivate();
			m_pDoc->OnStartBatch();
			if(t == 1)
				pModule->CallAsProc(ei.procid,newArgNum,lArray);
			else
			{
				CValue arValue;
				pModule->CallAsFunc(ei.procid,arValue,newArgNum,lArray);
			}
			m_pDoc->OnEndBatch(1);
		}
	}

}
/**/

BOOL CAXControlWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo)
{
	if(m_iEventProcessing){
		if(nCode == CN_EVENT){
			AFX_EVENT* pEvent=(AFX_EVENT*)pExtra;
			if(pEvent->m_eventKind == AFX_EVENT::event){
				EventInfo ei;
				BOOL foundModuleHandler=m_EventHandlers->Lookup(pEvent->m_dispid,ei);
				BOOL foundComponentHandler=FALSE;
				if(m_pComponentBLModule){
					foundComponentHandler=m_ComponentEventHandlers->Lookup(pEvent->m_dispid,ei);
				}
				if(foundModuleHandler || foundComponentHandler){
					CValue p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
					CValue *lArray[10]={&p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10};
					UINT ui;
					((CBLMyEx*)NULL)->DispParamToValueEx(lArray,pEvent->m_pDispParams,&ui);
					if(foundComponentHandler){
						CallEventHandler(ei,lArray,(CBLModule7*)m_pComponentBLModule);
					}
					if(foundModuleHandler){
						CallEventHandler(ei,lArray,&(m_pDoc->m_cBLModule7));
					}
					for(int i=0;i<pEvent->m_pDispParams->cArgs;i++){
						VARIANTARG v=pEvent->m_pDispParams->rgvarg[i];
						if(v.vt & VT_BYREF){
							CValue RetValue=*(lArray[pEvent->m_pDispParams->cArgs-i-1]);
							if((RetValue.type==1) || (RetValue.type==2) || (RetValue.type==3)){
								((CBLMyEx*)NULL)->ValueToVariantEx(RetValue,pEvent->m_pDispParams->rgvarg[i].pvarVal);
							}
						}
					}
				}
			}else if(pEvent->m_eventKind == AFX_EVENT::propChanged){
				//Msg("%s_propChanged(dispid=%i)", m_ControlID, pEvent->m_dispid);
			}else if(pEvent->m_eventKind == AFX_EVENT::propDSCNotify){
				//Msg("%s_DSCNotify(DSCSTATE=%i,DSCREASON=%i)", m_ControlID, pEvent->m_nDSCState, pEvent->m_nDSCReason);
			}
		}
		return FALSE;
	}else{
		return FALSE;
	}
}
