/*
	WinSTon

	Favourites File Loading/Saving
*/

#include "..\includes\winston.h"
#include "..\includes\debug.h"
#include "..\includes\dialog.h"
#include "..\includes\memory.h"
#include "..\includes\misc.h"

FAVOURITES Favourites;
ifstream infavourites;									// Input/Output favourite file
ofstream outfavourites;
FAVOURITE_FOLDER *pSelectedFolder;						// Selected folder
FAVOURITE_DISC *pSelectedDisc;							// Selected disc

//-----------------------------------------------------------------------
/*
	Add folder structure
*/
FAVOURITE_FOLDER *Favourites_AddFolder(FAVOURITE_FOLDER *pFolder)
{
	FAVOURITE_FOLDER *pNewFolder;

	// Allocate folder structure
	pNewFolder = (FAVOURITE_FOLDER *)Memory_Alloc(sizeof(FAVOURITE_FOLDER));
	memset(pNewFolder,0x0,sizeof(FAVOURITE_FOLDER));

	// Add as next folder
	pNewFolder->pNextFolder = pFolder->pNextChildFolder->pNextFolder;
	pNewFolder->pPrevFolder = (FAVOURITE_FOLDER *)MAKE_PARENT_POINTER(&pFolder->pNextChildFolder->pNextFolder);
	if (pFolder->pNextChildFolder->pNextFolder)
		pFolder->pNextChildFolder->pNextFolder->pPrevFolder = pNewFolder;
	pNewFolder->pParentFolder = pFolder;
	pFolder->pNextChildFolder->pNextFolder = pNewFolder;

	// Return structure
	return(pNewFolder);
}

//-----------------------------------------------------------------------
/*
	Add child folder structure
*/
FAVOURITE_FOLDER *Favourites_AddChildFolder(FAVOURITE_FOLDER *pFolder)
{
	FAVOURITE_FOLDER *pNewFolder;

	// Allocate folder structure
	pNewFolder = (FAVOURITE_FOLDER *)Memory_Alloc(sizeof(FAVOURITE_FOLDER));
	memset(pNewFolder,0x0,sizeof(FAVOURITE_FOLDER));

	// Add to folder, set parent mask
	pNewFolder->pNextChildFolder = pFolder->pNextChildFolder;
	pNewFolder->pPrevChildFolder = (FAVOURITE_FOLDER *)MAKE_PARENT_POINTER(&pFolder->pNextChildFolder);
	if (pFolder->pNextChildFolder)
		pFolder->pNextChildFolder->pPrevChildFolder = pNewFolder;
	pNewFolder->pParentFolder = pFolder;
	pFolder->pNextChildFolder = pNewFolder;

	// Return structure
	return(pNewFolder);
}

//-----------------------------------------------------------------------
/*
	Add disc structure to folder
*/
FAVOURITE_DISC *Favourites_AddDisc(FAVOURITE_FOLDER *pFolder)
{
	FAVOURITE_DISC *pNewDisc;

	// Allocate disc structure
	pNewDisc = (FAVOURITE_DISC *)Memory_Alloc(sizeof(FAVOURITE_DISC));
	memset(pNewDisc,0x0,sizeof(FAVOURITE_DISC));

	// Add to folder, set parent mask
	pNewDisc->pNextDisc = pFolder->pDiscs;
	pNewDisc->pPrevDisc = (FAVOURITE_DISC *)MAKE_PARENT_POINTER(&pFolder->pDiscs);
	if (pFolder->pDiscs)
		pFolder->pDiscs->pPrevDisc = pNewDisc;
	pFolder->pDiscs = pNewDisc;
	// Set pointer to folder which disc belongs to
	pNewDisc->pParentFolder = pFolder;
	// Set items
	pNewDisc->bDiscExists = TRUE;						// Default to TRUE
	pNewDisc->bAlreadyChecked = FALSE;					// Force to check for image

	// Return structure
	return(pNewDisc);
}

