#include <stdio.h>
#include <windows.h>
#include "identifiers.h"
#include "qbtypes.h"
#include "songlistedit.h"
#include "songlistwrite.h"
#include "qbkey32.h"

 /* This program is free software. It comes without any warranty, to
 * the extent permitted by applicable law. You can redistribute it
 * and/or modify it under the terms of the Do What The Fuck You Want
 * To Public License, Version 2, as published by Sam Hocevar. See
 * http://sam.zoy.org/wtfpl/COPYING for more details. */

BOOL CALLBACK MainWindowProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK EditSongProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK EditTextProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);

char songlistName[DEFAULT_BUFFER] = ""; // Global to transfer it easily between dialogs...

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	HWND hDlg;
	MSG  msg;
	int status;

	initCRC32(); // For QBKeys...

	hDlg = CreateDialog(hThisInstance, "MainWindowDlg", 0, MainWindowProc);

	while ((status = GetMessage(&msg, 0, 0, 0)) != 0)
	{
		if (status == -1)
			return -1;
		if (!IsDialogMessage (hDlg, &msg))
		{
			TranslateMessage (&msg);
			DispatchMessage (&msg);
		}
	}

	return 0;
}

BOOL CALLBACK MainWindowProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	static HINSTANCE hInstance; // App instance
	static FILE *qbFile = NULL; // QB file (Only present when open and save)
	static QBReturnInfo *qbInfo = NULL; // Info to rebuild the QB
	static BOOL modifiedFile = FALSE; // Info about if the user should save the file before closing

	switch (msg)
	{
		case WM_INITDIALOG:
			hInstance = (HINSTANCE) GetWindowLong(hDlg, GWL_HINSTANCE);
			return TRUE;
			break;
		case WM_COMMAND:
			switch(LOWORD(wParam))
			{
				case MAIN_SONGLIST:
					switch(HIWORD(wParam))
					{
						case LBN_SELCHANGE:
							getSelectionData(hDlg, qbInfo);
							break;
					}
					return 0;
					break;
				case MAIN_BUTTON_ABOUT:
					DialogBox(hInstance, "AboutDlg", hDlg, AboutDlgProc);
					break;
				case MAIN_BUTTON_EDITTEXT:
					if (qbInfo != NULL)
					{
						if (DialogBoxParam(hInstance, "EditTextDlg", hDlg, EditTextProc, (LPARAM) qbInfo) == TRUE)
							modifiedFile = TRUE;
					}
					break;
				case MAIN_BUTTON_OPEN:
					qbFile = OpenSongList(hDlg, hInstance, songlistName);
					if (qbFile != NULL)
					{
						if (qbInfo != NULL)
							FreeQbInfo(qbInfo);
						qbInfo = ParseQB(hDlg, qbFile);
						if (qbInfo != NULL)
							makeListbox(hDlg, qbInfo);

						fclose(qbFile);
					}
					return 0;
					break;
				case MAIN_BUTTON_EDIT:
					{
						int selItem = SendDlgItemMessage(hDlg, MAIN_SONGLIST, LB_GETCURSEL, 0, 0); // Get selection to select it again later...
						if (DialogBoxParam(hInstance, "EditSongDlg", hDlg, EditSongProc, (LPARAM) qbInfo) == TRUE)
						{
							makeListbox(hDlg, qbInfo);
							SendDlgItemMessage(hDlg, MAIN_SONGLIST, LB_SETCURSEL, selItem, 0);
							modifiedFile = TRUE;
						}
						return 0;
					}
					break;
				case MAIN_BUTTON_SAVE:
					if (qbInfo == NULL)
					{
						MessageBox(hDlg, "You should open a file before saving... obviously?", NULL, MB_OK | MB_ICONERROR);
					}
					else
					{
						qbFile = OpenSongListWrite(hDlg, songlistName);
						if (qbFile != NULL)
						{
							WriteOutFile(hDlg, qbFile, qbInfo);
							fclose(qbFile);
							modifiedFile = FALSE;
						}
					}
					return 0;
					break;
				case MAIN_BUTTON_CLOSE:
					SendMessage(hDlg, WM_CLOSE, 0, 0);
					return 0;
					break;
			}
			return TRUE;
			break;
		case WM_CLOSE:
			if (WishToSave(hDlg, qbInfo, modifiedFile) == 0)
			{
				if (WishToSave(hDlg, qbInfo, modifiedFile) == 0)
				{
					// Reset all data to the initial values
					if (qbInfo != NULL)
					{
						FreeQbInfo(qbInfo);
						// qbInfo = NULL; Not required
					}

					/* Not needed for close 
					qbFile = NULL;
					songlistName[0] = '\0';
					SendDlgItemMessage(hDlg, MAIN_SONGLIST, LB_RESETCONTENT, 0, 0);
					SetDlgItemText(hDlg, MAIN_SONGINFO, "");
					modifiedFile = FALSE; */
				}
				DestroyWindow(hDlg);
			}

			return 0;
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
			break;
	}
	return FALSE;
}

