/*****************************************************************************
Open Source MIT License

Copyright (c) 2017 Matthew Ahmed

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*****************************************************************************/

// PrefDlg.cpp: implementation of the CPrefDlg class.
//
//////////////////////////////////////////////////////////////////////

#include "Headers.h"
#include "resource.h"
#include "Settings.h"
#include "PrefDlg.h"
#include "ParentDlg.h"

CPrefDlg * pPrefDlg;

BOOL PrefDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	return pPrefDlg->OwnProc(hDlg, message, wParam, lParam);
}

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

CPrefDlg::CPrefDlg(HINSTANCE hInst, CSettings * pSet, // LPCTSTR sDirSlash,
								 LPCTSTR sCapt1, LPCTSTR sCapt2,
                 ZWin * pOwner, ZWinAppData * pzwd)
	: ZDlg(hInst, sCapt1, sCapt2, pOwner, pzwd)
{
	ini = pSet;
	pPrefDlg = this;
	m_pProc = PrefDlgProc;
	m_uID = IDD_PREF;

  //_tcscpy(m_sOwnDir, sDirSlash);
  //m_sOwnDir[_tcslen(sDirSlash) - 1] = '\0'; // Trim off trailing slash
  _tcscpy(m_sLogDir, pzwd->sAppDocsDirSlash);
  m_sLogDir[_tcslen(m_sLogDir) - 1] = _T('\0'); // Trim off trailing slash
  
  m_bEdChangeBySpinner = FALSE;
}

CPrefDlg::~CPrefDlg()
{

}

BOOL CPrefDlg::OwnProc(HWND hDlg, UINT uMsg, WPARAM wP, LPARAM lP)
{
 // NMUPDOWN* pud = NULL;

  NMUPDOWN* pud = NULL;
	switch (uMsg)
	{
    case WM_NOTIFY:
      pud = (NMUPDOWN*) lP;
      if (pud->hdr.code == UDN_DELTAPOS)
      {
        OnNotifySpin(pud); // Same handler for all, checks which control
        // Then drop through to return 0;
      }
      break;

		// Insert e.g. DTAKEMSG(WM_WHATEVER, OnWhatever); except for WM_COMMAND

    DSEEMSG(WM_PAINT, OnWmPaint);

// Don't bitch about no cases in WM_COMMAND's switch(wP) (warning 4065)
#pragma warning(push)
#pragma warning(disable : 4065)
		case WM_COMMAND:
			switch(LOWORD(wP))
			{
				// Insert e.g. DTAKECMD(IDC_BN_WHATEVER, OnWhatever);

// ==> MOVED TO LOG OPTIONS DIALOG
//        DSEECMDPARMS(IDC_CK_LOG, OnCkLog);

        DTAKECMD(IDC_BN_HELP, OnBnHelp);
        DSEECMD(IDCS_BN_RESET, OnBnReset);

        DSEECMDPARMS(IDCS_ED_SAME, OnEdReps);
        DSEECMDPARMS(IDCS_ED_STARS1, OnEdReps);
        DSEECMDPARMS(IDCS_ED_STARS2, OnEdReps);
        DSEECMDPARMS(IDCS_ED_STARS3, OnEdReps);
        DSEECMDPARMS(IDCS_ED_STARS4, OnEdReps);
        DSEECMDPARMS(IDCS_ED_STARS5, OnEdReps);

        DSEECMDPARMS(IDCC_ED_DEFSTARS, OnEdReps);

        default : break;

			} // END switch (wParam)
// Restore settings in effect at warning(push) above
#pragma warning(pop)

		default : break;
	} // END switch (uMsg)

	// ZDlg already calls OnInitDialog, OnOK, OnCancel, or returns FALSE
	return ZDlg::OwnProc(hDlg, uMsg, wP, lP);
}