//-----------------------------------------------------------------------
/*
	Delete folder structure
*/
void Favourites_DeleteFolder(FAVOURITE_FOLDER *pFolder)
{
	// Bypass link
	if (pFolder->pNextFolder)
		pFolder->pNextFolder->pPrevFolder = pFolder->pPrevFolder;
	if (IS_PARENT_POINTER(pFolder->pPrevFolder))
		SET_PARENT_POINTER(pFolder->pPrevFolder) = (unsigned long)pFolder->pNextFolder;
	else
		pFolder->pPrevFolder->pNextFolder = pFolder->pNextFolder;

	// Free structure
	Memory_Free(pFolder);
}

//-----------------------------------------------------------------------
/*
	Delete child folder structure
*/
void Favourites_DeleteChildFolder(FAVOURITE_FOLDER *pFolder)
{
	// Set parent to point to next in line
	pFolder->pParentFolder->pNextChildFolder = pFolder->pNextFolder;
	if (pFolder->pNextFolder) {
		pFolder->pNextFolder->pPrevFolder = pFolder->pPrevFolder;
		pFolder->pNextFolder->pParentFolder = pFolder->pParentFolder;
	}

	// Free structure
	Memory_Free(pFolder);
}

//-----------------------------------------------------------------------
/*
	Delete disc structure from folder
*/
void Favourites_DeleteDisc(FAVOURITE_DISC *pDisc)
{
	// Bypass link
	if (pDisc->pNextDisc)
		pDisc->pNextDisc->pPrevDisc = pDisc->pPrevDisc;
	if (IS_PARENT_POINTER(pDisc->pPrevDisc))
		SET_PARENT_POINTER(pDisc->pPrevDisc) = (unsigned long)pDisc->pNextDisc;
	else
		pDisc->pPrevDisc->pNextDisc = pDisc->pNextDisc;
	// Free structure
	Memory_Free(pDisc);
}

//-----------------------------------------------------------------------
/*
	Recursive free disc structures from folder
*/
void Favourites_Free_ScanDiscs(FAVOURITE_DISC *pDisc)
{
	FAVOURITE_DISC *pNextDisc;

	// Free disc details
	while(pDisc) {
		pNextDisc = pDisc->pNextDisc;
		// And free structure
		Memory_Free(pDisc);

		pDisc = pNextDisc;
	}
}

//-----------------------------------------------------------------------
/*
	Recursive free folder structures(and discs)
*/
void Favourites_Free_ScanFolders(FAVOURITE_FOLDER *pFolder)
{
	FAVOURITE_FOLDER *pNextFolder;

	// Free folder details
	while(pFolder) {
		pNextFolder = pFolder->pNextFolder;

		// Free any discs in this folder
		Favourites_Free_ScanDiscs(pFolder->pDiscs);
		// Free any child folders
		Favourites_Free_ScanFolders(pFolder->pNextChildFolder);
		// And free structure
		Memory_Free(pFolder);

		pFolder = pNextFolder;
	}
}

//-----------------------------------------------------------------------
/*
	Delete folder, and all children/discs
*/
void Favourites_DeleteFolders(FAVOURITE_FOLDER *pFolder)
{
	// Delete any child folders/disc images
	Favourites_Free_ScanFolders(pFolder->pNextChildFolder);
	
	// Free any discs in this folder
	Favourites_Free_ScanDiscs(pFolder->pDiscs);
	// Remove parent
	if (pFolder->pPrevFolder==NULL)
		Favourites_DeleteChildFolder(pFolder);
	else
		Favourites_DeleteFolder(pFolder);
}

//-----------------------------------------------------------------------
/*
	Delete all folders
*/
void Favourites_DeleteAllFolders(void)
{
	FAVOURITE_FOLDER *pFolder;

	pFolder = Favourites.DiscImages.pNextChildFolder;
	while(pFolder) {
		// Delete this, and all sub folders/discs
		Favourites_DeleteFolders(pFolder);

		pFolder = Favourites.DiscImages.pNextChildFolder;
	}
}