BOOL CALLBACK EditSongProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	static HWND hSongDlg; // Main dialog
	static QBReturnInfo *qbInfo; // Rebuild info
	static QBSongInfo *selSong; // Selected song quick pointer

	switch (msg)
	{
		case WM_INITDIALOG:
			{
				int selItem;

				qbInfo = (QBReturnInfo *) lParam; // Get QB info...
				hSongDlg = (HWND) GetWindowLong(hDlg, GWL_HWNDPARENT); // Get parent window
				selItem = SendDlgItemMessage(hSongDlg, MAIN_SONGLIST, LB_GETCURSEL, 0, 0); // Get selection

				if (selItem == LB_ERR) // No selection = Close dialog
				{
					EndDialog(hDlg, FALSE);
					return FALSE;
				}
				
				selSong = qbInfo->songs[selItem]; // Quick pointer

				/* Name, author, year (edit) */
				// Limit size
				SendDlgItemMessage(hDlg, EDITSONG_NAME, EM_LIMITTEXT, EDIT_MAX - 1, 0);
				SendDlgItemMessage(hDlg, EDITSONG_AUTHOR, EM_LIMITTEXT, EDIT_MAX - 1, 0);
				SendDlgItemMessage(hDlg, EDITSONG_YEAR, EM_LIMITTEXT, EDIT_MAX - 1, 0);

				// Put exisiting things or lock...
				if (selSong->internalFlags & IS_SONGNAME) // Song name
					SetDlgItemText(hDlg, EDITSONG_NAME, selSong->songName);
				else
					SendDlgItemMessage(hDlg, EDITSONG_NAME, EM_SETREADONLY, TRUE, 0);

				if (selSong->internalFlags & IS_SONGAUTHOR) // Song author
					SetDlgItemText(hDlg, EDITSONG_AUTHOR, selSong->songAuthor);
				else
					SendDlgItemMessage(hDlg, EDITSONG_AUTHOR, EM_SETREADONLY, TRUE, 0);

				if (selSong->internalFlags & IS_SONGYEAR) // Song year
					SetDlgItemText(hDlg, EDITSONG_YEAR, selSong->songYear);
				else
					SendDlgItemMessage(hDlg, EDITSONG_YEAR, EM_SETREADONLY, TRUE, 0);
				
				/* Is original artist? (checkbox) */
				if ((selSong->internalFlags & IS_ISORIGINALARTIST) == 0) // Is not a cover?
					CheckDlgButton(hDlg, EDITSONG_ISORIGINALARTIST, BST_INDETERMINATE);
				else if (selSong->isOriginalArtist == 1)
					CheckDlgButton(hDlg, EDITSONG_ISORIGINALARTIST, BST_CHECKED);

				/* Artist text... (radio + combo + edit) */
				// Set up combo box
				SendDlgItemMessage(hDlg, EDITSONG_GROUP1_REFERENCE_OPTION, CB_ADDSTRING, 0, (LPARAM) qbInfo->textAsMadeFamousBy);
				SendDlgItemMessage(hDlg, EDITSONG_GROUP1_REFERENCE_OPTION, CB_ADDSTRING, 0, (LPARAM) qbInfo->textBy);

				// Set limit for edit
				SendDlgItemMessage(hDlg, EDITSONG_GROUP1_STRING_OPTION, EM_LIMITTEXT, EDIT_MAX - 1, 0);

				// Select options...
				if (selSong->internalFlags & IS_ARTISTTEXT) // As text
				{
					CheckRadioButton(hDlg, EDITSONG_GROUP1_REFERENCE, EDITSONG_GROUP1_STRING, EDITSONG_GROUP1_STRING);
					SetDlgItemText(hDlg, EDITSONG_GROUP1_STRING_OPTION, selSong->artistText);
				}
				else if (selSong->internalFlags & IS_ARTISTTEXTKEY) // As QBKey...
				{
					CheckRadioButton(hDlg, EDITSONG_GROUP1_REFERENCE, EDITSONG_GROUP1_STRING, EDITSONG_GROUP1_REFERENCE);
					
					if (selSong ->artistTextKey == makeQBKey("artist_text_as_made_famous_by"))
						SendDlgItemMessage(hDlg, EDITSONG_GROUP1_REFERENCE_OPTION, CB_SETCURSEL, 0, 0);
					else if (selSong ->artistTextKey == makeQBKey("artist_text_by"))
						SendDlgItemMessage(hDlg, EDITSONG_GROUP1_REFERENCE_OPTION, CB_SETCURSEL, 1, 0);
				}

				// Offset

				if ((selSong->internalFlags & IS_INPUTOFFSET) && (selSong->internalFlags & IS_GEMOFFSET)) // Chart offset (Input + gem)
					SetDlgItemInt(hDlg, EDITSONG_CHARTOFFSET, selSong->inputOffset, TRUE);
				else
					SendDlgItemMessage(hDlg, EDITSONG_CHARTOFFSET, EM_SETREADONLY, TRUE, 0);

				return TRUE;
			}
			break;
		case WM_COMMAND:
			switch(LOWORD(wParam))
			{
				case EDITSONG_ISORIGINALARTIST:
					if (HIWORD(wParam) == BN_CLICKED)
					{
						switch(IsDlgButtonChecked(hDlg, EDITSONG_ISORIGINALARTIST))
						{
							case BST_CHECKED:
								CheckDlgButton(hDlg, EDITSONG_ISORIGINALARTIST, BST_UNCHECKED);
								break;
							case BST_UNCHECKED:
								CheckDlgButton(hDlg, EDITSONG_ISORIGINALARTIST, BST_CHECKED);
								break;
						}
					}
					break;
				case IDOK:
					{
						int selIndex;

						// Name, author, year
						GetDlgItemText(hDlg, EDITSONG_NAME, selSong->songName, EDIT_MAX);
						GetDlgItemText(hDlg, EDITSONG_AUTHOR, selSong->songAuthor, EDIT_MAX);
						GetDlgItemText(hDlg, EDITSONG_YEAR, selSong->songYear, EDIT_MAX);

						// Original artist...
						switch(IsDlgButtonChecked(hDlg, EDITSONG_ISORIGINALARTIST))
						{
							case BST_CHECKED:
								selSong->isOriginalArtist = 1;
								break;
							case BST_UNCHECKED:
								selSong->isOriginalArtist = 0;
								break;
						}

						// Artist text
						if (SendDlgItemMessage(hDlg, EDITSONG_GROUP1_REFERENCE, BM_GETCHECK, 0, 0) == BST_CHECKED) // QBKey
						{
							selIndex = SendDlgItemMessage(hDlg, EDITSONG_GROUP1_REFERENCE_OPTION, CB_GETCURSEL, 0, 0);
							if (selIndex != CB_ERR)
							{
								if (selSong->internalFlags & IS_ARTISTTEXT) // Disable it if enabled
									selSong->internalFlags -= IS_ARTISTTEXT;

								selSong->internalFlags |= IS_ARTISTTEXTKEY;

								if (selIndex == 0)
									selSong->artistTextKey = makeQBKey("artist_text_as_made_famous_by");
								else if (selIndex == 1)
									selSong->artistTextKey = makeQBKey("artist_text_by");
								else
								{
									// Should not happen, put a default value...
									MessageBox(hDlg, "INTERNAL ERROR: (Using default value)", NULL, MB_OK | MB_ICONERROR);
									selSong->artistTextKey = makeQBKey("artist_text_by");
								}
							}
						}
						else if(SendDlgItemMessage(hDlg, EDITSONG_GROUP1_STRING, BM_GETCHECK, 0, 0) == BST_CHECKED) // String
						{
							if (selSong->internalFlags & IS_ARTISTTEXTKEY) // Disable it if enabled
								selSong->internalFlags -= IS_ARTISTTEXTKEY;

							selSong->internalFlags |= IS_ARTISTTEXT;

							GetDlgItemText(hDlg, EDITSONG_GROUP1_STRING_OPTION, selSong->artistText, EDIT_MAX);
						}

						// Offsets
						selSong->inputOffset = GetDlgItemInt(hDlg, EDITSONG_CHARTOFFSET, NULL, TRUE);
						selSong->gemOffset = GetDlgItemInt(hDlg, EDITSONG_CHARTOFFSET, NULL, TRUE);

						// Clean info...
						SetDlgItemText(hSongDlg, MAIN_SONGINFO, "");
						EndDialog(hDlg, TRUE);
					}
					break;
				case IDCANCEL:
					EndDialog(hDlg, FALSE);
					break;
			}
			return TRUE;
			break;
		case WM_CLOSE:
			EndDialog(hDlg, FALSE);
			return 0;
			break;
	}

	return FALSE;
}