BOOL CPrefDlg::OnInitDialog()
{
	SendMessage(m_hWnd, WM_SETICON, TRUE,
							(LPARAM) LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_MAIN)));
  
  // Store client coordinates for painting  stars image later
  GetControlRect(GetDlgItem(m_hWnd, IDCS_RECT_STARS), &m_rcImgStars);
  // OnWmPaint ensures img top-left will match, but make sure size does too.
  m_rcImgStars.right = m_rcImgStars.left + 235;
  m_rcImgStars.bottom = m_rcImgStars.top + 18;

  m_hnImgStars = LoadImage(m_hInst, MAKEINTRESOURCE(IDB_STARS_SPIN), IMAGE_BITMAP,
                           0, 0, LR_DEFAULTCOLOR); // LR_LOADTRANSPARENT);

  ini->SetDlg(m_hWnd);

  if (
      !ini->DlgRBsFromKey(ini->uRememberReps, IDCC_RB_REPS_PREV_ALWAYS,
                          IDCC_RB_REPS_DEFAULT) ||
      !ini->DlgCheckFromKey(ini->bSrcName, IDC_CK_INCL_SRC) ||
      !ini->DlgCheckFromKey(ini->bLabel, IDC_CK_LABEL) ||
      !ini->DlgEditFromKey(ini->sLabel, IDC_ED_LABEL) ||
      !ini->DlgRBsFromKey(ini->uLabelPlace, IDC_RB_LABEL_BEFORE, IDC_RB_LABEL_AFTER) ||
      !ini->DlgCheckFromKey(ini->bTgtDirLast, IDCC_CK_LAST_DIR) ||
//      !ini->DlgRBsFromKey(ini->ubConvertWpl, IDC_RB_FMT_WPL, IDC_RB_FMT_M3U) ||
      !ini->DlgCheckFromKey(ini->bWmpNotify, IDCC_CK_WMP_NOTIFY) ||

// ==> MOVED TO LOG OPTIONS DIALOG
//      !ini->DlgCheckFromKey(ini->bLog, IDC_CK_LOG) ||
//      // Just in case ini file messed up, make sure dependent log checkbox right
//      !ini->DlgCheckFromKey(ini->bLogFlush && ini->bLog, IDC_CK_LOG_FLUSH) ||
//      !ini->DlgCheckFromKey(ini->bElapsed, IDC_CK_ELAPSED) ||

      // New in version 3.0
      !ini->DlgRBsFromKey(ini->nListboxOrder, IDCC_RB_LB_GENRES_1ST, IDCC_RB_LB_PLISTS_1ST) ||
      // Boolean handled as INT, OK for only 2 RB's
      !ini->DlgRBsFromKey(ini->bDaysNewAsDate, IDCC_RB_NEW_NUM_DAYS, IDCC_RB_NEW_FIXED_DATE) ||

      !ini->DlgCheckFromKey(ini->bDate, IDC_CK_DATE) ||
//      !ini->DlgRBsFromKey(ini->nPlaylistFmt, IDCC_RB_FMT_LAST, IDCC_RB_FMT_M3U8) ||  // v3.22
      !ini->DlgRBsFromKey(ini->nPlaylistFmt, IDCC_RB_FMT_LAST, IDCC_RB_FMT_M3U) ||  // v3.3
      !ini->DlgCheckFromKey(ini->bSongRelativePath, IDCC_CK_RELATIVE_PATH) ||  // v3.22
      !ini->DlgRBsFromKey(ini->uDatePlace, IDC_RB_DATE_BEFORE, IDC_RB_DATE_AFTER))
  {
    ini->ShowError(m_sCapt, _T("Error applying ini file settings to dialog"));
  }

  TCHAR sTxt[32];
  INT naReps[6];
  naReps[0] = ini->nRepsSameDefault; // Option all songs same frequency
  naReps[1] = ini->nReps1Default;    // Frequency for song ratings, 1-5 stars
  naReps[2] = ini->nReps2Default;
  naReps[3] = ini->nReps3Default;
  naReps[4] = ini->nReps4Default;
  naReps[5] = ini->nReps5Default;

  for (INT i = 0; i <= 5; i++) // 1-5 is star ratings, 0 is same frequency for all
  {
    m_haSpins[i] = GetItem(IDCS_SPIN_SAME + i);
    SendMessage(m_haSpins[i], UDM_SETRANGE, 0, MAKELONG((i ? 99 : 98), 0));

// Let edit control do it, by leaving m_bEdChangeBySpinner FALSE
//                                                    // Why have to add 1 here to match ed?
//    SendMessage(mhk_haSpins[i], UDM_SETPOS, 0, MAKELONG((SHORT) (m_uaRepsDef[i] + 1), 0));
//    SendMessage(mhk_haSpins[i], UDM_SETPOS, 0, MAKELONG((SHORT) (m_uaRepsDef[i]), 0));

    m_haEds[i] = GetItem(IDCS_ED_SAME + i);
    SendMessage(m_haEds[i], EM_LIMITTEXT, 2, 0); // Already digits only
    _stprintf(sTxt, _T("%d"), naReps[i]);
    SetWindowText(m_haEds[i], sTxt);
  }

  // Default rating for unrated
  m_hDefSpin = GetItem(IDCC_SPIN_DEFSTARS);
  SendMessage(m_hDefSpin, UDM_SETRANGE, 0, MAKELONG(4, 0)); // for 1 to 5 stars
  m_hDefEd = GetItem(IDCC_ED_DEFSTARS);
  SendMessage(m_hDefEd, EM_LIMITTEXT, 1, 0); // Already digits only
  _stprintf(sTxt, _T("%d"), ini->nDefStars);
  SetWindowText(m_hDefEd, sTxt); // Will set spinner b/c m_bEdChangeBySpinner FALSE

