// DUiMan.cpp: implementation of the CDUiMan class.
//
//////////////////////////////////////////////////////////////////////

#include "DUiMan.h"
#include "DirectXHelpers.h"

DWORD     g_dwStartX = 10;
DWORD     g_dwStartY = 10;
CDUiMan *g_pDUiManager = NULL;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

HRESULT GetSurfaceDesc(DDSURFACEDESC *pddsurfdesc, LPDIRECTDRAWSURFACE pddsurf)
{
    memset(pddsurfdesc, 0, sizeof(DDSURFACEDESC));
    pddsurfdesc->dwSize = sizeof(DDSURFACEDESC);
    
    return pddsurf->GetSurfaceDesc(pddsurfdesc);
}

BOOL IsPrintable(UINT nChar)
{
    if ((nChar >= 0x20) && (nChar <= 'z'))
        return TRUE;
    else
        return FALSE;

}

DWORD GetFadeColor(DWORD dwSourceColor, DWORD dwFadeAmount)
{
    DWORD dwRed;
    DWORD dwGreen;
    DWORD dwBlue; 
    DWORD dwFadeColor;

    if (TRUE) //565
    {
        dwRed = ((dwSourceColor >> 11) & 0x1f);
        dwGreen = ((dwSourceColor >> 5) & 0x3f);
        dwBlue = ((dwSourceColor >> 11) & 0x1f);
        if (dwRed <= 15)
            dwRed += dwFadeAmount;
        else
            dwRed -= dwFadeAmount;

        if (dwGreen <= 31)
            dwGreen += (dwFadeAmount * 2);
        else
            dwGreen -= (dwFadeAmount * 2);

        if (dwBlue <= 15)
            dwBlue += dwFadeAmount;
        else
            dwBlue -= dwFadeAmount;
        dwFadeColor = _565(dwRed,dwGreen,dwBlue);
    }
    return dwFadeColor;
}

DWORD ColorToColorRef(DWORD dwSourceColor)
{
    DWORD dwRed;
    DWORD dwGreen;
    DWORD dwBlue; 
    DWORD dwRetVal = 0;
    if (TRUE) //565
    {
        dwRed = ((dwSourceColor >> 11) & 0x1f);
        dwGreen = ((dwSourceColor >> 5) & 0x3f);
        dwBlue = ((dwSourceColor >> 11) & 0x1f);
        //since the source color ranges are from 0 - 1f/3f and the dest are
        //from 0-ff bit shift to multiply/adjust colors into that range
        dwRetVal = ((dwBlue << 19) | (dwGreen << 10) | (dwRed << 3));
    }
    return dwRetVal;
}

BOOL  GetOutlineRect(CDUiObject *pObject, RECT *pRect)
{
    int iThickness = 2;
    int iMaxHeight = 480;
    int iMaxWidth = 640;
    pRect->left = pObject->GetXPosition();
    pRect->top = pObject->GetYPosition();
    pRect->right = pRect->left + pObject->GetWidth();
    pRect->bottom = pRect->top + pObject->GetHeight();

    if (pRect->left > iThickness)
        pRect->left -= iThickness;
    else
        pRect->left = 0;
    
    if (pRect->top > iThickness)
        pRect->top -= iThickness;
    else
        pRect->top = 0;
    
    if (pRect->right< (iMaxWidth - iThickness))
        pRect->right += iThickness;
    else
        pRect->right = iMaxWidth - 1;
    
    if (pRect->bottom < (iMaxHeight - iThickness))
        pRect->bottom += iThickness;
    else
        pRect->bottom = iMaxHeight - 1;

    return TRUE;
}

