//	Album List for Winamp
//	Copyright (C) 1999-2001 Safai Ma
//
//	This program is free software; you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation; either version 2 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program; if not, write to the Free Software
//	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#ifndef __ALBUMLIST_H__
#define __ALBUMLIST_H__

#include "fileinfo.h"
#include "util.h"

#define ALBUMLISTSIZE_INC	16

//////////////////////////////////////////////////////////////////
// ALBUMINFO struct
//
// stores album information

typedef struct _TAGALBUMINFO
{
	char name[MAX_PATH];		// display name (combination of artist and album)
	char album[MAX_PATH];		// album name
	char artist[MAX_PATH];		// artist name
	char path[MAX_PATH];		// directory path
	char m3u_path[MAX_PATH];	// pathname of playlist (if exist)
	int  nTotalTime;			// total time in the directory (or playlist)
	int  nCount;				// number of files in this directory (or playlist)
	int  nYear;					// year of this album
	DWORD dwFlags;				// flags

#define AI_CDROM	0x00000001	// this is on CD-ROM
#define AI_SHORTCUT	0x00000002	// this is a shortcut (*.lnk)

}	ALBUMINFO, *LPALBUMINFO;

//////////////////////////////////////////////////////////////////

typedef struct _TAGTRACKINFO
{
	char path[MAX_PATH];		// full path of the track
	int  nTrack;				// track number

}	TRACKINFO, *LPTRACKINFO;

//////////////////////////////////////////////////////////////////

typedef struct _TAGTRACKINFOEX
{
	char path[MAX_PATH];		// full path of the track
	int  nTrack;				// track number
	char desc[MAX_PATH];		// #EXTINF:...

}	TRACKINFOEX, *LPTRACKINFOEX;

//////////////////////////////////////////////////////////////////

typedef struct _TAGFILEREADER
{
	HMODULE		hModule;			// instance handle
	int			nIndex;
	char		exts[MAX_PATH];		// extensions (separated by "space")
	char	   *(WINAPI *pGetExt)(int);	// create function
	CFileInfo  *(WINAPI *pCreate)(int);	// create function

}	FILEREADER, *LPFILEREADER;

//////////////////////////////////////////////////////////////////
// CAlbumArray class

class CAlbumArray : public CPtrArray
{
public:
	CAlbumArray();
	virtual ~CAlbumArray();

public:
	int Add(LPALBUMINFO pAlbumInfo);
	void SetAt(int nIndex, LPALBUMINFO pAlbumInfo);

	LPALBUMINFO operator[](int nIndex);

	void Sort();
	static int Compare(const void *elem1, const void *elem2);
};

//////////////////////////////////////////////////////////////////
// CTrackArray class

class CTrackArray : public CPtrArray
{
public:
	CTrackArray();
	virtual ~CTrackArray();

public:
	int Add(LPTRACKINFO pTrackInfo);

	LPTRACKINFO operator[](int nIndex);

	BOOL Sort(int sortname);
	static int Compare(const void *elem1, const void *elem2);

protected:
	static BOOL m_bDuplicate;
	static int	m_nSortName;
};

//////////////////////////////////////////////////////////////////
// CTrackExArray class

class CTrackExArray : public CTrackArray
{
public:
	int Add(LPTRACKINFOEX pTrackInfo);

	LPTRACKINFOEX operator[](int nIndex);
};

//////////////////////////////////////////////////////////////////
// SCANDIR struct
//
// used in the scanning of album directories

typedef struct _TAGSCANDIR
{
	char path[MAX_PATH];		// path to scan
	LPALBUMINFO pAlbumInfo;
	int  nAction;				// 0 - add, 1 - remove, 2 - remove old, 3 - add CD, 4 - remove not in search path
	struct _TAGSCANDIR *pNext;	// pointer to the next scan directory

}	SCANDIR, *LPSCANDIR;

//////////////////////////////////////////////////////////////////
// CAlbumList class

class CAlbumList
{
public:
	CAlbumList();				// constructor
	virtual ~CAlbumList();		// destructor

public:
	// implementation
	void Startup			(HWND hWnd);	// initializes with AL window handle
	void Refresh			();				// re-scan all directories
	void Shutdown			();				// clean-up

	// list management
	void AddMP3ToList		(char *path, BOOL bCD = FALSE);
	void AddMP3CDsToList	();
	void RemoveMP3FromList	(char *path);
	void StopScanning		(char *path);
	void RemoveOMP3FromList	();
	void RemoveMP3NotInSearchPath();