//-----------------------------------------------------------------------
/*
	Clean Favourites file(reset item handles)
*/
void Favourites_Clean_ScanDiscs(FAVOURITE_DISC *pDisc)
{
	FAVOURITE_DISC *pNextDisc;

	// Clean disc details
	while(pDisc) {
		pNextDisc = pDisc->pNextDisc;
		// Clean
		pDisc->hItem = NULL;

		pDisc = pNextDisc;
	}
}

void Favourites_Clean_ScanFolders(FAVOURITE_FOLDER *pFolder)
{
	// Free folder details
	while(pFolder) {
		// Clean any discs in this folder
		Favourites_Clean_ScanDiscs(pFolder->pDiscs);
		// Clean any child folders
		Favourites_Clean_ScanFolders(pFolder->pNextChildFolder);
		// Clean
		pFolder->hItem = NULL;

		pFolder = pFolder->pNextFolder;
	}
}

void Favourites_Clean(void)
{
	// And recursively clean folders/discs
	Favourites_Clean_ScanFolders(Favourites.DiscImages.pNextChildFolder);
}

//-----------------------------------------------------------------------
/*
	Find Disc image structure by item handle
*/
void Favourites_FindDiscByHandle_ScanDiscs(FAVOURITE_DISC *pDisc,HTREEITEM hSelectedItem)
{
	// Scan disc details
	while(pDisc) {
		if (pDisc->hItem==hSelectedItem) {
			// Set global so causes recursive functions to exit
			pSelectedDisc = pDisc;
			return;
		}

		pDisc = pDisc->pNextDisc;
	}
}

void Favourites_FindDiscByHandle_ScanFolders(FAVOURITE_FOLDER *pFolder,HTREEITEM hItem)
{
	// Scan folder details
	while(pFolder && (pSelectedDisc==NULL)) {
		// Scan any discs in this folder
		Favourites_FindDiscByHandle_ScanDiscs(pFolder->pDiscs,hItem);
		if (pSelectedDisc==NULL)						// Scan any child folders			
			Favourites_FindDiscByHandle_ScanFolders(pFolder->pNextChildFolder,hItem);

		pFolder = pFolder->pNextFolder;
	}
}

FAVOURITE_DISC *Favourites_FindDiscByHandle(HTREEITEM hItem)
{
	// Scan through all disc images for handle match
	pSelectedDisc = NULL;
	Favourites_FindDiscByHandle_ScanFolders(Favourites.DiscImages.pNextChildFolder,hItem);
	// Now if we found a matching image it should be store in 'pSelectedDisc'
	return(pSelectedDisc);
}

//-----------------------------------------------------------------------
/*
	Find folder structure by item handle
*/
void Favourites_FindFolderByHandle_ScanFolders(FAVOURITE_FOLDER *pFolder,HTREEITEM hItem)
{
	// Scan folder details
	while(pFolder && (pSelectedFolder==NULL)) {
		if (pSelectedFolder==NULL) {					// Scan any child folders
			if (pFolder->hItem==hItem) {
				pSelectedFolder = pFolder;
				return;
			}
			Favourites_FindFolderByHandle_ScanFolders(pFolder->pNextChildFolder,hItem);
		}

		pFolder = pFolder->pNextFolder;
	}
}

FAVOURITE_FOLDER *Favourites_FindFolderByHandle(HTREEITEM hItem)
{
	// Scan through all folder for handle match
	pSelectedFolder = NULL;
	Favourites_FindFolderByHandle_ScanFolders(Favourites.DiscImages.pNextChildFolder,hItem);
	// Now if we found a matching image it should be store in 'pSelectedFolder'
	return(pSelectedFolder);
}

//-----------------------------------------------------------------------
/*
	Find folder for selected item(ie return folder or if disc return parent folder)
*/
FAVOURITE_FOLDER *Favourites_FindParentFolderByHandle(HTREEITEM hItem)
{
	FAVOURITE_FOLDER *pFolder;
	FAVOURITE_DISC *pDisc;

	// Is a folder?
	pFolder = Favourites_FindFolderByHandle(hItem);
	if (pFolder)
		return(pFolder);
	// Could be a disc image?
	pDisc = Favourites_FindDiscByHandle(hItem);
	if (pDisc)
		return(pDisc->pParentFolder);

	return(NULL);
}