CDUiMan::CDUiMan()
{
    m_pddsBack = NULL;
    m_pddsPrimary = NULL;
    m_pDirectDraw = NULL;
    m_pDirectSound = NULL;

    m_dwDefaultPrimaryColor = _565(0,63,0); //0x0000FF00;
    m_dwDefaultBackgroundColor = _565(0,0,0); //0x00000000;
    m_wszDefaultFontName[0] = 0;
    m_dwDefaultFontColor = _565(0,63,0); //0x0000FF00;
    m_dwDefaultSelectOutlineColor = _565(31,63,31);
    m_dwDefaultSelectedFontColor = _565(15,32,15);

    m_wszLastSelectedWindowName[0] = 0;
    m_bShowDebugWindow = FALSE;
    m_pErrorWindow = NULL;
    m_pErrorDataList = NULL;
    m_pErrorMessageList = NULL;
    m_dwZOrderCounter = 0;
    m_pWindowList = new CDUiObjectList();
    m_pSelectedWindow = NULL;
    m_pDefaultFont = NULL;

    m_dwFontCount = 0;
#ifndef _WIN32_WCE
    DeleteFile(L"F:\\DUIMan.log");
#endif
}

CDUiMan::~CDUiMan()
{
    if (m_pddsBack)
    {
        m_pddsBack->Release();
        m_pddsBack = NULL;
    }
    if (m_pddsPrimary)
    {
        m_pddsPrimary->Release();
        m_pddsPrimary = NULL;
    }
    if (m_pDirectDraw)
    {
        m_pDirectDraw->Release();
        m_pDirectDraw = NULL;
    }
    delete m_pWindowList;
}

DWORD CDUiMan::Initialize(HINSTANCE hInstance, HWND hWnd)
{
    HRESULT hr = DD_OK;
    DDSURFACEDESC ddsd;         // DirectDraw Surface Descriptor
    CDUiText *pText;
    CDUiEditBox *pEdit = NULL;
    HDC hdc;
    WCHAR wszTemp[200];

    g_pDUiManager = this;
    m_hWnd = hWnd;
    m_hParentInstance = hInstance;

    // Find and create the proper DDraw device for our purposes.
    if ((hr = MyDirectDrawCreate(NULL,&m_pDirectDraw,NULL)) != DD_OK)
    {
        SetLastError(hr);
        return hr;
    }

    // Get exclusive mode.  Full-screen mode requires 'DDSCL_EXCLUSIVE'.
    if ((hr = m_pDirectDraw->SetCooperativeLevel(m_hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN))  != DD_OK)
    {
        SetLastError(hr);
        return hr;
    }
    // Set Display Mode
#ifdef _WIN32_WCE
    if ((hr = m_pDirectDraw->SetDisplayMode(640, 480, 16)) != DD_OK)
#else
    if ((hr = m_pDirectDraw->SetDisplayMode(1024, 768, 16)) != DD_OK)
#endif
    {
        SetLastError(hr);
        return hr;
    }

    // Setup to create the primary surface with 1 back buffer
    ddsd.dwSize            = sizeof(ddsd);
    ddsd.dwFlags           = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
    ddsd.ddsCaps.dwCaps    = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
    ddsd.dwBackBufferCount = 1;

    // Create the primary surface
    if ((hr = m_pDirectDraw->CreateSurface(&ddsd, &m_pddsPrimary, NULL)) != DD_OK)
    {
        SetLastError(hr);
        return hr;
    }

    // Get a pointer to the back buffer
    ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
    if ((hr = m_pddsPrimary->GetAttachedSurface(&ddsd.ddsCaps, &m_pddsBack)) != DD_OK)
    {
        SetLastError(hr);
        return hr;
    }

    //get font info
    if ((hr = m_pddsPrimary->GetDC(&hdc)) == DD_OK)
    {
        EnumFonts(hdc,NULL,(FONTENUMPROC)_EnumFontsFunc,(LPARAM)this);
        m_pddsPrimary->ReleaseDC(hdc);
    }
    else
    {
        SetLastError(hr);
        return hr;
    }
    
    if ((hr = MyDirectSoundCreate(NULL,&m_pDirectSound,NULL)) == DS_OK)
    {
        //hr = g_pDirectSound->Initialize(NULL);
        if ((hr = m_pDirectSound->SetCooperativeLevel(m_hWnd, DSSCL_NORMAL)) != S_OK)
            g_pDUiManager->DisplayDebugErrorf(L"SetCooperativeLevel Failed %08x",hr);
    }
    else
    {
        g_pDUiManager->DisplayDebugErrorf(L"DirectSoundCreate Failed %08x",hr);
    }

    //create the debugwindow
    if (m_pErrorWindow = CreateDUiWindow(L"DUiDebugWindow",0,0,640,480,0))
    {
        m_pErrorWindow->SetVisible(FALSE);
        if (IsFontAvailable(L"arial.ttf"))
        {
            SetDefaultFontName(L"arial.ttf");
        }
        else
        {
            if (GetFirstAvailableFont(wszTemp))
            {
                SetDefaultFontName(wszTemp);
            }
        }
        if (pText = (CDUiText *) m_pErrorWindow->CreateDUiObject(DUI_TEXT,L"Static",10,10,200,40,0))
        {
            pText->SetText(L"DUiDebugWindow");
            pText->Initialize();
        }

        if (m_pErrorMessageList = (CDUiListBox *) m_pErrorWindow->CreateDUiObject(DUI_LISTBOX,L"DUiDebugErrorMessageList",10,60,290,400,DUIS_LISTBOX_ALLOW_CLEAR))
        {
            m_pErrorMessageList->Initialize();
        }

        if (m_pErrorDataList = (CDUiListBox *) m_pErrorWindow->CreateDUiObject(DUI_LISTBOX,L"DUiDebugErrorDataList",310,60,290,400,DUIS_LISTBOX_ALLOW_CLEAR))
        {
            m_pErrorDataList->Initialize();
        }
    }
    
    return DD_OK;
}

