#include "main.h"

#include "./amnwatcher.h"
#include <shlobj.h>
#include <strsafe.h>

#include "playlists.h"
#include "PlaylistManager.h"
#include "PlaylistView.h"

waServiceFactory *AMNWatcher::watcherFactory = NULL;

BOOL IsMusicNowWantUs(void)
{
	HKEY key;
	DWORD value = 0, length = sizeof(DWORD);
	if (ERROR_SUCCESS == RegOpenKeyExW( HKEY_CURRENT_USER, L"Software\\AOL Music Now\\UserPreferences", 0, KEY_QUERY_VALUE, &key ))
	{
		long retCode = RegQueryValueExW(key, L"IntegrateWithWinamp", NULL, NULL, (LPBYTE) & value, &length);
		if (ERROR_SUCCESS != retCode) value = TRUE;
		RegCloseKey(key);
	}
	return value;
}

BOOL GetMusicNowPlaylistPath(LPWSTR *pathNew, LPWSTR *pathOld) // CAUTION!!! this function will allocate memory for the string using malloc
{
	// first check rgistry
	HKEY key;
	*pathNew = NULL;
	*pathOld = NULL;

	if (ERROR_SUCCESS == RegOpenKeyExW( HKEY_CURRENT_USER, L"Software\\AOL Music Now\\UserPreferences", 0, KEY_QUERY_VALUE, &key ))
	{
		const wchar_t *rPath = L"PlaylistDirectory";
		DWORD length;
		if (ERROR_SUCCESS == RegQueryValueExW(key, rPath, NULL, NULL, NULL, &length)) // try registry ( for future)
		{
			*pathNew = (LPWSTR)malloc(length);
			if (ERROR_SUCCESS != RegQueryValueExW(key, rPath, NULL, NULL, (LPBYTE)*pathNew, &length)) { free(*pathNew); *pathNew = NULL; }
		}
		RegCloseKey(key);
		
		if (*pathNew && !PathFileExists(*pathNew)) { free(*pathNew); *pathNew = NULL; } //check that path is actualy exist
		
		LPITEMIDLIST pidl;
		if (S_OK == SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl))
		{
			wchar_t path[MAX_PATH*4] = {0};
			if(SHGetPathFromIDListW(pidl, path))
			{
				const wchar_t *suffix = L"Music Now Playlists";
				int cchLen = lstrlenW(path) + lstrlenW(suffix) + 32; 
				if (!*pathNew) // no luck - use deafult's
				{
					*pathNew = (LPWSTR)malloc(cchLen*sizeof(wchar_t));
					StringCchPrintfW(*pathNew, cchLen, L"%s\\%s", path, suffix);
					if (!PathFileExists(*pathNew)) {free(*pathNew); *pathNew = NULL; }// i give up - can't find anything
				}
				// now let's try old path
				*pathOld = (LPWSTR)malloc(cchLen*sizeof(wchar_t));
				StringCchPrintfW(*pathOld, cchLen, L"%s\\AOL %s", path, suffix);
				if (!PathFileExists(*pathOld)) { free(*pathOld); *pathOld = NULL; }
			}
			CoTaskMemFree(pidl);
		}
	} 
	return (NULL != *pathNew) || (NULL != *pathOld);
}

AMNWatcher::AMNWatcher(void) : watcherOld(NULL), watcherNew(NULL), dirty(FALSE)
{}

AMNWatcher::~AMNWatcher(void)
{
	//Destroy(); // have to just let it leak. you should call Destroy() manually
}

int AMNWatcher::Init(api_service *service, const wchar_t *trackPath)
{
	BOOL retCode = FALSE;
	if (!IsMusicNowWantUs()) return retCode;
	if (watcherFactory) return retCode;
	
	LPWSTR pathNew, pathOld;
	if (!GetMusicNowPlaylistPath(&pathNew, &pathOld)) return retCode;
	int cchLen = lstrlenW(pathNew);
	if (cchLen > 1 && pathNew[cchLen -1] == L'\\') pathNew[cchLen -1] = 0x00;
	cchLen = lstrlenW(pathOld);
	if (cchLen > 1 && pathOld[cchLen -1] == L'\\') pathOld[cchLen -1] = 0x00;
 
	watcherFactory = service->service_getServiceByGuid(watcherGUID);
	if (watcherFactory)
	{
		if (pathNew) 
		{
			watcherNew = (api_watcher*)watcherFactory->getInterface();
			watcherNew->Create( L"WAMN_PLS_NEW", pathNew, TRUE, WATCHER_TRACKMODE_CENTRAL, OnWatcherNotify);
		}
		if (pathOld)
		{
			watcherOld = (api_watcher*)watcherFactory->getInterface();
			watcherOld->Create( L"WAMN_PLS_OLD", pathOld, TRUE, WATCHER_TRACKMODE_CENTRAL, OnWatcherNotify);
		}
		for (int i = 0; i < 2; i++)
		{
			api_watcher *watcher = (i) ? watcherOld : watcherNew;
			if (!watcher) continue;

			watcher->SetExtensionFilter(L"WPL", WATCHER_FILTERTYPE_INCLUDE);
			watcher->SetUserData(this);
			watcher->SetCallBack(OnWatcherNotify);
			watcher->SetTrackingPath(trackPath);
			watcher->Start();
			watcher->ForceScan(FALSE, SCANPRIORITY_IDLE);
		}
	}
	free(pathNew);
	free(pathOld);
	return TRUE;
}

