/*****************************************************************************
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.
*****************************************************************************/

// MinDlg.h: interface for the CMinDlg class.
//
//////////////////////////////////////////////////////////////////////

#pragma once

#include "ZWinDlg.h"

// Used by fnOnlySpaceAroundIt. Still use that function??
#define IGNORE_NONE   0
#define IGNORE_BEFORE 1
#define IGNORE_AFTER  2

// CONSTANTS FOR ALLOCATING SPACE ON PROGRESS BAR
// PROG_PCT_... from version 1 were absolute percentages, no longer.
// PROG_TIME_... new in v.2, divided by sum of whatever to get progress pct
//#define PROG_PCT_READ           5   // From version 1, no longer used

// These three total 90, now normalized for percentage allocated to shuffle.
// Originally defined in v.1 when RB_REPEAT_SEP was only option.
// In v.2-, RB_REPEAT_DIST only uses the total of these.
#define PROG_PCT_EA_ARR_SHUFFLE  10  // Used twice in total
#define PROG_PCT_SEP_DUPS_PT1    60
#define PROG_PCT_SEP_DUPS_PT2    10

// Used in setting multiplier for above
#define PROG_TIME_SHUFFLE_NORMAL  25
#define PROG_TIME_SHUFFLE_NO_SEP  10

#define PROG_PCT_WRITE           5 // Fixed percentage of total, same in v.2

//#define PROG_TIME_READ_LVIEW    5
//#define PROG_TIME_LOAD_WMP      5  // Usually not used, if cache thread finished

// Maybe ditch these three v.2 constants, use simple multiple per ListView row?
//#define PROG_TIME_ALL_SONGS    60
//#define PROG_TIME_NEW_SONGS    15
//#define PROG_TIME_PLAYLIST      8

// v.3 replace above?
// Use absolute numbers, multiply some, then adjust to total 95% of entire shuffle
#define PGRS_TIME_ONE_LV_ROW        45 // Time to add one CSongsSelection to main array
#define PGRS_TIME_WORKARR_TO_MAIN   35 // Copy working array to final array for write
#define PGRS_TIME_FILTER_MAIN       10 // Add to above if working exclusion array exists

// v.2 constants, renamed in v.3 for consistency. PGRS_TIME_LOAD_WMP value increased
#define PGRS_TIME_READ_LVIEW    5
#define PGRS_TIME_LOAD_WMP     10  // Usually not used, if cache thread finished



//// All cases read listview is 10%
//#define PB0_PCT_1LV    10
//
//// No All/New in the selection, playlist(s) only
//#define PB0_A0_PCT_2READ      40
//#define PB0_A0_PCT_3SHUFFLE   30
//#define PB0_A0_PCT_4WRITE     

// IF TEST OK MOVE TO ZWIN? // Macro works fine, but no real point
// #define FORLOOPS(nLoops) for(int Ix_ = 0; Ix_ < nLoops; Ix_ ++)



#define WMU_AFTERSHOW  WMU0 + 123

#define U_TIMER_PAINT   22583 // Recurring redraw of stars image

// Used for ListView LPARAMS.
// LPARAM 0 or higher is index playlist array. -1 to -999 is number of days * -1
#define N_LV_ROWTYPE_ALL  -10000 // Must be larger magnitude than possible days

#define SPACE_PADDING_LV_REPS 9

#define MAX_SONG_SELECTIONS   256


//#define SONG_MAX_REPEATS  256  in SongArray.h
#include "SongArray.h"

#include "wmp.h" // For member CComPtr<IWMPPlayer> declaration below
//#include <comutil.h> // For member _bstr_t declaration below

class CSongArray;
class CSongsSelection;
class CParentDlg;

BOOL MinDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);

class CMinDlg : public ZDlg  
{
public:
	CMinDlg(HINSTANCE hInst, CSettings * pSet, LPCTSTR sCapt1,
					LPCTSTR sCapt2 = NULL, ZWin * pOwner = NULL, ZWinAppData * pzwd = NULL);
	~CMinDlg();
	BOOL OwnProc(HWND hDlg, UINT uMsg, WPARAM wP, LPARAM lP);

