/*++

Copyright (c) 1996  Microsoft Corporation

Module Name:

    faxcomponent.h

Abstract:

    This file contains my implementation of IComponent.

Environment:

    WIN32 User Mode

Author:

    Darwin Ouyang (t-darouy) 30-Sept-1997

--*/

// faxcomponent.cpp : Implementation of CFaxComponent
#include "stdafx.h"
#include "faxadmin.h"
#include "faxhelper.h"
#include "faxcomp.h"
#include "faxcompd.h"
#include "faxdataobj.h"

#include "inode.h"
#include "iroot.h"
#include "ilogging.h"
#include "ilogcat.h"
#include "idevices.h"
#include "idevice.h"

#include "adminhlp.h"

#pragma hdrstop

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Constructor and Destructor
//
//

CFaxComponent::CFaxComponent() 
/*++

Routine Description:

    Constructor
    
Arguments:

    None.

Return Value:

    None.

--*/
{
    m_pUnknown = NULL;
    m_pConsole = NULL;
    m_pConsoleNameSpace = NULL;
    m_pConsoleVerb = NULL;
    m_pHeaderCtrl = NULL;
    m_pImageList = NULL;
    m_pResultData = NULL;
    m_pControlbar = NULL;

    m_dwPropSheetCount = 0;

    CFaxComponentExtendContextMenu::m_pFaxComponent = this;  
    CFaxComponentExtendPropertySheet::m_pFaxComponent = this;  
    CFaxComponentExtendControlbar::m_pFaxComponent = this;  

    // initialize CInternalDevices instance data
    pDeviceArray = NULL;
    numDevices = 0;

    // initialize CInternalLogging instance data
    pLogPArray = NULL;
    pCategories = NULL;
    numCategories = 0;

    DebugPrint(( TEXT("FaxComponent Created") ));
}

