// BullsEyePropPage.cpp : Implementacja CBullsEyePropPage
#include "stdafx.h"
#include "BullsEyeCtl.h"
#include "BullsEyePropPage.h"

/////////////////////////////////////////////////////////////////////////////
// Metody interfejsu IPropertyPage

/**************/
/* SetObjects */
/**************/


STDMETHODIMP CBullsEyePropPage::SetObjects(ULONG cObjects, IUnknown** ppUnk)
{
    ATLTRACE2(atlTraceControls,2,_T("CBullsEyePropPage::SetObjects\n"));

	if (ppUnk == NULL) return E_POINTER;

    ///////////////////////////////////////////////////////
    // Usuwa wcześniejsze obiekty, połączenia i  cookies //
    ///////////////////////////////////////////////////////
    CleanupObjectArray();

    /////////////////////////////////////////////////////////////////////////////
    // Alokacja nowej tablicy obiektów, utworzenie połączeń i zapisaniecookies //
    /////////////////////////////////////////////////////////////////////////////
    if (cObjects > 0) {
        // Alokacja tablicy obiektów
        ATLTRY(m_ppUnk = new LPUNKNOWN[cObjects]);
        if (m_ppUnk == NULL) return E_OUTOFMEMORY;

        // Alokacja cookies
        ATLTRY(m_pCookies = new DWORD[cObjects]);
        if (m_pCookies == NULL) {
            delete [] m_ppUnk;
            m_ppUnk = NULL;
            return E_OUTOFMEMORY;
        }

        // Utworzenie połączenia do punktów połączenia każdego obiektu
        for (UINT i = 0; i < cObjects; i++) {
            // Upewnienie się, czy obiekt obsługuje domyślny interfejs.
            // Ten interfejs jest wymagany do wysłania zmian z powrotem do obiektu.
            HRESULT hr = ppUnk[i]->QueryInterface (IID_IBullsEye, (void**)&m_ppUnk[i]);
            if (FAILED(hr)) return hr;

            // Nawiązanie punktu połączenia z obiektu do ujścia.
            // Jest to konieczne w celu odbioru powiadomień o zmianach obiektu.
            hr = AtlAdvise(m_ppUnk[i],
                           static_cast<IPropertyNotifySink*>(this),
					       IID_IPropertyNotifySink,
                           &m_pCookies[i]);
//            if (FAILED(hr)) return hr;
        }
    }
    m_nObjects = cObjects;

    //////////////////////////////////////////////////////////////////////////
    // Przekazanie właściwości z pierwszego obiektu do stronicy właściwości//
    /////////////////////////////////////////////////////////////////////////

    InitializeControlsFromObject (DISPID_UNKNOWN);

    return S_OK;
}

/**************/
/* Aktywacja */
/************/

STDMETHODIMP CBullsEyePropPage::Activate(HWND hWndParent, LPCRECT pRect, BOOL bModal)
{
    ATLTRACE(_T("CBullsEyePropPage::Activate\n"));
    HRESULT hr = IPropertyPage2Impl<CBullsEyePropPage>::Activate(hWndParent, pRect, bModal);
    if (SUCCEEDED (hr) && DISPID_UNKNOWN != m_EditProperty) {
        EditProperty (m_EditProperty);
        m_EditProperty = DISPID_UNKNOWN;
    }
    return hr;
}

/*****************/
/* Zastosowanie */
/***************/

STDMETHODIMP CBullsEyePropPage::Apply(void)
{
    ATLTRACE(_T("CBullsEyePropPage::Apply\n"));
    SetPropertiesFromControls(DISPID_UNKNOWN);
    m_bDirty = FALSE;
    m_flags  = 0;
    return S_OK;
}

/****************/
/* EditProperty */
/****************/

STDMETHODIMP CBullsEyePropPage::EditProperty(DISPID dispid)
{
    ATLTRACE(_T("CBullsEyePropPage::EditProperty\n"));
    m_EditProperty = dispid;

    if (IsWindow()) {
        switch (dispid) {
        case DISPID_BEEP:
            ::SetFocus(GetDlgItem (IDC_BEEP));
            break;
        case DISPID_ENABLED:
            ::SetFocus(GetDlgItem (IDC_ENABLED));
            break;
        case DISPID_RINGCOUNT:
            ::SetFocus(GetDlgItem (IDC_RINGCOUNT));
            break;
        case DISPID_BACKSTYLE:
            ::SetFocus(GetDlgItem (IDC_TRANSPARENT));
            break;
        default:
            return E_INVALIDARG;
        }
    }
    return S_OK;
}

/////////////////////////////////////////////////////////////////////////////
// Metody interfejsu IPropertyNotifySink

STDMETHODIMP CBullsEyePropPage::OnChanged(DISPID dispid)
{
    InitializeControlsFromObject (dispid);
    return S_OK;
}

