#include "sol.h"
VSZASSERT




VOID *PAlloc(INT cb)
{
    TCHAR *p;

    // KLUDGE: solve overwriting memory by allocating more
    #define MEMORYPAD 200
    p = (TCHAR *)LocalAlloc(LPTR, cb+MEMORYPAD);
    Assert(p != NULL);
    return (VOID *)p;
}


VOID FreeP(VOID *p)
{
    LocalFree((HANDLE) p);
}



VOID InvertRc(RC *prc)
{
    Assert(xOrgCur == 0);
    Assert(yOrgCur == 0);
    AssertHdcCur();

    InvertRect(hdcCur, (LPRECT) prc);
}


VOID DrawCard(CRD *pcrd)
{
    AssertHdcCur();
    cdtDrawExt( hdcCur,
                pcrd->pt.x-xOrgCur,
                pcrd->pt.y-yOrgCur,
                dxCrd,
                dyCrd,
                pcrd->fUp ? pcrd->cd : modeFaceDown,
                pcrd->fUp ? FACEUP : FACEDOWN,
                rgbTable);
}


VOID DrawOutline(PT *ppt, INT ccrd, DX dx, DY dy)
{
    Y y;
    PT pt;
    INT rop2;
    if(!FGetHdc())
        return;

    pt = *ppt;

    rop2 = SetROP2(hdcCur, R2_NOT);
    MMoveTo(hdcCur, pt.x, pt.y);
    LineTo(hdcCur, pt.x+dxCrd, pt.y);
    LineTo(hdcCur, pt.x+dxCrd, y = pt.y+dyCrd+(ccrd-1) * dy);
    LineTo(hdcCur, pt.x, y);
    LineTo(hdcCur, pt.x, pt.y);
    y = pt.y;
    while(--ccrd)
    {
        y += dy;
        MMoveTo(hdcCur, pt.x, y);
        LineTo(hdcCur, pt.x+dxCrd, y);
    }
    SetROP2(hdcCur, rop2);
    ReleaseHdc();
}

VOID DrawCardPt(CRD *pcrd, PT *ppt)
{
    DWORD dwModeExt=0;     // turn on sign bit if moving fast
                           // cdtDrawExt must support this!

    if( fKlondWinner )
    {
        dwModeExt= MINLONG;
    }

    AssertHdcCur();
    cdtDrawExt(hdcCur,
               ppt->x-xOrgCur,
               ppt->y-yOrgCur,
               dxCrd,
               dyCrd,
               pcrd->fUp ? pcrd->cd : modeFaceDown,
               (pcrd->fUp ? FACEUP : FACEDOWN ) | dwModeExt,
               rgbTable);
}

VOID DrawCardExt(PT *ppt, INT cd, INT mode)
{
    VOID DrawBackground();

    AssertHdcCur();

    cdtDrawExt( hdcCur,
                ppt->x-xOrgCur,
                ppt->y-yOrgCur,
                dxCrd,
                dyCrd,
                cd,
                mode,
                rgbTable);
}


VOID DrawBackground(X xLeft, Y yTop, X xRight, Y yBot)
{
    HBRUSH hbr;


    AssertHdcCur();
    MSetBrushOrg(hdcCur, xOrgCur, yOrgCur);
    MUnrealizeObject(hbrTable);
    if((hbr = SelectObject(hdcCur, hbrTable)) != NULL)
    {
        Assert(xRight >= xLeft);
        Assert(yBot >= yTop);
        PatBlt( hdcCur,
                xLeft-xOrgCur,
                yTop-yOrgCur,
                xRight-xLeft,
                yBot-yTop,
                PATCOPY);
        SelectObject(hdcCur, hbr);
    }
}


VOID EraseScreen(VOID)
{
    RC rc;
    HDC HdcSet();

    if(!FGetHdc())
        return;
    GetClientRect(hwndApp, (LPRECT) &rc);
    DrawBackground(rc.xLeft, rc.yTop, rc.xRight, rc.yBot);
    ReleaseHdc();
}





