/////////////////////////////////////////////////////////////////////////////
//
//       
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <afxctl.h>
#include <afxpriv.h>
#include "ABaseEvent.h"

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

//-------------------------------------------------------------------------------
//  
// ---
CObList& ABaseEvent::m_EventList = *new CObList();

extern ABaseEvent * NewApplicationEvent  ();
extern ABaseEvent * NewDocumentEvent     ( LPDISPATCH doc );
class PropertyManagerObject;
 
extern ABaseEvent * NewDocumentFrameEvent( LPDISPATCH doc, LPDISPATCH frame, PropertyManagerObject & obj );
extern IApplicationPtr newKompasAPI;


//-----------------------------------------------------------------------------
//    
// ---
bool IsSame( LPUNKNOWN obj1, LPUNKNOWN obj2 )
{
  bool res = obj1 == obj2;
  if ( !res && obj1 && obj2 ) // ,        
  {
    LPUNKNOWN unk1 = NULL;
    obj1->QueryInterface( IID_IUnknown, (void **)&unk1 );
    if ( unk1 )
    {
      res = unk1 == obj2;
      if ( !res )
      {
        LPUNKNOWN unk2 = NULL;
        obj2->QueryInterface( IID_IUnknown, (void **)&unk2 );
        if ( unk2 )
        {
          res = unk1 == unk2;
          unk2->Release();
        }
      }
      unk1->Release();
    }  
  } 
  return res;
} 


/////////////////////////////////////////////////////////////////////////////
//
//      
//
/////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------
//  
// ---
ABaseEvent::ABaseEvent( LPUNKNOWN    pObject, 
                        IID          iidEvents,
                        LPDISPATCH   doc,      /*NULL*/
                        long         objType,  /*-1*/
                        LPDISPATCH   obj3D     /*NULL*/ ) 
  : CCmdTarget  (           ),  
    m_dwCookie  ( 0         ),
    m_pContainer( pObject   ),                 //  
    m_iidEvents ( iidEvents ),                 // IID
    m_pConnPt   ( NULL      ),
    m_doc       ( doc       ),                 // 
    m_objType   ( objType   ),                 //  
    m_obj3D     ( obj3D     )                  //   3D
{
  if ( m_pContainer ) 
    m_pContainer->AddRef();
  
  if ( m_doc )
	  m_doc->AddRef();

  if ( m_obj3D )
	  m_obj3D->AddRef();

  ASSERT( !IsEqualIID(m_iidEvents, GUID_NULL) ); //   
  m_EventList.AddTail( this ); 
}


//-------------------------------------------------------------------------------
// 
// ---
ABaseEvent::~ABaseEvent()
{
	RemoveThis();
  if ( m_pContainer ) 
  {
    m_pContainer->Release();
	  m_pContainer = NULL;     
  }
  
  if ( m_doc ) 
  {
	  m_doc->Release();
		m_doc = NULL;
	}

 if ( m_obj3D ) 
  {
	  m_obj3D->Release();
		m_obj3D = NULL;
	}
}


//-------------------------------------------------------------------------------
//     
// ---
void ABaseEvent::RemoveThis() {
	//      
	POSITION pos = m_EventList.Find(this);
  if ( pos ) { 
  	m_EventList.RemoveAt( pos );
    Unadvise();                           //    
  }
}


//-------------------------------------------------------------------------------
//  
// ---
void ABaseEvent::DestroyList() {
  if ( &m_EventList ) {
    delete &m_EventList;
  }
}


//-------------------------------------------------------------------------------
// 
// ---
void ABaseEvent::Clear() 
{
  if ( m_pContainer ) 
  {
    m_pContainer->Release();
	  m_pContainer = NULL;     
  }

  if ( m_doc ) 
  {
		m_doc->Release();
		m_doc = NULL;
	}
  
  if ( m_obj3D ) 
  {
		m_obj3D->Release();
		m_obj3D = NULL;
	}

  m_iidEvents = GUID_NULL;
}


//-------------------------------------------------------------------------------
// 
// ---
void ABaseEvent::Disconnect()      
{
  Unadvise();
  Clear();
  ExternalRelease();
}


//-------------------------------------------------------------------------------
//    
// ---
int ABaseEvent::Advise() 
{
  ASSERT( m_dwCookie == 0 ); //   

  //    
	if ( m_pContainer ) 
  {
    LPCONNECTIONPOINTCONTAINER lpContainer = NULL;
	  if ( SUCCEEDED(m_pContainer->QueryInterface(IID_IConnectionPointContainer, (LPVOID*)&lpContainer)) ) 
    {
	    if ( lpContainer && SUCCEEDED(lpContainer->FindConnectionPoint(m_iidEvents, &m_pConnPt)) ) 
	    {
		    ASSERT( m_pConnPt != NULL );
		    m_pConnPt->Advise( &m_xEventHandler, &m_dwCookie ); 
	    }
	    lpContainer->Release();
    }
  }

	return m_dwCookie;
}