//-----------------------------------------------------------------------
/*
	Open Favourites file, to load from
*/
BOOL Favourites_OpenForLoading(char *pszFileName)
{
	// Open favourites file
	infavourites.open(pszFileName);
	// OK?
	if (infavourites)
		return(TRUE);
	return(FALSE);
}

//-----------------------------------------------------------------------
/*
	Close Favourites file, to load from
*/
void Favourites_CloseForLoading(void)
{
	// Close favourites file
	infavourites.close();
}

//-----------------------------------------------------------------------
/*
	Open Favourites file, to save to
*/
BOOL Favourites_OpenForSaving(char *pszFileName)
{
	// Open favourites file
	outfavourites.open(pszFileName);
	// OK?
	if (outfavourites)
		return(TRUE);
	return(FALSE);
}

//-----------------------------------------------------------------------
/*
	Close Favourites file, to save to
*/
void Favourites_CloseForSaving(void)
{
	// Close favourites file
	outfavourites.close();
}

//-----------------------------------------------------------------------
/*
	Write KeyWord to Favourites file
*/
void Favourites_WriteKeyWord(char *pszKeyWord,char *pszKeyString,int Level)
{
	int i;

	// Output tab for depth, so is just easier to read
	for(i=0; i<Level; i++)
		outfavourites << "\t";

	// Do have KeyString to go with KeyWord?
	if (pszKeyString)
		outfavourites << pszKeyWord << pszKeyString << endl;
	else
		outfavourites << pszKeyWord << endl;
}

//-----------------------------------------------------------------------
/*
	Read KeyWord from Favourites file
	Splits file line, from format [KeyWord]String into two string, first is key word and second is string
*/
BOOL Favourites_ReadKeyWord(char *pszKeyWord,char *pszKeyString)
{
	char szWholeKeyString[MAX_KEYWORD+MAX_KEYSTRING];
	int i=0;

	// Clear output
	strcpy(pszKeyWord,"");
	strcpy(pszKeyString,"");

	// Read in string from file - eg '[KeyWord]String'
	if (!infavourites.eof()) {
		infavourites.getline(szWholeKeyString,MAX_KEYWORD+MAX_KEYSTRING);
		Misc_RemoveWhiteSpace(szWholeKeyString,sizeof(szWholeKeyString));
		// Split into two parts, scan for ]
		while(szWholeKeyString[i]!='\0') {
			// Is end of keyword, ie ']'
			if (szWholeKeyString[i]==']') {
				// Cut out keyword
				strcpy(pszKeyWord,szWholeKeyString);
				pszKeyWord[i+1] = '\0';
				// And string
				strcpy(pszKeyString,&szWholeKeyString[i+1]);
			}
			i++;
		}
		return(TRUE);
	}
	
	return(FALSE);										// EOF
}

//-----------------------------------------------------------------------
/*
	Return TRUE if two KeyWords match(ignore case)
*/
BOOL Favourites_KeyWordMatch(char *pszKeyWord,char *pszMatchKeyWord)
{
	// Do the two KeyWords match?
	if (!stricmp(pszKeyWord,pszMatchKeyWord))
		return(TRUE);
	return(FALSE);
}

//-----------------------------------------------------------------------
/*
	Load Favourites file
*/
void Favourites_Load(void)
{
	char szFileName[MAX_FILENAME_LENGTH];

	// Clear out(keep top-level folder, called 'Disc Images')
	memset(&Favourites,0x0,sizeof(FAVOURITES));
	strcpy(Favourites.DiscImages.szFolder,"Disc Images");

	// Open favourites file
	sprintf(szFileName,"%s\\%s",szWorkingDir,FAVOURITES_FILENAME);
	if (Favourites_OpenForLoading(szFileName)) {
		// And recursively Load folders/discs
		Favourites_Load_ScanFolders(&Favourites.DiscImages,NULL,0);
		// Close up
		Favourites_CloseForLoading();
	}
}