	// actions
	void ShuffleAlbums		();
	void Resort				();
	BOOL WritePlaylist		(HWND hWnd, int nIndex);
	BOOL PlayAlbum			(LPALBUMINFO album);
	BOOL EnqueueAlbum		(LPALBUMINFO album);
	void RefreshAlbum		(int nIndex) { RefreshAlbum(GetAlbum(nIndex)); }
	void RefreshAlbum		(LPALBUMINFO album);
	void ExportList			();
	void SwapAlbum			(int from, int to);

	// queries
	int GetSize				();
	LPALBUMINFO GetAlbum	(int i);
	int GetTotalTime		();

	// archive
	void WriteAlbumList		();
	BOOL ReadAlbumList		();

	int GetAlbumIndex		(char *path);

private:
	// member variables
	CAlbumArray m_AlbumList;				// array of album list
	CPtrArray	m_FileReaders;				// array of file readers
	HWND		m_hWnd;						// handle to the AL window
	int			m_nTotalTime;				// total time of all the albums
	int			m_nRootLen;					// root directory (string length)
	char		m_szCurrentDir[MAX_PATH];	// root directory
	BOOL		m_bStopScanning;			// indicate whether to stop scanning
	DWORD		m_dwCDROMs;

	// thread related variables
	HANDLE		m_hEvent;					// event handle
	HANDLE		m_hThread;					// thread handle
	DWORD		m_dwThreadId;				// thread ID
	LPSCANDIR	m_pScanDir;					// pointer to scan directory list (link list)

private:
	// private functions
	BOOL PlayDirectory			(LPALBUMINFO album, BOOL bEnqueue = FALSE, BOOL bStartPlay = TRUE);
	BOOL PlayM3U				(LPALBUMINFO album, BOOL bEnqueue = FALSE, BOOL bStartPlay = TRUE);

	void CreateAlbumDisplayName	(char *path, LPALBUMINFO pAlbumInfo);

	BOOL GetAlbumInfo			(char *path, char *name, LPALBUMINFO pAlbumInfo);
	BOOL GetAlbumInfoFromM3U	(char *path, char *name, LPALBUMINFO pAlbumInfo);

	void LoadAlbumBitmap		(LPALBUMINFO pAlbumInfo);

	BOOL AddAlbum				(LPALBUMINFO pAlbumInfo);
	BOOL AddAlbumsToList		(char *path, BOOL bIgnoreM3U);
	void RemoveAlbumsFromList	(char *path);
	void RemoveOldAlbumsFromList();
	void RemoveAlbumsNotInSearchPath();
	void RefreshAlbumThread		(LPALBUMINFO pAlbumInfo);

	BOOL CheckSubDirectories	(char *path, WIN32_FIND_DATA *file);
	BOOL PathExists				(char *path);
	BOOL M3UExists				(char *path, char *filename);
	BOOL IsCDROM				(LPCTSTR path);

	CFileInfo *CreateFileInfo	(LPCTSTR szFile);
	void AddFileReader			(char *reader);
	void LoadExternalFileReader	();
	void UnloadExternalFileReader();

	void FixTitles				(char *str);
	void StripTrailingSpaces	(char *str, int len);
	BOOL IsDirMultiDisc			(char *album);

	// thread function for scanning directories
	static DWORD WINAPI ThreadProc(LPVOID lpParameter);
};

//////////////////////////////////////////////////////////////////
// inline functions

inline int CAlbumList::GetSize()
{ 
	return m_AlbumList.GetSize();
}

inline LPALBUMINFO CAlbumList::GetAlbum(int i)
{
	return m_AlbumList[i];
}

inline int CAlbumList::GetTotalTime(void)
{
	return m_nTotalTime;
}

inline int CAlbumList::GetAlbumIndex(char *path)
{
	if (path == NULL) return -1;
	if (lstrlen(path) == 0) return -1;

	int size = m_AlbumList.GetSize();
	for (int i=0; i<size; i++)
	{
		LPALBUMINFO pAlbumInfo = m_AlbumList[i];
		if ((lstrcmp(pAlbumInfo->m3u_path, path) == 0) ||
			(lstrcmp(pAlbumInfo->path, path) == 0))
		{
			return i;
		}
	}

	return -1;
}

#endif /* __ALBUMLIST_H__ */