// ==> MOVED TO LOG OPTIONS DIALOG
//  m_hCkLogFlush = GetItem(IDC_CK_LOG_FLUSH);
//  // Disable if Log button unchecked:
//  EnableWindow(m_hCkLogFlush, ini->bLog);

//  _stprintf(sBS, _T("Save log file in \"%s\" folder"),
//            m_sLogDir);
//  SetItemText(IDC_CK_LOG, sBS);

	//LPCTSTR sKey = "Software\\Microsoft\\MediaPlayer\\Player\\Settings";
 // if (ReadReg(HKEY_CURRENT_USER, sKey, "SaveAsDir", sBS, FALSE))
 //   SetItemText(IDC_TX_WMP_PLAYLIST_DIR, sBS);
 // else SetItemText(IDC_TX_WMP_PLAYLIST_DIR,
 //         "Playlist save folder is not in WMP settings, default to My Documents");

  return ZDlg::OnInitDialog(); // always TRUE
}

// Spin/edit copied almost exactly from SelectDlg.cpp, incl. same resource ID's
void CPrefDlg::OnNotifySpin(LPNMUPDOWN pud)
{
  m_bEdChangeBySpinner = TRUE; // Avoid feedback loop with associated edit handler

  HWND hSpin = pud->hdr.hwndFrom;
  HWND hEdit = NULL;
//  INT nEdMax = 99;   // Default correct for star ratings & same frequencies
  INT nAddToEd = 0;  // Default correct for star ratings
  INT nSpinMax = 99; // Default correct for star ratings
  for (INT i = 0; i <= 5; i++) // 1-5 is star ratings, 0 is same frequency for all
  {
    if (hSpin == m_haSpins[i])
    {
      hEdit = m_haEds[i];
      if (!i)
      {
        nSpinMax = 98; // Spinner max 98 is Edit max 99
        nAddToEd = 1;  // Spinner 0 is Edit 1
      }
      break;
    }
  }
  if (!hEdit) 
  {
    if (hSpin == m_hDefSpin)
    {
      hEdit = m_hDefEd;
      nSpinMax = 4; // Spinner max 4 is Edit max 5
      nAddToEd = 1;  // Spinner 0 is Edit 1
    }
    else
    {
      // Not set above, must be some spinner not relevant here
      m_bEdChangeBySpinner = FALSE;
      return;
    }
  }

  TCHAR sEdTxt[32];

//  // Raw sum could be -1 or 100; keep positive in range 0 to 99  <== FOR WRAPPING
//  INT nSpinCount = (nMax + pud->iPos + pud->iDelta) % (nMax + 1);

  // If goes outside min 0 or max 99, restore old value instead of wrapping
  INT nSpinCount = pud->iPos + pud->iDelta;
  BOOL bRestore = FALSE;
  if (nSpinCount < 0)
  {
    nSpinCount = 0;
    bRestore = TRUE;
  }
  if (nSpinCount > nSpinMax)
  {
    nSpinCount = nSpinMax;
    bRestore = TRUE;
  }
  if (bRestore)
  {
    SendMessage(hSpin, UDM_SETPOS, 0, MAKELONG((SHORT) nSpinCount + 1, 0));
  }

  _stprintf(sEdTxt, _T("%d"), nSpinCount + nAddToEd);
  SetWindowText(hEdit, sEdTxt);

  m_bEdChangeBySpinner = FALSE;
} // void CPrefDlg::OnNotifySpin(HWND hSpin, HWND hEdit, NMUPDOWN pud)

