/*
* Copyright (C) 2004 TES Electronic Solutions GmbH,
* All Rights Reserved.
* This source code and any compilation or derivative thereof is the
* proprietary information of TES Electronic Solutions GmbH
* and is confidential in nature.
* Under no circumstances is this software to be exposed to or placed
* under an Open Source License of any type without the expressed
* written permission of TES Electronic Solutions GmbH
*
*############################################################
*/

#include "StreamRuntimeStartup.h"
#include "Resource.h"

#include "GUITrace.h"
#include "GUIException.h"
#include "GUI.h"

#include "GfxEnvWin.h"

// Includes for wrapper classes
#include "SndWrapWin.h"
#include "GUIInputWindows.h"
#include "GUIPlaybackInput.h"

#if defined GFX_USE_EGML
    #include "GfxWrapeGML.h"
    #if defined FNT_USE_FREETYPE
        #include "FntWrapFreeType.h"
    #elif defined FNT_USE_GLYPHLIB
        #include "FntWrapGlyphLib.h"
    #endif
#elif defined GFX_USE_DAVE
    #include "GfxEnvWin.h"
    #include "GfxWrapDAVE.h"
    #if defined FNT_USE_FREETYPE
        #include "FntWrapFreeTypeDave.h"
    #elif defined FNT_USE_GLYPHLIB
        #include "FntWrapGlyphLibDave.h"
    #endif
#elif defined GFX_USE_DAVEHD
    #include "GfxWrapDaveHD.h"
    #if defined FNT_USE_FREETYPE
        #include "FntWrapFreeTypeDave.h"
    #elif defined FNT_USE_GLYPHLIB
        #include "FntWrapGlyphLibDave.h"
    #endif
#elif defined GFX_USE_GL
    #include "GfxWrapOGL.h"
    #if defined FNT_USE_FREETYPE
        #include "FntWrapFreeTypeGL.h"
    #elif defined FNT_USE_GLYPHLIB
        #include "FntWrapGlyphLibGL.h"
    #endif
#elif defined GFX_USE_BLU
    #include "GfxWrapBLU.h"
    #if defined FNT_USE_FREETYPE
        #include "FntWrapFreeType.h"
    #elif defined FNT_USE_GLYPHLIB
        #include "FntWrapGlyphLib.h"
    #endif
#else
    #include "GfxWrapNull.h"
#endif

#if defined(GFX_USE_DAVE) || defined(GFX_USE_DAVEHD) || defined(GFX_USE_GL) || defined(GFX_USE_BLU)
#ifdef GUILIANI_ADD_IMAGE_DECODER
    #include "GUIImageLoader.h"
    #include "GUIImageDecoderBLU.h"
    #include "GUIImageDecoderBMP.h"
    #include "GUIImageDecoderPNG.h"
    #include "GUIImageDecoderJPG.h"
    #include "GUIImageDecoderRAW.h"
    #include "GUIImageDecoderRLE.h"
    #include "GUIImageDecoderSVG.h"
#else
#error "Guiliani is built without Imageloaders. Image will not be loaded correctly."
#endif
#endif

// needs to be included to avoid unresolved references to memleak
#include "GUIMemLeakDetection.h"

#include "GUIMemLeakWatcher.h"

// User configurable values for the application window position:
static const eC_UInt cuiWINDOWPOS_X = 0;
static const eC_UInt cuiWINDOWPOS_Y = 0;

// Window related variables
static const eC_UInt cuiMAX_LOADSTRING = 100;
static TCHAR szTitle[cuiMAX_LOADSTRING];                // Caption (title bar) text
static TCHAR szWindowClass[cuiMAX_LOADSTRING];

/*
Startup sequence is:
    Init()
    MyRegisterClass()
    OpenWindow()
    ConstructWrapperClasses()
    <--- Application lifetime --->
    DestructWrapperClasses()
*/