void AMNWatcher::Destroy(void)
{
	if (watcherNew)
	{
		watcherNew->Stop();
		watcherFactory->releaseInterface(watcherNew);
		watcherNew = NULL;
	}
	if (watcherOld)
	{
		watcherOld->Stop();
		watcherFactory->releaseInterface(watcherOld);
		watcherOld = NULL;
	}
}

int AMNWatcher::OnWatcherNotify(api_watcher *sender, UINT message, LONG_PTR param, void* userdata)
{
	UNREFERENCED_PARAMETER(sender);

	AMNWatcher *watcher = (AMNWatcher*)userdata;
	if (WATCHER_MSG_FILE == message)
	{
		WATCHERCHANGEINFO *info = (WATCHERCHANGEINFO*)param;
		
		// ignore some names
		if (info->cchFile >= 21) // can be "AOL Music Now - Auido.wpl" or "AOL Music Now - Video.wpl"
		{
			const wchar_t *testname = info->file + info->cchFile - 21;
			if (CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, NULL, testname, 9, L"Music Now", 9)) return 1;
		}
		else if ( 17 == info->cchFile && CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, NULL, info->file, 13, L"AOL Music Now", 13)) return 1;
		
		wchar_t fullName[MAX_PATH*4];
		PathCombineW(fullName, info->path, info->file);

		size_t i(0);

		switch (info->state)
		{
		case WATCHER_FILESTATE_ADDED:
		case WATCHER_FILESTATE_CHANGED:
			{
				if (!info->file)
					break;
				wchar_t *title = _wcsdup(info->file);
				unsigned int len = lstrlen(title);
				while (len && title[len] != '.') len--;
				if (len != 0) title[len] = 0x00;
				while (i != playlists.size() && lstrcmpW(fullName, playlists.at(i).filename)) i++;
				if ( i == playlists.size())
				{
					AddPlaylist(title, fullName, TRUE, playlistManager->CountItems(fullName));
					watcher->dirty = TRUE;
				}
				else
				{
					int length = playlistManager->GetLengthMilliseconds(fullName);
					int numItems = (int)playlistManager->CountItems(fullName);
					if (playlists.at(i).length != length || playlists.at(i).numItems != numItems)
					{
						StringCchCopy(playlists.at(i).title, 1024, title);
						playlists.at(i).length = length;
						playlists.at(i).numItems = numItems;

						HWND hwnd = (HWND) SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_GETCURRENTVIEW);
						if (hwnd)
						{
							wchar_t* title = (wchar_t*)GetPropW(hwnd, L"TITLE");
							if (title && 0 == lstrcmp(title, playlists[i].title)) SendMessage(hwnd, WM_PLAYLIST_RELOAD, 0, 0);
						}
						watcher->dirty = TRUE;
					}

				}
				free(title);
			}
			break;
		case WATCHER_FILESTATE_REMOVED:
			{
				for ( i = 0; i < playlists.size(); i++)
				{
					if (0 == lstrcmpW(fullName, playlists.at(i).filename))
					{
						HWND hwnd = (HWND) SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_GETCURRENTVIEW);
						if (hwnd)
						{
							wchar_t* title = (wchar_t *)GetPropW(hwnd, L"TITLE");
							if (title && 0 == lstrcmp(title, playlists[i].title)) SendMessage(hwnd, WM_PLAYLIST_UNLOAD, 0, 0);
						}
						if (playlists.at(i).treeId) 
							mediaLibrary.RemoveTreeItem(playlists.at(i).treeId);
						playlists.eraseAt(i);
						i--;
						watcher->dirty = TRUE;
						break;
					}
				}
			}
			break;
		}
	}
	else if (WATCHER_MSG_STATUS == message)
	{
		if (STATUS_SCANER_STOPPED == param || STATUS_SCANER_FINISHED == param)
		{
			if (watcher->dirty)
			{
				SavePlaylists();
				RefreshPlaylistsList();
				watcher->dirty = FALSE;
			}

		}
	}


	return 1;
}