   // Public for parent
  void Close();
  BOOL InProgress();
  void UpdatePref();
  void SetPaintMonitor(BOOL bShow);

  void CacheWmpData(); // Public to be called by by global background thread

  // These public for SelectDlg
  BOOL IsFirstSelectCall() { return !m_b1stSelectFinished; }
  void LogSelectDlgStartMsg(LPCTSTR sMsg);

protected:

  BOOL SongsSelToSongArr(CSongsSelection & songssel, CSongArray & songarr);

  CSongsSelection * GetSongSelForLvIx(INT nLvIx);

//  void OnBnTest();
  INT m_nTest;

  CSongsSelection * mpArr_SongsSelections[MAX_SONG_SELECTIONS];
  INT AvailableSongSelIx();
  LPCTSTR scPrefixGenre;
  LPCTSTR scPrefixPlist;
  void OnNotifyGetInfoTip(NMLVGETINFOTIP * plv);

  HWND m_hTipOrig; // Listview default tooltip
  HWND m_hTipLv;   // Replace with custom tooltip
//  BOOL ReplaceLvTooltip();
//  void OnNotifyTipDispInfo(NMTTDISPINFO * pdi);

//void OnNotifyAnyLv();   // TEST ///////////////////////////////////////////////////////////

  // For option to limit distributed output length so no song repeats.
  INT m_nMinSegmentSize;

  // Called by CacheWmpData
  BOOL CacheWmpDataSegmentOfAll(INT nIxStart, INT nIxEnd);

  //BOOL m_bPauseCaching;
  BOOL m_b1stSelectStarted;
  BOOL m_b1stSelectFinished;
  BOOL m_bStopCaching;
  BOOL m_bCacheFinished;
//  HANDLE m_hCacheThread;
//  void OnBnTestSrcWmp();
  CParentDlg* m_pParent;

  TCHAR m_sStartLogMsg[4096];
  TCHAR m_sStartLogSelectMsg[2048];
  TCHAR m_sStartLogPath[MAX_PATH];
  DWORD m_dwStartTime;
  void AddToStartLogMsg(LPCTSTR sMsg1, LPCTSTR sMsg2 = NULL, LPCTSTR sMsg3 = NULL);

  //BOOL m_bUseStarRatings; // Doesn't need to be member?

  // Both of these call CSelectDlg, but with different dialog resources
  void OnBnSource();
  void OnBnLvEdit();
  void LvItemNewOrEdit(INT nLvIx = -1);

  void OnBnLvRemove();

  BOOL LvCountStrToArray(LPCTSTR sCountStr, INT * naRet);
  BOOL LvCountStrToArray(INT nLvRowIndex, INT * naRet);
  void LvCountArrayToStr(INT* naCounts, LPTSTR sCounts);

  // Access to Windows Media Player library database
  void ReleaseWmpPointers(LPCTSTR sErrMsg = NULL, HRESULT hr = 0);
  CComPtr<IWMPPlayer> m_cpPlayer;  // Smart pointer to IWMPPlayer interface.
  CComPtr<IWMPPlaylistCollection> m_cpWmpPlaylistColl;
  CComPtr<IWMPPlaylistArray> m_cpWmpPlaylistArr;
  CComPtr<IWMPMediaCollection> m_cpWmpAllMedia; // Instead all media playlist member?
  CComPtr<IWMPPlaylist> m_cpWmpPlaylistAll;

  //BOOL LoadSongArray_All(CSongArray & songarray, UINT * uaReps, INT nMaxAge = 0);
  //BOOL LoadSongArray_Playlist(CSongArray & songarray, IWMPPlaylist *pPlaylist,
  //                            UINT * uaReps, INT nMaxAge = 0);