//-----------------------------------------------------------------------
/*
	Load Disc Image ([TITLE] to [ENDTITLE])
*/
void Favourites_Load_ScanDiscs(FAVOURITE_DISC *pDisc,int Level)
{
	char szKeyWord[MAX_KEYWORD],szKeyString[MAX_KEYSTRING];

	// Read in until end, or find [ENDTITLE]
	while(Favourites_ReadKeyWord(szKeyWord,szKeyString)) {
		if (Favourites_KeyWordMatch(szKeyWord,"[ENDTITLE]"))
			return;
		else if (Favourites_KeyWordMatch(szKeyWord,"[DISC1]"))
			strcpy(pDisc->szDiscImages[0],szKeyString);
		else if (Favourites_KeyWordMatch(szKeyWord,"[DISC2]"))
			strcpy(pDisc->szDiscImages[1],szKeyString);
		else if (Favourites_KeyWordMatch(szKeyWord,"[ALTDISC1]"))
			strcpy(pDisc->szDiscImages[2],szKeyString);
		else if (Favourites_KeyWordMatch(szKeyWord,"[ALTDISC2]"))
			strcpy(pDisc->szDiscImages[3],szKeyString);
		else if (Favourites_KeyWordMatch(szKeyWord,"[TOS]"))
			strcpy(pDisc->szTOSImage,szKeyString);
		else if (Favourites_KeyWordMatch(szKeyWord,"[URL]"))
			strcpy(pDisc->szURLAddress,szKeyString);
		else if (Favourites_KeyWordMatch(szKeyWord,"[FAILS]"))
			pDisc->bFails = TRUE;
	}
}

//-----------------------------------------------------------------------
/*
	Load Folder ([FOLDER] to [ENDFOLDER])
*/
void Favourites_Load_ScanFolders(FAVOURITE_FOLDER *pFolder,FAVOURITE_DISC *pDisc,int Level)
{
	char szKeyWord[MAX_KEYWORD],szKeyString[MAX_KEYSTRING];
	FAVOURITE_FOLDER *pNewFolder;
	FAVOURITE_DISC *pNewDisc;

	// Read KeyWords until end, or find [FOLDER]
	while(Favourites_ReadKeyWord(szKeyWord,szKeyString)) {
		// Is this a [FOLDER]?
		if (Favourites_KeyWordMatch(szKeyWord,"[FOLDER]")) {
			// Create structure for Folder
			if (pFolder->pNextChildFolder)
				pNewFolder = Favourites_AddFolder(pFolder);
			else
				pNewFolder = Favourites_AddChildFolder(pFolder);
			// Fill in details
			strcpy(pNewFolder->szFolder,szKeyString);
			// And lost into this
			Favourites_Load_ScanFolders(pNewFolder,pNewFolder->pDiscs,Level+1);
		} // [ENDFOLDER]?
		else if (Favourites_KeyWordMatch(szKeyWord,"[ENDFOLDER]")) {
			return;
		} // [TITLE]?
		else if (Favourites_KeyWordMatch(szKeyWord,"[TITLE]")) {
			// Create structure for Disc
			pNewDisc = Favourites_AddDisc(pFolder);
			// Fill in details
			strcpy(pNewDisc->szTitle,szKeyString);
			// Load disc
			Favourites_Load_ScanDiscs(pNewDisc,Level);
		} // [URLBASE]?
		else if (Favourites_KeyWordMatch(szKeyWord,"[URLBASE]")) {
			// URL base string(add to [URL] entries)
			// Add to global? or folder?
			if (pFolder==&Favourites.DiscImages)
				strcpy(Favourites.szURLBaseAddress,szKeyString);
			else
				strcpy(pFolder->szURLBaseAddress,szKeyString);
		}
	}
}