void CPrefDlg::OnEdReps(WPARAM wP, LPARAM lP)
{
  if (m_bEdChangeBySpinner ||   // Edit control was changed to match spinner
	    HIWORD(wP) != EN_CHANGE)  // Not the message we're interested in
    return;

  HWND hEdit = GetItem(LOWORD(wP));
  // Find spin control associated with this edit
  HWND hSpin = NULL;
  INT nMinEd = 0;
  for (INT i = 0; i <= 5; i++) // 1-5 is star ratings, 0 is same frequency for all
  {
    if (hEdit == m_haEds[i])
    {
      hSpin = m_haSpins[i];
      if (!i) nMinEd = 1;  // Edit value associated with spin value 0
      break;
    }
  }
  if (!hSpin) // Not set in loop above, don't know why, give up
  {
    if (hEdit == m_hDefEd)
    {
      hSpin = m_hDefSpin;
      nMinEd = 1;
    }
    else
      RET_V(_T("Can't find spin control associated with changed edit control"));
  }

  // Text manually edited. Update spin control for new number
  // Control is digits only, max chars limits value, so no invalid (sort of "")
  TCHAR sNum[6];
  GetWindowText(hEdit, sNum, 5);
  INT nSpin = _tstoi(sNum); // returns 0 if empty string

  if (nSpin < nMinEd // Can only happen w/ Same or Days edit; others nMinEd = 0
      || !sNum[0])   // Empty string, reset to minimum value
  {
    nSpin = nMinEd;
    _stprintf(sNum, _T("%d"), nMinEd);
    m_bEdChangeBySpinner = TRUE; // Not really, but prevents feedback from next:
    SetWindowText(hEdit, sNum);
    m_bEdChangeBySpinner = FALSE;
  }
             // Why have to add 1 to match ed here & in Init?
//  SendMessage(hSpin, UDM_SETPOS, 0, MAKELONG((SHORT) nSpin + 1, 0));
  // Huh now don't add, after fiddling with no wrap??
  SendMessage(hSpin, UDM_SETPOS, 0, MAKELONG((SHORT) nSpin - nMinEd, 0));
} // void CPrefDlg::OnEdReps(WPARAM wP, LPARAM lP)

void CPrefDlg::OnBnReset()
{
  m_bEdChangeBySpinner = FALSE; // Should already be, be sure

  // Init spin/edit controls.
  // 6 spins & edits, each group w/ consecutive ID's
  // Load original program defaults, defined in Settings.h
  UINT uaRepsDef[6];
  uaRepsDef[0] = UREPS_SAME_DEFAULT; // Option all songs same frequency
  uaRepsDef[1] = UREPS1_DEFAULT;   // Frequencies for song ratings, 1-5 stars
  uaRepsDef[2] = UREPS2_DEFAULT;
  uaRepsDef[3] = UREPS3_DEFAULT;
  uaRepsDef[4] = UREPS4_DEFAULT;
  uaRepsDef[5] = UREPS5_DEFAULT;

  TCHAR sTxt[32];
  for (INT i = 0; i <= 5; i++) // 1-5 is star ratings, 0 is same frequency for all
  {
    //SendMessage(m_haSpins[i], UDM_SETRANGE, 0, MAKELONG((i ? 99 : 98), 0));

    // Let edit control set spinner, by leaving m_bEdChangeBySpinner FALSE
    _stprintf(sTxt, _T("%u"), uaRepsDef[i]);
    SetWindowText(m_haEds[i], sTxt);
  }
}