// Namespace containing default implementations for initializing a StreamRuntime under windows
namespace NStreamRuntime
{
    void CStreamRuntimeStartup::ConstructWrapperClasses()
    {
#if defined GFX_USE_GL
        CGfxEnvWin::CreateInstance(m_hWnd, CGfxEnv::SM_OPENGL, CGUICommonEnums::ARGB_8888, GetScreenWidth(), GetScreenHeight());
#elif defined GFX_USE_DAVE
#ifdef GFX_USE_ARGB32
        CGfxEnvWin::CreateInstance(m_hWnd, CGfxEnv::SM_FRAMEBUFFER, CGUICommonEnums::ARGB_8888, GetScreenWidth(), GetScreenHeight(), 2);
#else
        CGfxEnvWin::CreateInstance(m_hWnd, CGfxEnv::SM_FRAMEBUFFER, CGUICommonEnums::RGB_565, GetScreenWidth(), GetScreenHeight(), 2);
#endif
#elif defined GFX_USE_DAVEHD
        CGfxEnvWin::CreateInstance(m_hWnd, CGfxEnv::SM_FRAMEBUFFER, CGUICommonEnums::ARGB_8888, GetScreenWidth(), GetScreenHeight(), 2);
#else
#ifdef GFX_USE_ARGB32
        CGfxEnvWin::CreateInstance(m_hWnd, CGfxEnv::SM_FRAMEBUFFER, CGUICommonEnums::ARGB_8888, GetScreenWidth(), GetScreenHeight());
#else
        CGfxEnvWin::CreateInstance(m_hWnd, CGfxEnv::SM_FRAMEBUFFER, CGUICommonEnums::RGB_565, GetScreenWidth(), GetScreenHeight());
#endif
#endif

#if 1
        // initialize layers from configuration
        const eC_UInt uiLayerCount = GETRUNTIMECONFIG.GetLayerCount();
        for (eC_UInt uiLayerIndex = 0; uiLayerIndex < uiLayerCount; ++uiLayerIndex)
        {
            LayerConfiguration_t rkLayerConfig = GETRUNTIMECONFIG.GetLayerConfig(uiLayerIndex);
            //rkLayerConfig.m_uiNumBuffers = 2;
            //eC_UByte* pkBuffer0 = new eC_UByte[rkLayerConfig.m_uiWidth * rkLayerConfig.m_uiHeight * 4];
            //eC_UByte* pkBuffer1 = new eC_UByte[rkLayerConfig.m_uiWidth * rkLayerConfig.m_uiHeight * 4];
            //rkLayerConfig.m_pkBuffers[0] = pkBuffer0;
            //rkLayerConfig.m_pkBuffers[1] = pkBuffer1;
            GETGFXENV.AddLayer(rkLayerConfig);
        }
#endif
        GETGFXENV.InitLayers();

// Sets the graphics wrapper and font wrapper
#if defined GFX_USE_EGML
    #if defined GFX_USE_DCWRAP
        CGfxWrapeGML::CreateInstance(&GETGFXENV);
    #else
        #if defined GFX_USE_ARGB32
            CGfxWrapeGML::CreateInstance(&GETGFXENV);
        #elif defined GFX_USE_RGB565
            CGfxWrapeGML::CreateInstance(&GETGFXENV);
        #else
            #error "Please choose supported color-format"
        #endif
    #endif

    #if defined FNT_USE_FREETYPE
            CFntWrapFreeType::CreateInstance(1024 * 1024);
    #elif defined FNT_USE_GLYPHLIB
            CFntWrapGlyphLib::CreateInstance();
    #endif
#elif defined GFX_USE_GL
        CGfxWrapOGL::CreateInstance(&GETGFXENV);
#if defined FNT_USE_FREETYPE
        CFntWrapFreeTypeGL::CreateInstance();
#elif defined FNT_USE_GLYPHLIB
        CFntWrapGlyphLibGL::CreateInstance();
#endif
#elif defined GFX_USE_DAVE
        CGfxWrapDAVE::CreateInstance(&GETGFXENV, 80000);
#if defined FNT_USE_FREETYPE
        CFntWrapFreeTypeDAVE::CreateInstance(1024 * 1024);
#elif defined FNT_USE_GLYPHLIB
        CFntWrapGlyphLibDAVE::CreateInstance();
#endif
#elif defined GFX_USE_DAVEHD
        CGfxWrapDAVEHD::CreateInstance(&GETGFXENV);
#if defined FNT_USE_FREETYPE
        CFntWrapFreeTypeDAVE::CreateInstance(1024 * 1024);
#elif defined FNT_USE_GLYPHLIB
        CFntWrapGlyphLibDave::CreateInstance();
#endif
#elif defined GFX_USE_BLU
        CGfxWrapBLU::CreateInstance(&GETGFXENV);
#if defined FNT_USE_FREETYPE
        CFntWrapFreeType::CreateInstance(1024 * 1024);
#elif defined FNT_USE_GLYPHLIB
        CFntWrapGlyphLib::CreateInstance();
#endif
#else
        MessageBox(NULL, TEXT("Please choose a Graphics-Wrapper. Defaulting to CGfxWrapNull."), TEXT("Warning"), 0);
        CGfxWrapNull::CreateInstance();
#endif

#if defined(GFX_USE_DAVE) || defined(GFX_USE_DAVEHD) || defined(GFX_USE_GL) || defined(GFX_USE_BLU)
    #ifdef GUILIANI_ADD_IMAGE_DECODER
            GETIMGLOADER.AddDecoder(new CGUIImageDecoderBMP());
            GETIMGLOADER.AddDecoder(new CGUIImageDecoderBLU());
            GETIMGLOADER.AddDecoder(new CGUIImageDecoderPNG());
            GETIMGLOADER.AddDecoder(new CGUIImageDecoderJPG());
            GETIMGLOADER.AddDecoder(new CGUIImageDecoderRAW());
            GETIMGLOADER.AddDecoder(new CGUIImageDecoderRLE());
            GETIMGLOADER.AddDecoder(new CGUIImageDecoderSVG());
    #endif
#endif

        // Sets the sound wrapper
        CSndWrapWin::CreateInstance();
        // Sets the input wrapper
        CGUIInputWindows::CreateInstance(m_hWnd, true);
    }