  //BOOL AddToSongArray(CSongArray & songarray, IWMPPlaylist *pPlaylist,
  //                    UINT * uaReps, INT nProgPctThis,
  //                    INT nAddType, INT nMaxAge = 0);

  // v.2
  BOOL AddToSongArrayWrapper(CSongArray & songarray,
                             IWMPPlaylist *pPlaylist, UINT * uaReps,
                             INT nProgPctThis, INT nAddType, LPCTSTR sProgPrefix, 
                             INT nMaxAge = 0);

  // V.3 add bDedup arg, change uaReps to INT, no longer default nMaxAge = 0
  BOOL AddToSongArrayWrapper(CSongArray & songarray, IWMPPlaylist *pPlaylist,
                             const INT * naReps, BOOL bDedup, FLOAT fProgPctThis,
                             INT nAddType, LPCTSTR sProgPrefix, INT nMaxAge);

  // V.2
  BOOL AddToSongArray(CSongArray & songarray, IWMPPlaylist *pPlaylist,
                      UINT * uaReps, INT nProgPctThis, INT nAddType,
                      INT nIxStart, INT nIxEnd, INT nPlaylistCount,
                      INT nYYYYMMDD_min_date, INT * npOldReject,
                      LPCTSTR sProgPrefix);

  // v.3 Add bDedup arg in AddToSongArray, handling for exclude.
  // Also change uaReps to INT, because now naReps[0] is -1 for exclude.
  BOOL AddToSongArray(CSongArray & songarray, IWMPPlaylist *pPlaylist,
                      const INT * naReps, FLOAT fProgPctThis, INT nAddType, BOOL bDedup,
                      INT nIxStart, INT nIxEnd, INT nPlaylistCount,
                      INT nYYYYMMDD_min_date, INT * npOldReject,
                      LPCTSTR sProgPrefix);


  INT SongRatingToStars(LPCTSTR sRating);
  INT SongRatingToStars(INT nRating);
//  INT m_nDefaultStars;

  BOOL YYYYMMDD_n_days_ago(INT nDaysAgo);

  BOOL m_bVistaOrLater;
  LPTSTR m_sAppendPlaylists; // Now member for use by both OnInitDialog & fnShuffleList

  // Conveniently use BSTR and CComBSTR as LPCTSTR, & vice versa
  //LPCTSTR b2t(BSTR & bs);
  //inline LPCTSTR CMinDlg::b2t(CComBSTR & cbs) { return b2t(cbs.m_str); }
  //TCHAR mb2t_sRet[8192]; // So caller to b2t doesn't have to free string
  ////const BSTR * t2b(LPCTSTR sSrc);
  //BSTR t2b(LPCTSTR sSrc);
  //_bstr_t mt2b_bsw; // So caller to t2b doesn't have to declare

  BOOL bDidFirstShow;
  void LoadWmpLibrary();
  void OnFirstShow(); // Wrapper mainly for LoadWmpLibrary, but maybe others


  LPCTSTR GetNextNumber(LPCTSTR spSpacesAndDigits, INT * nNextNum);

  LPCTSTR scNameAllSongs; // Constant after set in constructor
  LPCTSTR scPrefixNewSongs;

  RECT m_rcImgStars;
  HANDLE m_hnImgStars;

  HWND m_hList;
  BOOL fnListViewInitColumns();
 BOOL fnListViewInsertItem(LPCTSTR sName, INT nLparam, INT* naCounts);
//   BOOL fnListViewInsertItem(LPCTSTR sName, UINT* uaCounts);
	CSettings * ini;

  TCHAR m_sWmpPlaylistDir[MAX_PATH];

  HWND m_hProgress;
  HWND m_hProgText;
  HWND m_hSpinDist;
  HWND m_hSpinSep;
  HWND m_hSpinTrunc;
  HWND m_hSpinMaxReps;
  HWND m_hEdDist;
  HWND m_hEdSep;
  HWND m_hEdTrunc;
  HWND m_hEdMaxReps;
  BOOL m_bEdChangeBySpinner;
  HWND m_hRepeatTxt;
  HWND m_hSepOnlyTxt;