//-----------------------------------------------------------------------
/*
	Save Favourites file
*/
void Favourites_Save(void)
{
	char szFileName[MAX_FILENAME_LENGTH];

	// Has changed? If not, then ignore
	if (Favourites.bChanged) {
		// Create favourites file
		sprintf(szFileName,"%s\\%s",szWorkingDir,FAVOURITES_FILENAME);
		if (Favourites_OpenForSaving(szFileName)) {
			// Save string details
			if (strlen(Favourites.szURLBaseAddress)>0)
				Favourites_WriteKeyWord("[URLBASE]",Favourites.szURLBaseAddress,0);

			// And recursively save folders/discs
			Favourites_Save_ScanFolders(Favourites.DiscImages.pNextChildFolder,0);
			// Close up
			Favourites_CloseForSaving();
			// Reset 'changed' flag
			Favourites.bChanged = FALSE;
		}
	}
}

//-----------------------------------------------------------------------
/*
	Save Disc Image ([TITLE] to [ENDTITLE])
*/
void Favourites_Save_ScanDiscs(FAVOURITE_DISC *pDisc,int Level)
{
	// Save disc details
	while(pDisc) {
		// Save disc details
		Favourites_WriteKeyWord("[TITLE]",pDisc->szTitle,Level+1);
		if (strlen(pDisc->szDiscImages[0])>0)
			Favourites_WriteKeyWord("[DISC1]",pDisc->szDiscImages[0],Level+2);
		if (strlen(pDisc->szDiscImages[1])>0)
			Favourites_WriteKeyWord("[DISC2]",pDisc->szDiscImages[1],Level+2);
		if (strlen(pDisc->szDiscImages[2])>0)
			Favourites_WriteKeyWord("[ALTDISC1]",pDisc->szDiscImages[2],Level+2);
		if (strlen(pDisc->szDiscImages[3])>0)
			Favourites_WriteKeyWord("[ALTDISC2]",pDisc->szDiscImages[3],Level+2);
		if (strlen(pDisc->szTOSImage)>0)
			Favourites_WriteKeyWord("[TOS]",pDisc->szTOSImage,Level+2);
		if (strlen(pDisc->szURLAddress)>0)
			Favourites_WriteKeyWord("[URL]",pDisc->szURLAddress,Level+2);
		Favourites_WriteKeyWord("[ENDTITLE]",NULL,Level+1);

		pDisc = pDisc->pNextDisc;
	}
}

//-----------------------------------------------------------------------
/*
	Save Folder ([FOLDER] to [ENDFOLDER])
*/
void Favourites_Save_ScanFolders(FAVOURITE_FOLDER *pFolder,int Level)
{
	// Save folder details
	while(pFolder) {
		// Save this parent folder
		Favourites_WriteKeyWord("[FOLDER]",pFolder->szFolder,Level);
		// And folder URL
		if (strlen(pFolder->szURLBaseAddress)>0)
			Favourites_WriteKeyWord("[URLBASE]",pFolder->szURLBaseAddress,1);
		// Save any discs in this folder
		Favourites_Save_ScanDiscs(pFolder->pDiscs,Level);
		// Save any child folders
		Favourites_Save_ScanFolders(pFolder->pNextChildFolder,Level+1);
		Favourites_WriteKeyWord("[ENDFOLDER]",NULL,Level);

		pFolder = pFolder->pNextFolder;
	}
}

//-----------------------------------------------------------------------
/*
	Debug output of loaded favourites
*/
#ifdef DEBUG_TO_FILE
void Favourites_DisplayDiscs(FAVOURITE_DISC *pDiscs,int Level)
{
	while(pDiscs) {
		for(int i=0; i<Level; i++)
			debug << " ";
		debug << pDiscs->szTitle << "   " << pDiscs->pParentFolder << endl;

		pDiscs = pDiscs->pNextDisc;
	}
}

void Favourites_DisplayFolder(FAVOURITE_FOLDER *pFolder,int Level)
{
	while(pFolder) {
		for(int i=0; i<Level; i++)
			debug << " ";
		debug << pFolder->szFolder << " " << pFolder->pPrevFolder << "   " << pFolder->pParentFolder << endl;
		Favourites_DisplayDiscs(pFolder->pDiscs,Level+1);
		
		if (pFolder->pNextChildFolder)
			Favourites_DisplayFolder(pFolder->pNextChildFolder,Level+1);

		pFolder = pFolder->pNextFolder;
	}
}
#endif	//DEBUG_TO_FILE