BOOL FPtInCrd(CRD *pcrd, PT pt)
{

    return(pt.x >= pcrd->pt.x && pt.x < pcrd->pt.x+dxCrd &&
             pt.y >= pcrd->pt.y && pt.y < pcrd->pt.y+dyCrd);
}




BOOL FRectIsect(RC *prc1, RC *prc2)
{
    RC rcDummy;

    return(IntersectRect((LPRECT) &rcDummy, (LPRECT) prc1, (LPRECT) prc2));
}


VOID CrdRcFromPt(PT *ppt, RC *prc)
{
    prc->xRight = (prc->xLeft = ppt->x) + dxCrd;
    prc->yBot = (prc->yTop = ppt->y) + dyCrd;
}


BOOL FCrdRectIsect(CRD *pcrd, RC *prc)
{
    RC rcDummy;
    RC rcCrd;

    CrdRcFromPt(&pcrd->pt, &rcCrd);
    return(IntersectRect((LPRECT) &rcDummy, (LPRECT) &rcCrd, (LPRECT) prc));
}

/* BUG: only considers upper left and lower right corners */
/* this is ok for my purposes now, but beware... */
BOOL FRectAllVisible(HDC hdc, RC *prc)
{
    return PtVisible(hdc, prc->xLeft, prc->yTop) && PtVisible(hdc, prc->xRight, prc->yBot);
}


VOID OffsetPt(PT *ppt, DEL *pdel, PT *pptDest)
{
    pptDest->x = ppt->x + pdel->dx;
    pptDest->y = ppt->y + pdel->dy;
}


VOID SwapCards(CRD *pcrd1, CRD *pcrd2)
{
    CRD crdT;

    crdT = *pcrd1;
    *pcrd1 = *pcrd2;
    *pcrd2 = crdT;
}





TCHAR *PszCopy(TCHAR *pszFrom, TCHAR *rgchTo)
{
    while (*rgchTo++ = *pszFrom++)
        ;
    return(rgchTo-1);
}



INT CchDecodeInt(TCHAR *rgch, INT_PTR w)
{
    INT fNeg;
    TCHAR *pch, *pchT;
    TCHAR rgchT[20];

    if (fNeg = w<0)
        w = -w;

    pchT = rgchT;
    do
    {
        *pchT++ = (TCHAR)(TEXT('0') + (TCHAR) (w % 10));
        w /= 10;
    }
    while (w);
    pch = rgch;
    if (fNeg)
        *pch++ = TEXT('-');
    do
        *pch++ = *--pchT;
    while (pchT > rgchT);
    *pch = TEXT('\000');
    return((INT)(pch - rgch));
}

VOID Error(TCHAR *sz)
{

    MessageBox(hwndApp, (LPTSTR)sz, (LPTSTR)szAppName, MB_OK|MB_ICONEXCLAMATION);
}

/* returns fTrue if yes is clicked  */
BOOL FYesNoAlert( INT ids )
{
    TCHAR sz[128];
    INT id;

    CchString(sz, ids, ARRAYSIZE(sz));
    id = MessageBox(hwndApp, sz, szAppName, MB_YESNO|MB_ICONEXCLAMATION);
    return id == IDYES || id == IDOK;
}


VOID ErrorIds(INT ids)
{
    TCHAR sz[128];

    CchString(sz, ids, ARRAYSIZE(sz));
    Error(sz);
}

INT WMin(INT w1, INT w2)
{
    return(w1 < w2 ? w1 : w2);
}


INT WMax(INT w1, INT w2)
{
    return(w1 > w2 ? w1 : w2);
}


BOOL FInRange(INT w, INT wFirst, INT wLast)
{
    Assert(wFirst <= wLast);
    return(w >= wFirst && w <= wLast);
}


INT PegRange(INT w, INT wFirst, INT wLast)
{
    Assert(wFirst <= wLast);
    if(w < wFirst)
        return wFirst;
    else if(w > wLast)
        return wLast;
    else
        return w;
}


VOID OOM()
{
    Error(szOOM);
}

VOID NYI()
{
    Error(TEXT("Not Yet Implemented"));
}