    /* ---------------------------------------------------------------------------------
    Everything below is plain Windows-Code for setting up the application window
    ---------------------------------------------------------------------------------  */
    void CStreamRuntimeStartup::Init(HINSTANCE hInstance, int nCmdShow)
    {
        m_hInstance = hInstance;
        // Load some global strings from programs resource chunk
        LoadString(hInstance, IDS_APP_TITLE, szTitle, cuiMAX_LOADSTRING);
        LoadString(hInstance, IDC_APP_WCLASS, szWindowClass, cuiMAX_LOADSTRING);

        MyRegisterClass();

        if (!OpenWindow(nCmdShow))
            GUILOG_THROW_EXCEPTION(CGUIException(), "NStreamRuntime::Init: Could not initialize application.\n");
    }

    ATOM CStreamRuntimeStartup::MyRegisterClass()
    {
        WNDCLASSEX wcex;
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style = 0;
        wcex.lpfnWndProc = (WNDPROC)WndProc;
        wcex.cbClsExtra = 0;
        wcex.cbWndExtra = 0;
        wcex.hInstance = m_hInstance;
        wcex.hIcon = LoadIcon(m_hInstance, (LPCTSTR)IDI_APP_ICON);
        wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground = NULL;
        wcex.lpszMenuName = NULL;
        wcex.lpszClassName = szWindowClass;
        wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_APP_ICON_SMALL);

        return RegisterClassEx(&wcex);
    }

    BOOL CStreamRuntimeStartup::OpenWindow(int nCmdShow)
    {
        // Used for client area
        RECT aRect;
        SetRect(&aRect, 0, 0, GetScreenWidth(), GetScreenHeight());

        // Adjust the window size based on desired client area
        DWORD dwStyle = WS_SYSMENU | WS_CAPTION | WS_VISIBLE;

        if (IsWindowResizable())
        {
            //Resizable window;
            dwStyle |= WS_SIZEBOX;
        }

        AdjustWindowRect(&aRect, dwStyle, false);

        m_hWnd = CreateWindow(
            szWindowClass, szTitle, dwStyle,
            cuiWINDOWPOS_X, cuiWINDOWPOS_Y, aRect.right - aRect.left, aRect.bottom - aRect.top,
            NULL, NULL, m_hInstance, NULL);

        if (!m_hWnd)
        {
            return FALSE;
        }

        eC_Int caps;
        caps = GetDeviceCaps(GetDC(m_hWnd), BITSPIXEL);

        if (caps != 32 && caps != 16) // 16 or 32 Bit are the recommended color depth for windows
        {
            GUILOG(GUI_TRACE_WARNING, "Please choose a color depth of 16 or 32-Bit. \n");
        }

        ShowWindow(m_hWnd, nCmdShow);
        UpdateWindow(m_hWnd);
        return TRUE;
    }

    // Processes some of the windows OS messages that are sent to this application window.
    LRESULT CALLBACK CStreamRuntimeStartup::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
            case WM_PAINT:
                if (CGUI::IsCreated())
                {
                    PAINTSTRUCT ps;
                    BeginPaint(hWnd, &ps);

                    // reduce rect to screen size
                    GETGFX.InvalidateRect(
                        eC_FromInt(ps.rcPaint.left),
                        eC_FromInt(ps.rcPaint.top),
                        eC_FromInt(ps.rcPaint.right),
                        eC_FromInt(ps.rcPaint.bottom));
                    EndPaint(hWnd, &ps);
                }
                break;

            case WM_SIZE:
            {
                if (CGUI::IsCreated())
                {
                    GETGUI.SetWidth(eC_FromInt(LOWORD(lParam)));
                    GETGUI.SetHeight(eC_FromInt(HIWORD(lParam)));
                    GETGFX.SetScreenSize(LOWORD(lParam), HIWORD(lParam));

                    RECT rect;
                    GetClientRect(hWnd, &rect);
                    InvalidateRect(hWnd, &rect, FALSE);
                }
            }
            break;

            case WM_DESTROY:
                PostQuitMessage(0);
                break;

            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
}