/*
// ==> MOVED TO LOG OPTIONS DIALOG
void CPrefDlg::OnCkLog(WPARAM wP, LPARAM lP)
{
  if (HIWORD(wP) != BN_CLICKED) return; // Not what we're interested in

  // Always uncheck IDC_CK_LOG_FLUSH when uncheck IDC_CK_LOG; redundant on check 
  CheckBn(IDC_CK_LOG_FLUSH, FALSE);
  EnableWindow(m_hCkLogFlush, IsBnChecked(IDC_CK_LOG));
}
*/

void CPrefDlg::OnBnHelp()
{
  CParentDlg * pParent =  (CParentDlg *) m_pOwner;
  pParent->ShowHelp(_T("pl_pref.htm"));
}

void CPrefDlg::OnOk()
{
  // Check for default output file name that could overwrite source playlist
  if (IsBnChecked(IDC_CK_INCL_SRC)  // Uses source name in output name
      && !IsBnChecked(IDC_CK_LABEL) // Need one of these to make different
      && !IsBnChecked(IDC_CK_DATE))
  {
    nBS = MB(MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
            _T("You chose a default output file name with ONLY the source name,"),
            _T("which could overwrite an existing playlist used as the source."),
            _T("\nAre you sure you want to do this?\n"),
            _T("Click No, and then also check Include Label and/or Include Datestamp")
            _T("\nto ensure the default output file name will differ."));

    if (nBS != IDYES) return;
  }

  // Verify valid reps defaults before updating anything
  TCHAR sEdTxt[8];
  INT naReps[6];
  INT nAtLeastOneRatingNonZero = 0; // Really using as boolean

  for (INT i = 0; i <= 5; i++) // i = stars rating 1-5; 0 all same
  {
    // Consecutive resource IDs: IDCS_ED_STARS5 = IDCS_ED_STARS1 + 4
    GetItemText(IDCS_ED_STARS1 + i - 1, sEdTxt, 3);
    naReps[i] = _tstoi(sEdTxt); // _tstoi returns 0 if empty string
    if (i) nAtLeastOneRatingNonZero += naReps[i]; // Only for star ratings
  }

  if (!nAtLeastOneRatingNonZero)
  {
    fnErr(_T("All song-rating based play frequencies are set to 0 times."),
      _T("At least some song ratings must default to play 1 or more times"));
    return;
  }

  if (!naReps[0]) // Should be mechanically prevented, but just in case
  {
    fnErr(_T("All songs same frequency is set to 0."),
          _T("It must default to a positive number"));
    return;
  }

  // Since already have values, update ini vars directly
  ini->nRepsSameDefault = naReps[0];
  ini->nReps1Default = naReps[1];
  ini->nReps2Default = naReps[2];
  ini->nReps3Default = naReps[3];
  ini->nReps4Default = naReps[4];
  ini->nReps5Default = naReps[5];

  if (

      // New in version 3.0
      !ini->DlgRBsToKey(ini->nListboxOrder, IDCC_RB_LB_GENRES_1ST, IDCC_RB_LB_PLISTS_1ST) ||
      // Boolean handled as INT, OK for only 2 RB's
      !ini->DlgRBsToKey(ini->bDaysNewAsDate, IDCC_RB_NEW_NUM_DAYS, IDCC_RB_NEW_FIXED_DATE) ||

      !ini->WriteIniSection(ini->m_sectPref) )
  {
    ini->ShowError(m_sCapt, _T("Error saving 3.0 settings from dialog to ini file"));
  }


  if (
      !ini->DlgRBsToKey(ini->uRememberReps, IDCC_RB_REPS_PREV_ALWAYS,
                        IDCC_RB_REPS_DEFAULT) ||
      //!ini->DlgCheckToKey(ini->bSrcDirLast, IDC_CK_SRC_DIR) ||
      !ini->DlgCheckToKey(ini->bSrcName, IDC_CK_INCL_SRC) ||
      !ini->DlgCheckToKey(ini->bLabel, IDC_CK_LABEL) ||
      !ini->DlgEditToKey(ini->sLabel, IDC_ED_LABEL) ||
      !ini->DlgRBsToKey(ini->uLabelPlace, IDC_RB_LABEL_BEFORE, IDC_RB_LABEL_AFTER) ||
      !ini->DlgCheckToKey(ini->bDate, IDC_CK_DATE) ||
      !ini->DlgRBsToKey(ini->uDatePlace, IDC_RB_DATE_BEFORE, IDC_RB_DATE_AFTER) ||
      !ini->DlgCheckToKey(ini->bTgtDirLast, IDCC_CK_LAST_DIR) ||
      //!ini->DlgRBsToKey(ini->nPlaylistFmt, IDCC_RB_FMT_LAST, IDCC_RB_FMT_M3U8) ||  // v3.22
      !ini->DlgRBsToKey(ini->nPlaylistFmt, IDCC_RB_FMT_LAST, IDCC_RB_FMT_M3U) ||  // v3.3 changed order
      !ini->DlgCheckToKey(ini->bSongRelativePath, IDCC_CK_RELATIVE_PATH) ||  // v3.22
      !ini->DlgCheckToKey(ini->bWmpNotify, IDCC_CK_WMP_NOTIFY) ||
      !ini->DlgEditToKey(ini->nDefStars, IDCC_ED_DEFSTARS) ||

// ==> MOVED TO LOG OPTIONS DIALOG
//      !ini->DlgCheckToKey(ini->bLog, IDC_CK_LOG) ||
//      !ini->DlgCheckToKey(ini->bLogFlush, IDC_CK_LOG_FLUSH) ||
//      !ini->DlgCheckToKey(ini->bElapsed, IDC_CK_ELAPSED) ||

      // New in version 3.0
      !ini->DlgRBsToKey(ini->nListboxOrder, IDCC_RB_LB_GENRES_1ST, IDCC_RB_LB_PLISTS_1ST) ||
      // Boolean handled as INT, OK for only 2 RB's
      !ini->DlgRBsToKey(ini->bDaysNewAsDate, IDCC_RB_NEW_NUM_DAYS, IDCC_RB_NEW_FIXED_DATE) ||

      !ini->WriteIniSection(ini->m_sectPref) )
  {
    ini->ShowError(m_sCapt, _T("Error saving settings from dialog to ini file"));
  }

  // Special case for option to always use permananent default frequencies.
  // Just in case it's a change, replace remembered values with defaults
  if (ini->uRememberReps == UREPS_REMEMBER_NO)
  {
    ini->nReps1 = ini->nReps1Default; // Frequency for song ratings, 1-5 stars
    ini->nReps2 = ini->nReps2Default;
    ini->nReps3 = ini->nReps3Default;
    ini->nReps4 = ini->nReps4Default;
    ini->nReps5 = ini->nReps5Default;
    ini->nRepsSame = ini->nRepsSameDefault; // Option all songs same frequency
  }

	ZDlg::OnOk();
}

void CPrefDlg::OnWmPaint()
{
  HDC hdc = GetDC(m_hWnd);
  HDC image_dc = CreateCompatibleDC(hdc);
  SelectObject(image_dc, m_hnImgStars);

  BOOL bRet = TransparentBlt(
                  hdc,        // handle to destination DC
                  m_rcImgStars.left,   // x-coord of destination upper-left corner
                  m_rcImgStars.top,   // y-coord of destination upper-left corner
       // Make sure height/width right in OnInitDialolg
                  m_rcImgStars.right - m_rcImgStars.left,  // width & height of
                  m_rcImgStars.bottom - m_rcImgStars.top,  // destination rect
                  image_dc,         // handle to source DC
                  0,    // x-coord of source upper-left corner
                  0,    // y-coord of source upper-left corner
                  m_rcImgStars.right - m_rcImgStars.left, // source dimensions,
                  m_rcImgStars.bottom - m_rcImgStars.top, // must == destination
                  //0xFF0000  // color to make transparent
                  RGB(255, 0, 0)  // color to make transparent
              );

  DeleteDC(image_dc);     // Won't paint on subsequent calls without this
  ReleaseDC(m_hWnd, hdc); // Mem usage grows without this
}