  HWND m_hNoRepsCk;
  HWND m_hNoRepsTxt;
  HWND m_hNoRepsRbMin;
  HWND m_hNoRepsRbMax;
  void EnableLimitNoReps();

  BOOL m_bInProgress;
  INT m_nProgPos;
  INT m_nProgLastPos;
  BOOL m_bAbort;


  LPCTSTR m_sFmtOneThirdAvgSep;
  LPCTSTR m_sFmtSepOnly;
  LPCTSTR m_sSepNowPureRandom;

  typedef struct SongListItem
  {
    INT nCount;  // Same as nCount for this song in the song array
    INT nListIxArr[SONG_MAX_REPEATS]; // Where placed. Only use first nCount elements
  } SongItem;

//  BOOL DistributeList(CSongArray * psa, INT nMinSepBetweenSongs, INT * nIxArrWholeList,
  BOOL DistributeList(CSongArray & saUnique, INT nMinSepBetweenSongs, INT * nIxArrWholeList,
                       INT nProgPctThisFn, INT * pnFailures); //, BOOL bWpl);

  BOOL AssignGroupToSegments(INT * nArrWholeList, INT nWholeListSize,
                             SongItem * pItems, INT * nArrIxGroup,
                             INT nGroupSize, INT nMinSepBetweenSongs,
                             INT nProgPctParentFn, CSongArray * sa,
                             INT * pnFailures);

  void OnBnShuffle();
  BOOL fnShuffleList(LPTSTR sPathRet, LPTSTR sRetMsg); //FLOAT * fTotalSecs);


  BOOL fnOnlySpaceAroundIt(LPCTSTR sLine, LPCTSTR sSubStr,
                           LPTSTR sError, UINT uIgnoreWhat = IGNORE_NONE);
  BOOL fnOnlySpaceBeforeIt(LPCTSTR sLine, LPCTSTR sSubStr, LPTSTR sError);
  BOOL fnOnlySpaceAfterIt(LPCTSTR sLine, LPCTSTR sSubStr, LPTSTR sError);

  BOOL fnShuffleNumArray(UINT * upArr, UINT uArrSize,
                         INT nProgPctThisFn, INT nProgPctSoFar);
  BOOL fnShuffleNumArrayByExch(UINT * upArr, UINT uArrSize,
                               INT nProgPctThisFn, INT nProgPctSoFar);

  //BOOL fnOutputNameFromSource(LPCTSTR sSrcPath, LPTSTR sOutPathOrName,
  //                        BOOL bFullPath = FALSE, BOOL bRequireExt = FALSE);
  void GetDefaultSaveName(LPTSTR sOutPathOrName);

  BOOL SeparateDups(CSongArray & songarr, UINT * upArr, UINT uMinSep);

  // Version 3.0 change BOOL bM3u to INT nPlistFmt for 3 options (add .m3u8)
  BOOL WritePlaylist(LPCTSTR sOutPath, CSongArray & songarr, UINT * upSongIndArr,
            INT nPlistFmt, INT nMax, LPCTSTR sWplTitle, LPTSTR sFinalOutDir); 

  INT WriteSongArrayToFile(HANDLE hFile, LPCTSTR sOutPath, CSongArray & songarr,
                           UINT * upSongIndArr, INT nMax,
//                           BOOL bM3u);
                           INT nPlistFmt, // Version 3.0 add 3rd option .m3u8
                           LPTSTR sFinalOutDir); // v3.22 for relative path option

  BOOL SetXmlCharsForWpl(LPTSTR sLine);

  void EnableControls(BOOL bNormalCtls);
  void OnNotifySpin(NMUPDOWN* pud);
  void OnEdWithSpinner(WPARAM wP, LPARAM lP);
  void OnWmPaint();

  BOOL OnInitDialog();
	//void OnBnClose();
  
  TCHAR m_sVersionNum[32];;
};