LRESULT CDUiMan::WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
    switch (uMessage)
    {
    case WM_KEYDOWN:
        switch (wParam)
        {
        case VK_TAB:
            if (m_pSelectedWindow)
                m_pSelectedWindow->DoFocusChange();
            break;
        case VK_F2:
            break;
        default:
            if (m_pSelectedWindow)
                m_pSelectedWindow->OnKey(wParam,lParam);
            break;
        }
        break;
    case WM_SYSCHAR:
    case WM_CHAR:
        switch (wParam)
        {
        case 0:
        default:
            if (m_pSelectedWindow)
            {
                m_pSelectedWindow->OnChar(wParam,lParam);
            }
            break;
        }
        break;
    default:
        break;
    }

    return 0;
}

void CDUiMan::UpdateFrame()
{
    if (!DrawScene())
        return;
    
    FlipBuffers();
}

BOOL CDUiMan::GetDC(HDC *phDC)
{
    if (m_hDC)
    {
        *phDC = m_hDC;
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

CDUiFont *CDUiMan::GetDefaultFont()
{
    if (!m_pDefaultFont)
    {
        if (m_wszDefaultFontName[0])
        {
            m_pDefaultFont = CreateDUiFont(m_wszDefaultFontName,0);
            if (m_pDefaultFont->Initialize() != 0)
            {
                delete m_pDefaultFont;
                m_pDefaultFont = NULL;
            }
        }
    }
    return m_pDefaultFont;
}

BOOL CDUiMan::DrawScene()
{
    RECT rcDest = {0, 0, 640, 480};
    HRESULT     hr;
    DDBLTFX     ddbltfx;

    if (!m_pddsBack)
        return FALSE;

    memset(&ddbltfx,0,sizeof(DDBLTFX));
    ddbltfx.dwSize = sizeof(DDBLTFX);
    ddbltfx.dwFillColor = m_pSelectedWindow->GetBackgroundColor();
    m_pddsBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);

    CDUiObject *pTemp;
    m_pWindowList->Reset();
    while (pTemp = m_pWindowList->GetNextObject())
    {
        if (pTemp->GetVisible())
            pTemp->Display();
    }

    hr = m_pddsBack->GetDC(&m_hDC);
    m_pWindowList->Reset();
    while (pTemp = m_pWindowList->GetNextObject())
    {
        if (pTemp->GetVisible())
            pTemp->DisplayText();
    }
    hr = m_pddsBack->ReleaseDC(m_hDC);

    return TRUE;
}

void CDUiMan::FlipBuffers()
{
    HRESULT hr;
    if (!m_pddsPrimary)
        return;

    if ((hr = m_pddsPrimary->Flip(NULL, DDFLIP_WAIT)) != DD_OK)
    {
        SetLastError(hr);
    }
}


CDUiWindow *CDUiMan::CreateDUiWindow(WCHAR *wszWindowName, DWORD x, DWORD y, 
                                     DWORD dwWidth, DWORD dwHeight, DWORD dwStyle)
{
    CDUiWindow *pWindow = new CDUiWindow();

    pWindow->SetXPosition(x);
    pWindow->SetYPosition(y);
    pWindow->SetHeight(dwHeight);
    pWindow->SetWidth(dwWidth);
    pWindow->SetTabOrder(0);
    pWindow->SetName(wszWindowName);
    pWindow->SetBackgroundColor(m_dwDefaultBackgroundColor);
    pWindow->SetPrimaryColor(m_dwDefaultPrimaryColor);
    pWindow->SetZOrder(m_dwZOrderCounter++);
    pWindow->SetStyle(dwStyle);

    pWindow->m_pddsMain = m_pddsBack;
    m_pWindowList->AddObject(pWindow);

    if (!m_pSelectedWindow)
        m_pSelectedWindow = pWindow;

    return pWindow;
}

CDUiWave *CDUiMan::CreateDUiWave(WCHAR *wszWaveName, WCHAR *wszFileName, DWORD dwMode)
{
    CDUiWave *pWave = NULL; 
    CDUiObject *pTemp;
    WCHAR wszTemp[512];

    m_pWindowList->Reset();
    while (pTemp = m_pWindowList->GetNextObject())
    {
        if (pTemp->GetObjectType() == DUI_WAVE)
        {
            pWave = (CDUiWave *) pTemp;
            pWave->GetName(wszTemp);
            if (wcscmp(wszTemp,wszWaveName) == 0)
            {
                pWave->GetClipName(wszTemp);
                if (wcscmp(wszTemp,wszFileName) == 0)
                {
                    break;
                }
            }
        }
    }

    if (!pTemp)
    {
        pWave = new CDUiWave();
        pWave->SetName(wszWaveName);
        pWave->SetClipName(wszFileName);
        pWave->SetStyle(dwMode);
        pWave->m_pDirectSound = m_pDirectSound;
        m_pWindowList->AddObject(pWave);
    }

    return pWave;
}

CDUiFont *CDUiMan::CreateDUiFont(WCHAR *wszName, DWORD dwMode)
{
    CDUiFont *pFont = NULL; 
    CDUiObject *pTemp;
    WCHAR wszTemp[512];

    m_pWindowList->Reset();
    while (pTemp = m_pWindowList->GetNextObject())
    {
        if (pTemp->GetObjectType() == DUI_FONT)
        {
            pFont = (CDUiFont *) pTemp;
            pFont->GetName(wszTemp);
            if (wcscmp(wszTemp,wszName) == 0)
            {
                break;
            }
        }
    }

    if (!pTemp)
    {
        pFont = new CDUiFont();
        pFont->SetName(wszName);
        pFont->SetStyle(dwMode);
        m_pWindowList->AddObject(pFont);
    }

    return pFont;
}

BOOL CDUiMan::SelectWindow(WCHAR *wszName)
{
    BOOL bRetVal = FALSE;
    CDUiObject *pTemp;
    WCHAR wszTemp[200];
    m_pWindowList->Reset();
    if (m_pSelectedWindow)
    {
        m_pSelectedWindow->GetName(m_wszLastSelectedWindowName);
    }
    m_pSelectedWindow = NULL;

    while (pTemp = m_pWindowList->GetNextObject())
    {
        pTemp->GetName(wszTemp);
        if ((wcscmp(wszTemp,wszName) == 0) && (pTemp->GetObjectType() == DUI_WINDOW))
        {
            m_pSelectedWindow = (CDUiWindow *) pTemp;
            pTemp->SetVisible(TRUE);
            bRetVal = TRUE;
        }
        else
        {
            pTemp->SetVisible(FALSE);
        }
    }
    return bRetVal;
}

BOOL CDUiMan::SelectWindow(CDUiWindow *pWindow)
{
    BOOL bRetVal = FALSE;
    CDUiObject *pTemp;
    m_pWindowList->Reset();
    if (m_pSelectedWindow)
    {
        m_pSelectedWindow->GetName(m_wszLastSelectedWindowName);
    }
    m_pSelectedWindow = NULL;

    while (pTemp = m_pWindowList->GetNextObject())
    {
        if (pWindow == pTemp)
        {
            m_pSelectedWindow = (CDUiWindow *) pTemp;
            pTemp->SetVisible(TRUE);
            bRetVal = TRUE;
        }
        else
        {
            pTemp->SetVisible(FALSE);
        }
    }
    return bRetVal;
}

BOOL CDUiMan::SelectLastWindow()
{
    BOOL bRetVal = FALSE;
    
    if (m_wszLastSelectedWindowName[0])
    {
        bRetVal = SelectWindow(m_wszLastSelectedWindowName);
    }

    return bRetVal;
}

BOOL CDUiMan::GetNamedObject(WCHAR *wszName, CDUiObject **pObject)
{
    BOOL bRetVal = FALSE;
    CDUiObject *pTemp;
    WCHAR wszTemp[200];
    *pObject = NULL;
    m_pWindowList->Reset();
    while (pTemp = m_pWindowList->GetNextObject())
    {
        pTemp->GetName(wszTemp);
        if (wcscmp(wszTemp,wszName) == 0)
        {
            *pObject = pTemp;
            bRetVal = TRUE;
            break;
        }
    }
    return bRetVal;
}

void CDUiMan::DisplayDebugErrorf(WCHAR *wszMessage, ...)
{
    WCHAR wszTemp[512];

    va_list marker;
    va_start( marker, wszMessage );     
    wvsprintf(wszTemp,wszMessage,marker);

    if (m_pErrorMessageList)
        m_pErrorMessageList->AddString(wszTemp);

}

void CDUiMan::DisplayDebugDataf(WCHAR *wszMessage, ...)
{
    WCHAR wszTemp[512];

    va_list marker;
    va_start( marker, wszMessage );     
    wvsprintf(wszTemp,wszMessage,marker);

    if (m_pErrorDataList)
        m_pErrorDataList->AddString(wszTemp);

}

int CDUiMan::_EnumFontsFunc(LOGFONT *pLogFont, TEXTMETRIC *pMetric, DWORD dwType, LPARAM lpData)
{
    return ((CDUiMan *)lpData)->EnumFontsFunc(pLogFont,pMetric,dwType);
}

int CDUiMan::EnumFontsFunc(LOGFONT *pLogFont, TEXTMETRIC *pMetric, DWORD dwType)
{
    if (m_dwFontCount < 32)
    {
        wcscpy(m_wszFontNameArray[m_dwFontCount],pLogFont->lfFaceName);
        m_dwFontCount++;
        return 1;
    }
    else
    {
        return 0;
    }
}

BOOL CDUiMan::IsFontAvailable(WCHAR *wszFontName)
{
    BOOL bRetVal = FALSE;
    WCHAR wszTemp[40];
    WCHAR *wszPtr;
    DWORD i;

    wcscpy(wszTemp,wszFontName);
    wcsupr(wszTemp);
    if (wszPtr = wcsstr(wszTemp,L".TTF"))
    {
        *wszPtr = 0;
    }
    for (i = 0; i < m_dwFontCount; i++)
    {
        if (wcsicmp(m_wszFontNameArray[i],wszTemp) == 0)
        {
            bRetVal = TRUE;
            break;
        }
    }
    return bRetVal;
}

BOOL CDUiMan::GetFirstAvailableFont(WCHAR *wszFontName)
{
    BOOL bRetVal = FALSE;    

    if (m_dwFontCount)
    {
        wcscpy(wszFontName,m_wszFontNameArray[0]);
        bRetVal = TRUE;
    }

    return bRetVal;
}