STDMETHODIMP CBullsEyePropPage::OnRequestEdit(DISPID dispid)
{
    return S_OK;
}

/////////////////////////////////////////////////////////////////////////////
// Procedury obsługi wiadomości okna CBullsEyePropPage

/****************/
/* OnInitDialog */
/****************/

LRESULT CBullsEyePropPage::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    InitializeControlsFromObject (DISPID_UNKNOWN);
    return 0;
}

/************/
/* OnCreate */
/************/

LRESULT CBullsEyePropPage::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    INITCOMMONCONTROLSEX ic = { sizeof (ic), ICC_UPDOWN_CLASS };
    BOOL bInit = InitCommonControlsEx (&ic);
    return 0;
}

/*************/
/* OnDestroy */
/*************/

LRESULT CBullsEyePropPage::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	CleanupObjectArray();
	return 0;
}

/////////////////////////////////////////////////////////////////////////////
// Procedury obsługi powiadomień elementu sterującego CBullsEyePropPage

/*****************/
/* OnClickedBeep */
/*****************/

LRESULT CBullsEyePropPage::OnClickedBeep(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
    m_beepNew = (BST_CHECKED == SendDlgItemMessage  (wID, BM_GETCHECK)) ? VARIANT_TRUE : VARIANT_FALSE;

    if (m_beepNew != m_beepOrig)
        m_flags |= BEEP_CHANGED;
    else
        m_flags &= ~BEEP_CHANGED;

    SetDirty (m_flags != 0);
	return 0;
}

/********************/
/* OnClickedEnabled */
/********************/

LRESULT CBullsEyePropPage::OnClickedEnabled(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
    m_enabledNew = (BST_CHECKED == SendDlgItemMessage  (wID, BM_GETCHECK)) ? VARIANT_TRUE : VARIANT_FALSE;

    if (m_enabledNew != m_enabledOrig)
        m_flags |= ENABLED_CHANGED;
    else
        m_flags &= ~ENABLED_CHANGED;

    SetDirty (m_flags != 0);
	return 0;
}

/*********************/
/* OnChangeRingCount */
/*********************/

LRESULT CBullsEyePropPage::OnChangeRingCount(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
    BOOL bTranslated = FALSE;
    m_ringCountNew = (short) GetDlgItemInt (IDC_RINGCOUNT, &bTranslated, FALSE);
    if (!bTranslated || m_ringCountNew < 1 || m_ringCountNew > 9) {
        // Wartości nienumeryczne lub poza zakresem - konieczna ponowna inicjalizacja elementu sterującego.
        SendDlgItemMessage (IDC_SPIN1, UDM_SETPOS,   0, MAKELONG(m_ringCountNew, 0));
        return 0;
    }
    if (m_ringCountOrig != m_ringCountNew)
        m_flags |= RINGCOUNT_CHANGED;
    else
        m_flags &= ~RINGCOUNT_CHANGED;

    SetDirty (m_flags != 0);
	return 0;
}

/************************/
/* OnClickedTransparent */
/************************/

LRESULT CBullsEyePropPage::OnClickedTransparent(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
    m_transparentNew = (BST_CHECKED == SendDlgItemMessage  (wID, BM_GETCHECK)) ? 1 : 0;

    if (m_transparentNew != m_transparentOrig)
        m_flags |= TRANSPARENT_CHANGED;
    else
        m_flags &= ~TRANSPARENT_CHANGED;

    SetDirty (m_flags != 0);
	return 0;
}

/********************************/
/* InitializeControlsFromObject */
/********************************/

