/*++

Copyright (c) Microsoft Corporation. All rights reserved.

--*/

#include "stdafx.h"
#include "resource.h"

#include "BitmapUtil.h"
#include "BitmapWnd.h"

//////////////////////////////////////////////////////////////////////////
//
// CBitmapWnd::CBitmapWnd
//

CBitmapWnd::CBitmapWnd(IStream *pStream) : m_Image(pStream)
{
    m_cRef = 0;
}

//////////////////////////////////////////////////////////////////////////
//
// CBitmapWnd::CBitmapWnd
//

CBitmapWnd::CBitmapWnd(PCWSTR pszFileName) : m_Image(pszFileName)
{
    m_cRef = 0;
}

//////////////////////////////////////////////////////////////////////////
//
// CBitmapWnd::QueryInterface
//

STDMETHODIMP CBitmapWnd::QueryInterface(REFIID iid, LPVOID *ppvObj)
{
    if (ppvObj == NULL)
    {
	    return E_POINTER;
    }

    if (iid == IID_IUnknown)
    {
	    *ppvObj = (IUnknown *) this;
    }
    else
    {
        *ppvObj = NULL;
        return E_NOINTERFACE;
    }

	AddRef();
    return S_OK;
}

//////////////////////////////////////////////////////////////////////////
//
// CBitmapWnd::AddRef
//

STDMETHODIMP_(ULONG) CBitmapWnd::AddRef()
{
    return InterlockedIncrement(&m_cRef);
}

//////////////////////////////////////////////////////////////////////////
//
// CBitmapWnd::Release
//

STDMETHODIMP_(ULONG) CBitmapWnd::Release()
{
    LONG cRef = InterlockedDecrement(&m_cRef);

    if (cRef == 0)
    {
        delete this;
    }

    return cRef;
}

///////////////////////////////////////////////////////////////////////////////
//
// CBitmapWnd::Register
//

ATOM CBitmapWnd::Register()
{
    WNDCLASSEX wcex = { 0 };

    wcex.cbSize         = sizeof(wcex);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WindowProc;
    wcex.hInstance      = g_hInstance;
    wcex.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
    wcex.lpszClassName  = _T("BitmapWindow");

    return RegisterClassEx(&wcex);
}

//////////////////////////////////////////////////////////////////////////
//
// CBitmapWnd::WindowProc
//

LRESULT 
CALLBACK
CBitmapWnd::WindowProc(
    HWND   hWnd,
    UINT   uMsg,
    WPARAM wParam,
    LPARAM lParam
)
{
    switch (uMsg)
    {
        case WM_CREATE:
        {
            LPCREATESTRUCT pcs = (LPCREATESTRUCT) lParam;

            LPMDICREATESTRUCT pmdics = (LPMDICREATESTRUCT) pcs->lpCreateParams;

            CBitmapWnd *that = (CBitmapWnd *) pmdics->lParam;

            that->AddRef();

            SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) that);

            break;
        }

        case WM_DESTROY:
        {
            CBitmapWnd *that = (CBitmapWnd *) GetWindowLongPtr(hWnd, GWLP_USERDATA);

            SetWindowLongPtr(hWnd, GWLP_USERDATA, NULL);

            that->Release();

            break;
        }

        case WM_PAINT:
        {
            CBitmapWnd *that = (CBitmapWnd *) GetWindowLongPtr(hWnd, GWLP_USERDATA);

            that->OnPaint(hWnd);

            break;
        }
    }

    return DefMDIChildProc(
        hWnd,
        uMsg,
        wParam,
        lParam
    );
}

//////////////////////////////////////////////////////////////////////////
//
// CBitmapWnd::OnPaint
//

LRESULT CBitmapWnd::OnPaint(HWND hWnd)
{
    // Get the destination DC

    PAINTSTRUCT ps;

    HDC hDC = BeginPaint(hWnd, &ps);

    if (hDC != NULL)
    {
        Gdiplus::Graphics graphics(hDC);

        // Get the size of the window

        RECT r;

        GetClientRect(hWnd, &r);

        UINT nWindowWidth = r.right;
        UINT nWindowHeight = r.bottom;

        // Get the size of the image

        UINT nBitmapWidth = m_Image.GetWidth();
        UINT nBitmapHeight = m_Image.GetHeight();

        if (nBitmapWidth != 0 && nBitmapHeight != 0)
        {
            // Calculate the coordinates and the size of the image

            Gdiplus::Rect rDest;

            if (nBitmapWidth <= nWindowWidth && nBitmapHeight <= nWindowHeight)
            {
                // If the image is smaller than the window, center the image

                rDest.X      = (nWindowWidth - nBitmapWidth) / 2;
                rDest.Y      = (nWindowHeight - nBitmapHeight) / 2;
                rDest.Width  = nBitmapWidth;
                rDest.Height = nBitmapHeight;
            }
            else
            {
                // If the image is larger than the window, resize and center 
                // the image while keeping the aspect ratio

                UINT nStretchedWidth  = nWindowWidth;
                UINT nStretchedHeight = MulDiv(nBitmapHeight, nWindowWidth, nBitmapWidth);

			    if (nStretchedHeight > nWindowHeight)
			    {
				    nStretchedWidth  = MulDiv(nBitmapWidth, nWindowHeight, nBitmapHeight);
				    nStretchedHeight = nWindowHeight;
			    }

                rDest.X      = (nWindowWidth - nStretchedWidth) / 2;
                rDest.Y      = (nWindowHeight - nStretchedHeight) / 2;
                rDest.Width  = nStretchedWidth;
                rDest.Height = nStretchedHeight;
            }

            // Paint the image with a white background

            graphics.DrawImage(&m_Image, rDest);

            graphics.ExcludeClip(rDest);
        }

	Gdiplus::Color white(255, 255, 255, 255);
	
        graphics.Clear(white);

        EndPaint(hWnd, &ps);
    }

    return 0;
}