//-------------------------------------------------------------------------------
//    
// ---
void ABaseEvent::Unadvise()
{
  if ( m_pConnPt != NULL )              //  
  {
    m_pConnPt->Unadvise( m_dwCookie );  //    
    m_pConnPt->Release();	              //  
    m_pConnPt  = NULL;
  } 
  m_dwCookie = 0;

}


//-----------------------------------------------------------------------------
//
// ---
bool ABaseEvent::IsMyContainer( LPUNKNOWN container )
{
  return IsSame( m_pContainer, container ); 
}


//-----------------------------------------------------------------------------
//  
// ---
LPUNKNOWN ABaseEvent::GetContainer( bool addRef )
{
  if ( addRef && m_pContainer )
    m_pContainer->AddRef();
  return m_pContainer;
}


//-----------------------------------------------------------------------------
//   
// ---
void ABaseEvent::TerminateEvents( LPUNKNOWN container )
{
  if ( container ) {
    int count = m_EventList.GetCount();
	  for ( int i = count - 1; i>= 0 ; i-- )
    {
		  CObject* obj = m_EventList.GetAt( m_EventList.FindIndex(i) );
      ABaseEvent* event = (ABaseEvent*) obj;  
      if ( event && event->IsMyContainer(container) )
        event->Disconnect();			//       RemoveAt(pos)
    }
  }
}


//-----------------------------------------------------------------------------
//     GUID  
// ---
void ABaseEvent::TerminateEvents( IID iid, LPDISPATCH doc/*NULL*/,
                                           long objType/*-1*/,
                                           LPDISPATCH obj3D /*NULL*/)
{
  int count = m_EventList.GetCount();
	for ( int i = count - 1; i >= 0; i-- )
	{
		CObject* obj = m_EventList.GetAt( m_EventList.FindIndex( i ) );
    ABaseEvent* event = (ABaseEvent*) obj;  
    if ( event && 
         ( IsEqualIID( iid, GUID_NULL)                    ||
           IsEqualIID( event->m_iidEvents, iid ) )        &&
         ( objType == -1 || event->m_objType == objType ) &&
         ( !doc          || IsSame(event->m_doc, doc) )   &&
         ( !obj3D        || IsSame(obj3D, event->m_obj3D) ) ) 
    {         
			event->Disconnect();	//       RemoveAt(pos)
    }
	}
}



//-----------------------------------------------------------------------------
//   
// ---
void ABaseEvent::TerminateEvents( void )
{
  while ( !m_EventList.IsEmpty() ) {
	  ABaseEvent* headEvent = (ABaseEvent*)m_EventList.RemoveHead();
		headEvent->Disconnect();		
  }
}


//-----------------------------------------------------------------------------
//
// ---
bool ABaseEvent::FindEvent( IID iid, LPDISPATCH doc/*NULL*/, 
                                     long objType/*-1*/, LPDISPATCH obj3D ) 
{
  int count = m_EventList.GetCount();
	for ( int i = count - 1; i >= 0; i-- )
	{
		CObject* obj = m_EventList.GetAt(  m_EventList.FindIndex( i ) );
    ABaseEvent* event = (ABaseEvent*) obj;  
	  if ( event && 
         ( IsEqualIID( iid, GUID_NULL) || 
           IsEqualIID( event->m_iidEvents, iid ) ) &&
         ( !doc          || event->m_doc == doc ) &&
         ( ( objType == -1 && !event->m_objType ) || (event->m_objType == objType) ) && 
         ( ( !obj3D && !event->m_obj3D) || ( obj3D == event->m_obj3D ) ) )         
      return true;
  }
  return false;
}


//-----------------------------------------------------------------------------
//
// ---
bool ABaseEvent::FindEventByContainer( IID iid, LPUNKNOWN pObject ) 
{
  int count = m_EventList.GetCount();
	for ( int i = count - 1; i >= 0; i-- )
	{
		CObject* obj = m_EventList.GetAt(  m_EventList.FindIndex( i ) );
    ABaseEvent* event = (ABaseEvent*) obj;  
	  if ( event && 
         ( IsEqualIID( iid, GUID_NULL) || 
           IsEqualIID( event->m_iidEvents, iid ) ) &&
            event->IsMyContainer(pObject) )         
      return true;
  }
  return false;
}


//-------------------------------------------------------------------------------
//  
// ---
BEGIN_INTERFACE_MAP(ABaseEvent, CCmdTarget)
END_INTERFACE_MAP()


//-------------------------------------------------------------------------------
//   
// ---
BEGIN_EVENTSINK_MAP(ABaseEvent, CCmdTarget)
END_EVENTSINK_MAP()


//-------------------------------------------------------------------------------
// AddRef
// ---
STDMETHODIMP_(ULONG) ABaseEvent::XEventHandler::AddRef()
{
	METHOD_PROLOGUE( ABaseEvent, EventHandler )
	return (ULONG)pThis->ExternalAddRef();
}