void CBullsEyePropPage::InitializeControlsFromObject(DISPID dispid)
{
    // Tablica już zawiera IBullsEye*, a więc jest zbędna...
    CComQIPtr<IBullsEye> pBullsEye = m_ppUnk[0];

    if (DISPID_RINGCOUNT == dispid || DISPID_UNKNOWN == dispid) {
        // Uzyskanie właściwości RingCount
        HRESULT hr = pBullsEye->get_RingCount (&m_ringCountOrig);
        ATLASSERT (SUCCEEDED (hr));
        m_ringCountNew = m_ringCountOrig;

        if (IsWindow ()) {
            SendDlgItemMessage (IDC_SPIN1, UDM_SETRANGE, 0, MAKELONG(9, 1));
            SendDlgItemMessage (IDC_SPIN1, UDM_SETPOS,   0, MAKELONG(m_ringCountOrig, 0));
        }
    }

    if (DISPID_BEEP == dispid || DISPID_UNKNOWN == dispid) {
        // Uzyskanie właściwości Beep
        HRESULT hr = pBullsEye->get_Beep (&m_beepOrig);
        ATLASSERT (SUCCEEDED (hr));
        m_beepNew = m_beepOrig;

        if (IsWindow ()) {
            SendDlgItemMessage (IDC_BEEP, BM_SETCHECK, m_beepOrig ? BST_CHECKED : BST_UNCHECKED);
        }
    }

    if (DISPID_ENABLED == dispid || DISPID_UNKNOWN == dispid) {
        // Uzyskanie właściwości  Enabled
        HRESULT hr = pBullsEye->get_Enabled (&m_enabledOrig);
        ATLASSERT (SUCCEEDED (hr));
        m_enabledNew = m_enabledOrig;

        if (IsWindow ()) {
            SendDlgItemMessage (IDC_ENABLED, BM_SETCHECK, m_enabledOrig ? BST_CHECKED : BST_UNCHECKED);
        }
    }

    if (DISPID_BACKSTYLE == dispid || DISPID_UNKNOWN == dispid) {
        // Uzyskanie właściwości  Enabled
        HRESULT hr = pBullsEye->get_BackStyle (&m_transparentOrig);
        ATLASSERT (SUCCEEDED (hr));
        m_transparentNew = m_transparentOrig;

        if (IsWindow ()) {
            SendDlgItemMessage (IDC_TRANSPARENT, BM_SETCHECK, m_transparentOrig ? BST_CHECKED : BST_UNCHECKED);
        }
    }
}

/*****************************/
/* SetPropertiesFromControls */
/*****************************/

void CBullsEyePropPage::SetPropertiesFromControls(DISPID dispid)
{
    // Jeśli działanie QI zakończyło się niepowodzeniem w SetObjects
    if (!m_ppUnk || !m_ppUnk[0]) return;

    // Dla wszystkich obiektów w tablicy...
    for (UINT i = 0; i < m_nObjects; i++) {
        // Uzyskanie odpowiedniego interfejsu...
        CComQIPtr<IBullsEye> pBullsEye = m_ppUnk[i];

        // Aktualizacja właściwości RingCount, jeśli jest to wymagane.
        if ((DISPID_RINGCOUNT == dispid || DISPID_UNKNOWN == dispid) &&
            m_flags & RINGCOUNT_CHANGED) {
            pBullsEye->put_RingCount(m_ringCountNew);   // Aktualizacja właściwości
            m_ringCountOrig = m_ringCountNew;           // Synchronizacja właściwości
            m_flags &= ~RINGCOUNT_CHANGED;              // Oczyszczenie znacznika Changed
        }

        // Aktualizacja właściwości Beep, jeśli jest to wymagane.
        if ((DISPID_BEEP == dispid || DISPID_UNKNOWN == dispid) &&
            m_flags & BEEP_CHANGED) {
            pBullsEye->put_Beep(m_beepNew);             // Aktualizacja właściwości
            m_beepOrig = m_beepNew;                     // Synchronizacja właściwości
            m_flags &= ~BEEP_CHANGED;                   // Oczyszczenie znacznika Changed
        }

        // Aktualizacja właściwości, jeśli jest to wymagane.
        if ((DISPID_ENABLED == dispid || DISPID_UNKNOWN == dispid) &&
            m_flags & ENABLED_CHANGED) {
            pBullsEye->put_Enabled(m_enabledNew);       // Aktualizacja właściwości
            m_enabledOrig = m_enabledNew;               // Synchronizacja właściwości
            m_flags &= ~ENABLED_CHANGED;                // Oczyszczenie znacznika Changed
        }

        // Aktualizacja właściwości BackStyle, jeśli jest to wymagane.
        if ((DISPID_BACKSTYLE == dispid || DISPID_UNKNOWN == dispid) &&
            m_flags & TRANSPARENT_CHANGED) {
            pBullsEye->put_BackStyle(m_transparentNew); // Aktualizacja właściwości
            m_transparentOrig = m_transparentNew;       // Synchronizacja właściwości
            m_flags &= ~TRANSPARENT_CHANGED;            // Oczyszczenie znacznika Changed
        }
    }
}

/**********************/
/* CleanupObjectArray */
/**********************/

void CBullsEyePropPage::CleanupObjectArray()
{
    // Oczyszczenie istniejącej tablicy obiektów
    if (m_ppUnk != NULL && m_nObjects > 0) {
        for (UINT i = 0; i < m_nObjects; i++) {
            if (NULL == m_ppUnk[i]) break;
            // Przerwanie połączenia
			AtlUnadvise(m_ppUnk[i], IID_IPropertyNotifySink, m_pCookies[i]);
            m_ppUnk[i]->Release();
        }

        delete [] m_ppUnk;
        delete [] m_pCookies;
	}
    // Na liście nie ma już żadnych obiektów
	m_ppUnk    = NULL;
	m_pCookies = NULL;
    m_nObjects = 0;
}