BOOL CALLBACK EditTextProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	static QBReturnInfo *qbInfo;

    switch (msg)                  /* manipulador del mensaje */
    {
        case WM_INITDIALOG:
			qbInfo = (QBReturnInfo *) lParam;

			SendDlgItemMessage(hDlg, EDITTEXT_ASMADEFAMOUSBY, EM_LIMITTEXT, EDIT_MAX - 1, 0);
			SendDlgItemMessage(hDlg, EDITTEXT_BY, EM_LIMITTEXT, EDIT_MAX - 1, 0);

			SetDlgItemText(hDlg, EDITTEXT_ASMADEFAMOUSBY, qbInfo->textAsMadeFamousBy);
			SetDlgItemText(hDlg, EDITTEXT_BY, qbInfo->textBy);
           return TRUE;
        case WM_COMMAND:
			switch(LOWORD(wParam))
			{
				case IDOK:
					GetDlgItemText(hDlg, EDITTEXT_ASMADEFAMOUSBY, qbInfo->textAsMadeFamousBy, EDIT_MAX);
					GetDlgItemText(hDlg, EDITTEXT_BY, qbInfo->textBy, EDIT_MAX);
					EndDialog(hDlg, TRUE);
					break;
				case IDCANCEL:
					EndDialog(hDlg, FALSE);
					break;
			}
			return 0;
			break;
		case WM_CLOSE:
           EndDialog(hDlg, FALSE);
           return 0;
    }
    return FALSE;
}

BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_INITDIALOG:
           return TRUE;
		case WM_COMMAND:
		case WM_CLOSE:
           EndDialog(hDlg, FALSE);
           return TRUE;
    }
    return FALSE;
}