//-------------------------------------------------------------------------------
// GetIDsOfNames
// ---
STDMETHODIMP ABaseEvent::XEventHandler::GetIDsOfNames( REFIID riid, LPOLESTR* rgszNames, 
                                                      unsigned int cNames, LCID lcid, 
                                                      DISPID* rgdispid )
{
	METHOD_PROLOGUE( ABaseEvent, EventHandler )
	ASSERT_VALID( pThis );

	return ResultFromScode( E_NOTIMPL );
}


//-------------------------------------------------------------------------------
// GetTypeInfo
// ---
STDMETHODIMP ABaseEvent::XEventHandler::GetTypeInfo( unsigned int itinfo, LCID lcid, 
                                                    ITypeInfo** pptinfo )
{
	METHOD_PROLOGUE( ABaseEvent, EventHandler )
	ASSERT_VALID( pThis );

	return ResultFromScode( E_NOTIMPL );
}


//-------------------------------------------------------------------------------
// GetTypeInfoCount
// ---
STDMETHODIMP ABaseEvent::XEventHandler::GetTypeInfoCount( unsigned int* pctinfo )
{
	METHOD_PROLOGUE( ABaseEvent, EventHandler )
	*pctinfo = 0;
	return NOERROR;
}


//-------------------------------------------------------------------------------
//  
// ---
STDMETHODIMP ABaseEvent::XEventHandler::Invoke( DISPID           dispidMember, 
                                               REFIID           riid, 
                                               LCID             lcid, 
                                               unsigned short   wFlags, 
                                               DISPPARAMS     * lpDispparams, 
                                               VARIANT        * pvarResult, 
                                               EXCEPINFO      * pexcepinfo, 
                                               unsigned int   * puArgErr )
{
	METHOD_PROLOGUE( ABaseEvent, EventHandler )
	ASSERT_VALID( pThis );

  //    
	AFX_EVENT event( AFX_EVENT::event, dispidMember, lpDispparams, pexcepinfo, puArgErr );

  // : OnEvent     FALSE,   ,
  //               TRUE,     ,  
  //              OnEvent   GetEventSinkEntry           
            
  BOOL eventHandled = TRUE; //   ,   TRUE
  if (pThis->GetEventSinkEntry( 1, &event ) != NULL )      
    eventHandled = pThis->OnEvent( 1, &event, NULL ); //   

  if ( pvarResult != NULL ) {
		VariantClear( pvarResult );                       //  
	                                  
	  V_VT  (pvarResult) = VT_BOOL;
	  V_BOOL(pvarResult) = eventHandled;
  }
  return event.m_hResult;
}


//-------------------------------------------------------------------------------
// QueryInterface
// ---
STDMETHODIMP ABaseEvent::XEventHandler::QueryInterface( REFIID iid, LPVOID* ppvObj )
{
	METHOD_PROLOGUE( ABaseEvent, EventHandler )

	*ppvObj = NULL;
	if ( IID_IUnknown == iid || IID_IDispatch == iid || iid == pThis->m_iidEvents )
		*ppvObj = this;

	if ( NULL != *ppvObj )
	{
		((LPUNKNOWN)*ppvObj)->AddRef();
		return NOERROR;
	}

  return (HRESULT)pThis->ExternalQueryInterface( &iid, ppvObj );
}


//-------------------------------------------------------------------------------
// Release
// ---
STDMETHODIMP_(ULONG) ABaseEvent::XEventHandler::Release()
{
	METHOD_PROLOGUE( ABaseEvent, EventHandler )
	return (ULONG)pThis->ExternalRelease();
}


//-----------------------------------------------------------------------------
//
// ---
void AdviseFrames( IKompasDocumentPtr & doc )
{
// if ( doc )
// {
//   IDocumentFramesPtr docFrames( doc->DocumentFrames );
//   if ( docFrames )
//   {
//     IDocumentFramePtr frame;
//     for ( long i = 0, count = docFrames->Count; i < count; i++ )
//     {
//       frame = docFrames->Item[i];
//       NewDocumentFrameEvent( doc, frame );
//     }
//   }
// }
}


//-------------------------------------------------------------------------------
//    
// ---
void AdviseDoc( IKompasDocumentPtr & doc )
{
  if ( newKompasAPI )
  {
    if ( !(bool)doc )
      doc = newKompasAPI->ActiveDocument; 
		if ( doc )
    {
      int docType = doc->DocumentType;
      switch( docType ) 
      {
        case ksDocumentPart    :
        case ksDocumentAssembly: 
        {
          if ( NewDocumentEvent( doc ) ) 
          {
            AdviseFrames(doc);
          }
          break;
        }
      }    
    }
  }
}


//-------------------------------------------------------------------------------
//      
// ---
void AdviseDocuments() 
{
// if ( newKompasAPI ) 
// {
//   IDocumentsPtr docs( newKompasAPI->Documents );
//   for ( long i = 0, count = docs->Count; i < count; i++ )
//   {
//     IKompasDocumentPtr doc( docs->GetItem(i) );
//     //  
//        
//     //    
//     AdviseDoc( doc );
//        
//   }
// }
}