CFaxComponent::~CFaxComponent()
/*++

Routine Description:

    Destructor.
    
Arguments:

    None.

Return Value:

    None.

--*/
{
    DebugPrint(( TEXT("FaxComponent Destroyed") ));

    DWORD count; 

    // release CInternalDevices instance data
    if(pDeviceArray != NULL ) {
        for(  count = 0; count < numDevices; count ++ ) {
            if( pDeviceArray[count] != NULL ) {            
                delete pDeviceArray[count];
                pDeviceArray[count] = NULL;
            }
        }
        delete pDeviceArray;
        pDeviceArray = NULL;
    }

    // release CInternalLogging instance data
    if( pLogPArray != NULL ) {
        for( count = 0; count < numCategories; count++ ) {
            if( pLogPArray[count] != NULL ) {
                delete pLogPArray[count];
                pLogPArray[count] = NULL;
            }
        }
        delete pLogPArray;
        pLogPArray = NULL;
    }
    if( pCategories != NULL ) {
        FaxFreeBuffer( (PVOID) pCategories );
        pCategories = NULL;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// CFaxComponent implementation
//
//

HRESULT 
STDMETHODCALLTYPE 
CFaxComponent::Initialize(
                         IN LPCONSOLE lpUnknown)
/*++

Routine Description:

    This routine initializes IComponent by querying
    for needed interfaces.
    
Arguments:

    lpUnknown - the console's IUnknown/IConsole interface.

Return Value:

    HRESULT indicating SUCCEEDED() or FAILED()

--*/
{
    assert( lpUnknown != NULL );

    HRESULT     hr;

    do {
        m_pUnknown = lpUnknown;
        // increment reference on the console
        m_pUnknown->AddRef();

        hr = m_pUnknown->QueryInterface( IID_IConsole, (void **)&m_pConsole );
        assert( SUCCEEDED( hr ));
        if( FAILED( hr ) ) {
            break;        
        }

        hr = m_pConsole->QueryResultImageList( &m_pImageList );
        assert( SUCCEEDED( hr ));        
        if( FAILED( hr ) ) {
            break;        
        }


        hr = m_pUnknown->QueryInterface( IID_IResultData, (void **)&m_pResultData );
        assert( SUCCEEDED( hr ));
        if( FAILED( hr ) ) {
            break;        
        }

        hr = m_pUnknown->QueryInterface( IID_IConsoleNameSpace, (void **)&m_pConsoleNameSpace );
        assert( SUCCEEDED( hr ));
        if( FAILED( hr ) ) {
            break;        
        }

        hr = m_pConsole->QueryConsoleVerb( &m_pConsoleVerb );
        assert( SUCCEEDED( hr ));
        if( FAILED( hr ) ) {
            break;        
        }

        hr = m_pUnknown->QueryInterface( IID_IHeaderCtrl, (void **)&m_pHeaderCtrl );
        assert( SUCCEEDED( hr ));
        if( FAILED( hr ) ) {
            break;        
        }

        // set the header object
        hr = m_pConsole->SetHeader( m_pHeaderCtrl );
        assert( SUCCEEDED( hr ));
        if( FAILED( hr ) ) {
            break;        
        }

    } while( 0 );

    return hr;
}

HRESULT 
STDMETHODCALLTYPE 
CFaxComponent::Notify(
                     IN LPDATAOBJECT lpDataObject,
                     IN MMC_NOTIFY_TYPE event,
                     IN LPARAM arg,
                     IN LPARAM param) 
/*++

Routine Description:

    This routine dispatches events sent to the IComponent
    interface using the cookie extracted from the DataObject.
    
    The cookie stored is a pointer to the class that implements behavior for
    that subfolder. So we delegate all the messages by taking the cookie
    casting it to a pointer to a folder, and invoking the notify method.
    
Arguments:

    lpDataobject - the data object
    event - the event type
    arg, param - event arguments

Return Value:

    HRESULT indicating SUCCEEDED() or FAILED()

--*/
{
    HRESULT             hr = S_OK;
    CFaxDataObject *    dataObject = NULL;
    LONG_PTR            cookie;

//    DebugPrint(( TEXT("Trace: CFaxComponent::Notify") ));

    if( event == MMCN_CONTEXTHELP ) {
        MMCPropertyHelp(FAXMMC_HTMLHELP_TOPIC);
    }
    else if( lpDataObject != NULL) {
        dataObject = ExtractOwnDataObject( lpDataObject );
        if( dataObject == NULL ) {
            return E_UNEXPECTED;
        }

        cookie = dataObject->GetCookie();

        if( cookie == NULL) {
            // my static node
            assert( pOwner );
            hr = pOwner->globalRoot->ResultNotify( this, dataObject, event, arg, param );
        } else {
            // cast the cookie to a pointer
            try {            
                hr = ((CInternalNode *)cookie)->ResultNotify( this, dataObject, event, arg, param );
            } catch ( ... ) {
                DebugPrint(( TEXT("Invalid Cookie: 0x%08x"), cookie ));
                assert( FALSE ); // got passed an INVALID COOKIE!?!?!?!?
                hr = E_UNEXPECTED;
            }
        }
    } else {
        // some events do not pass a lpDataObject into Notify.
        // we need to handle those events here, if you want
        // to handle them at all!!
        if( event == MMCN_PROPERTY_CHANGE ) {
            if( param != NULL ) {
                try {                
                    hr = ((CInternalNode *)param)->ResultNotify( this, NULL, event, arg, param );
                } catch ( ... ) {
                    DebugPrint(( TEXT("Invalid Cookie") ));
                    assert( FALSE ); // got passed an INVALID COOKIE!?!?!?!?
                    hr = E_UNEXPECTED;
                }
            }
        }
    }

    return hr;    
}

HRESULT 
STDMETHODCALLTYPE 
CFaxComponent::Destroy(
                      IN MMC_COOKIE cookie) 
/*++

Routine Description:

    This method releases all the aquired console interface in preperation
    for the IComponent being destroyed.
    
Arguments:

    None.

Return Value:

    HRESULT indicating SUCCEEDED() or FAILED()

--*/
{
    DebugPrint(( TEXT("Trace: CFaxComponent::Notify") ));

    // the prop sheet count should never be negative
    assert( QueryPropSheetCount() >= 0 );

    // check to see if any property sheets are up
    while( QueryPropSheetCount() > 0 ) {
        DebugPrint(( TEXT("Trace: QueryPropSheetCount() %d "), QueryPropSheetCount() ));
        // don't allow deletion        
        GlobalStringTable->PopUpMsg( NULL, IDS_PROP_SHEET_STILL_UP, TRUE, NULL );
    }

    // release the header object
    HRESULT hr = m_pConsole->SetHeader( NULL );
    assert( SUCCEEDED( hr ));

    if( m_pUnknown != NULL ) {
        m_pUnknown->Release();
        m_pUnknown = NULL;
    }

    if( m_pConsole != NULL ) {
        m_pConsole->Release();
        m_pConsole = NULL;
    }

    if( m_pConsoleNameSpace != NULL ) {
        m_pConsoleNameSpace->Release();
        m_pConsoleNameSpace = NULL;
    }

    if( m_pConsoleVerb != NULL ) {
        m_pConsoleVerb->Release();
        m_pConsoleVerb = NULL;
    }

    if( m_pHeaderCtrl != NULL ) {
        m_pHeaderCtrl->Release();
        m_pHeaderCtrl = NULL;
    }

    if( m_pImageList != NULL ) {
        m_pImageList->Release();
        m_pImageList = NULL;
    }

    if( m_pResultData != NULL ) {
        m_pResultData->Release();
        m_pResultData = NULL;
    }

    if( m_pControlbar != NULL ) {
        m_pControlbar->Release();
        m_pControlbar = NULL;
    }

    return S_OK;
}

HRESULT 
STDMETHODCALLTYPE 
CFaxComponent::QueryDataObject(
                              IN MMC_COOKIE cookie,
                              IN DATA_OBJECT_TYPES type,
                              OUT LPDATAOBJECT __RPC_FAR *ppDataObject) 
/*++

Routine Description:

    This method dispatches DataObjects requests to the appropriate 
    nodes using the cookie.
    
Arguments:

    cookie - the cookie for the associated node
    type - the type of the cookie
    ppDataobject - a pointer to the new data object is stored here
    
Return Value:

    HRESULT indicating SUCCEEDED() or FAILED()

--*/
{
//    DebugPrint(( TEXT("Trace: CFaxComponent::QueryDataObject") ));

    HRESULT hr = S_OK;

    if( ppDataObject != NULL ) {
        if( cookie == NULL ) {
            assert( pOwner );
            hr = pOwner->globalRoot->ResultQueryDataObject( this, cookie, type, ppDataObject );
        } else {
            try {            
                hr = ((CInternalNode *)cookie)->ResultQueryDataObject( this, cookie, type, ppDataObject );
            } catch ( ... ) {
                DebugPrint(( TEXT("Invalid Cookie: 0x%08x"), cookie ));
                assert( FALSE ); // got passed an INVALID COOKIE!?!?!?!?
                hr = E_UNEXPECTED;
            }
        }
    } else {
        // bad pointer
        assert( FALSE );
        hr = E_POINTER;
    }

    return hr;

}

HRESULT 
STDMETHODCALLTYPE 
CFaxComponent::GetResultViewType(
                                IN MMC_COOKIE cookie,
                                OUT LPOLESTR __RPC_FAR *ppViewType,
                                OUT long __RPC_FAR *pViewOptions) 
/*++

Routine Description:

    This method dispatches GetResultViewType requests to the appropriate 
    nodes using the cookie.
    
Arguments:

    cookie - the cookie for the associated node
    ppViewType - the viewtype
    ppViewOptions - view options
    
Return Value:

    HRESULT indicating SUCCEEDED() or FAILED()

--*/
{
    HRESULT hr = S_OK;

    assert ( ppViewType != NULL );
    if( ppViewType == NULL ) {
        return E_POINTER;
    }
    assert ( pViewOptions != NULL );
    if( pViewOptions == NULL ) {
        return E_POINTER;
    }

    if( cookie == NULL ) {
        assert( pOwner );
        hr = pOwner->globalRoot->ResultGetResultViewType( this, cookie, ppViewType, pViewOptions );
    } else {
        try {        
            hr = ((CInternalNode *)cookie)->ResultGetResultViewType( this, cookie, ppViewType, pViewOptions );
        } catch ( ... ) {
            DebugPrint(( TEXT("Invalid Cookie: 0x%08x"), cookie ));
            assert( FALSE ); // got passed an INVALID COOKIE!?!?!?!?
            hr = E_UNEXPECTED;
        }
    }

    return hr;
}

HRESULT 
STDMETHODCALLTYPE 
CFaxComponent::GetDisplayInfo(
                             IN OUT RESULTDATAITEM __RPC_FAR *pResultDataItem) 
/*++

Routine Description:

    This method dispatches DisplayInfo requests to the appropriate 
    nodes using the cookie in pResultDataItem.
    
Arguments:

    pResultDataItem - struct containing information about the scope item.

Return Value:

    HRESULT indicating SUCCEEDED() or FAILED()

--*/
{

//    DebugPrint(( TEXT("Trace: CFaxComponent::GetDisplayInfo") ));

    LONG_PTR cookie;
    HRESULT hr = S_OK;

    assert( pResultDataItem != NULL );

    if( pResultDataItem == NULL ) {
        // oops bad pointer
        return E_POINTER;
    }

    cookie = pResultDataItem->lParam;    

    if( cookie == NULL ) {
        // our top node
        assert( pOwner );
        hr = pOwner->globalRoot->ResultGetDisplayInfo(this, pResultDataItem);
    } else {
        // another node
        try {      
            hr = ((CInternalNode *)cookie)->ResultGetDisplayInfo(this, pResultDataItem);
        } catch ( ... ) {
            DebugPrint(( TEXT("Invalid Cookie: 0x%08x"), cookie ));
            //assert( FALSE ); // got passed an INVALID COOKIE!?!?!?!?
            hr = E_UNEXPECTED;
        }
    }

    return hr;
}

HRESULT 
STDMETHODCALLTYPE 
CFaxComponent::CompareObjects(
                             IN LPDATAOBJECT lpDataObjectA,
                             IN LPDATAOBJECT lpDataObjectB) 
/*++

Routine Description:

    This method compares two data object to see if they correspond to 
    the same object by comparing the cookies.
    
Arguments:

    lpDataObjectA - object A
    lpDataObjectB - object B

Return Value:

    HRESULT indicating S_OK or S_FALSE. E_UNEXPECTED for an error.

--*/
{
    CFaxDataObject * aOBJ = ExtractOwnDataObject( lpDataObjectA );
    CFaxDataObject * bOBJ = ExtractOwnDataObject( lpDataObjectB );

    if( aOBJ == NULL || bOBJ == NULL ) {
        return E_UNEXPECTED;
    }

    if( aOBJ->GetCookie() == bOBJ->GetCookie() ) {
        return S_OK;
    } else {
        return S_FALSE;
    }    
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Internal Methods
//
//

void 
CFaxComponent::SetOwner(
                       CFaxComponentData * myOwner )
/*++

Routine Description:

    Sets the Component's owner - needed for internal stuff
    
Arguments:

    myOwner - the owner of the IComponent instance.

Return Value:

    None.

--*/
{
    assert( myOwner != NULL );
    pOwner = myOwner;
}

HRESULT 
CFaxComponent::InsertIconsIntoImageList()
/*++

Routine Description:

    oads the component's result pane icons into an image list
    
Arguments:

    None.

Return Value:

    HRESULT indicating SUCCEEDED() or FAILED()

--*/
{
    HRESULT     hr = E_UNEXPECTED;

    assert( pOwner != NULL );
    assert( m_pImageList != NULL );

    if( m_pImageList != NULL ) {
        if( pOwner != NULL ) {
            hr = pOwner->InsertIconsIntoImageList( m_pImageList );
        }
    }
    return hr;
}