INT CchString(TCHAR *sz, INT ids, UINT cchBuf)
{
    return LoadString(hinstApp, (WORD)ids, (LPTSTR)sz, cchBuf);
}



BOOL FWriteIniString(INT idsTopic, INT idsItem, TCHAR *szValue)
{
    TCHAR szItem[32];
    HKEY  hKey;          // key to our registry root
    LONG  lStatus;       // status from RegCreateKey
    INT   iLen;
    BOOL  fRet = FALSE;

    // create the key
    lStatus = RegCreateKeyEx(HKEY_CURRENT_USER, SOLKEYNAME, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
    if(lStatus != ERROR_SUCCESS)
    {
        return FALSE;         // just return quietly
    }

    CchString(szItem, idsItem, ARRAYSIZE(szItem));
    iLen = (lstrlen(szValue)+1) * sizeof(TCHAR);

    // write the key and value to the registry
    if (RegSetValueEx(hKey, szItem, 0, REG_SZ, (BYTE*)szValue, iLen) == ERROR_SUCCESS)    
        fRet = TRUE;
    else
        fRet = FALSE;

    RegCloseKey(hKey);
    return fRet;
}

BOOL FWriteIniInt(INT idsTopic, INT idsItem, DWORD w)
{
    TCHAR szItem[32];
    HKEY  hKey;          // key to our registry root
    LONG  lStatus;       // status from RegCreateKey
    BOOL  fRet = FALSE;

    // create the key
    lStatus = RegCreateKeyEx(HKEY_CURRENT_USER, SOLKEYNAME, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
    if(lStatus != ERROR_SUCCESS)
    {
        return FALSE;         // just return quietly
    }

    CchString(szItem, idsItem, ARRAYSIZE(szItem));

    // write the key and value to the registry
    if (RegSetValueEx(hKey, szItem, 0, REG_DWORD, (BYTE*) &w, sizeof(DWORD)) == ERROR_SUCCESS)
       fRet = TRUE;
    else
        fRet = FALSE;

    RegCloseKey(hKey);
    return fRet;

}


BOOL FGetIniString(INT idsTopic, INT idsItem, TCHAR *sz, TCHAR *szDefault, INT cchMax)
{
    TCHAR szItem[32];
    HKEY  hKey;          // key to our registry root
    LONG  lStatus;
    DWORD dwType;

    // open the key 
    lStatus = RegCreateKeyEx(HKEY_CURRENT_USER, SOLKEYNAME, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
    if(lStatus != ERROR_SUCCESS)
    {
        CopyMemory(sz, szDefault, min(cchMax, lstrlen(szDefault)+1));
        return TRUE;
    }

    CchString(szItem, idsItem, ARRAYSIZE(szItem));

    if(hKey)
    {
        lStatus= RegQueryValueEx(hKey, szItem, NULL, &dwType, (BYTE*) szDefault, &cchMax);
        RegCloseKey(hKey);

        if(lStatus != ERROR_SUCCESS || dwType != REG_SZ)
        {
            CopyMemory(sz, szDefault, min(cchMax, lstrlen(szDefault)+1));
        }
    }

    return TRUE;
}


DWORD GetIniInt(INT idsTopic, INT idsItem, DWORD wDefault)
{
    TCHAR szItem[32];
    HKEY  hKey;          // key to our registry root
    LONG  lStatus;
    DWORD dwResult = wDefault;
    DWORD dwSize = sizeof(DWORD);
    DWORD dwType = 0;

    lStatus = RegCreateKeyEx(HKEY_CURRENT_USER, SOLKEYNAME, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
    if(lStatus != ERROR_SUCCESS)
    {
        return wDefault;
    }

    CchString(szItem, idsItem, ARRAYSIZE(szItem));

    if(hKey)
    {
        lStatus = RegQueryValueEx(hKey, szItem, NULL, &dwType, (BYTE*) &dwResult, &dwSize);
        RegCloseKey(hKey);

        if(lStatus != ERROR_SUCCESS || dwType != REG_DWORD)
        {
            dwResult = wDefault;
        }
    }

    return(dwResult);

}