/*

				Diagnostic Console
	 
*/

#include "netfone.h"

#define MAX_CONSOLE_SCROLL_LENGTH	29800			// Maximum scrollable text in console before prune from top

//	CONSOLEHELP  --  Print help text on console

static void consoleHelp(void)
{
	consoleLog("args      Echo command arguments");
	consoleLog("help      Print this message.");
	consoleLog("rate [r]  Query / set output rate.");
}

//	CONSOLEPROCESSCOMMAND  --  Process commands entered in the console input field

static void consoleProcessCommand(HWND hwnd)
{
	int n;
	char s[256];
#define MAXARGS	10
	char *args[MAXARGS];
	int nargs = 0;
	char *cp, *cpo;
	BOOL inquote = FALSE;

	if ((n = GetDlgItemText(hwnd, IDC_CONSOLE_INPUT, s, sizeof(s) - 2)) > 0) {
		//	Trim trailing spaces
		while ((n > 0) && isspace(s[n - 1])) {
			n--;
		}

		if (n > 0) {

			//	Parse command into arguments

			cp = s;
			while ((*cp != 0) && isspace(*cp)) {
				cp++;				// Ignore leading space
			}
			cpo = s;
			args[nargs++] = cpo;
			while (*cp != 0) {
				if ((*cp == '\\') && (cp[1] != 0)) {
					*cpo++ = *(++cp);
					cp++;
				} else if (*cp == '"') {
					inquote = !inquote;
					cp++;
				} else if (isspace(*cp) && !inquote) {
					*cpo++ = 0;
					cp++;
					while ((*cp != 0) && isspace(*cp)) {
						cp++;
					}
					if (*cp != 0) {
						args[nargs++] = cpo;
					}
				} else {
					*cpo++ = *cp++;
				}
			}
			*cpo = 0;

			if (strcmp(s, "args") == 0) {
				int i;

				for (i = 0; i < nargs; i++) {
					cPrintf("%3d: \"%s\"", i, args[i]);
				}
			} else if ((strcmp(s, "help") == 0) || (strcmp(s, "?") == 0)) {
				consoleHelp();
			} else if (strcmp(s, "rate") == 0) {
				if (nargs == 1) {
					cPrintf("Current output rate: %d samples/second.", currentOutputRate);
				} else {
					currentOutputRate = atoi(args[1]);	
				}
			} else {
				cPrintf("Unknown command \"%s\".  Type help for a list of commands.", s);
			}
		}
	}
}


//  CONSOLEINPUT  --  Edit control which notifies parent of return key. 

static WNDPROC lpfnOldEdit = NULL;

#define WM_EDITRETURN	(WM_USER + 1071) 

LONG WINAPI consoleInput(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	if (message == WM_GETDLGCODE) {
		return DLGC_WANTALLKEYS;		// We want to see Tab, Return, etc.
	}

	if (message == WM_KEYDOWN) {
		if (wParam == VK_RETURN) {
			SendMessage(GetParent(hWnd), WM_COMMAND,
				MAKELONG(GetWindowLong(hWnd, GWL_ID), WM_EDITRETURN),
				(LPARAM) hWnd);
			return 0L;
		}
		if (wParam == VK_TAB) {
			SetFocus(GetDlgItem(GetParent(hWnd), IDC_CONSOLE_SUBMIT));
			return 0L;
		}
	}
	
	//	Must eat return and tab WM_CHAR messages to avoid inane "bing"
	if ((message == WM_CHAR) &&
		((wParam == '\t')) || (wParam == '\r')) {
		return 0L;
	}
	
	return CallWindowProc(lpfnOldEdit, hWnd, message, wParam, lParam);
}

//	CONSOLEDLGPROC  --  Console dialogue procedure

#define WM_CONSOLE_TEXT	(WM_USER + 1003)

BOOL CALLBACK consoleDlgProc(HWND hwnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
	int l;

    switch (nMessage) {
    	case WM_INITDIALOG:
			hDlgConsole = hwnd;

			//	Subclass text input control so return sends line
			
			lpfnOldEdit = (WNDPROC) GetWindowLong(GetDlgItem(hwnd, IDC_CONSOLE_INPUT),
										GWL_WNDPROC);
			SetWindowLong(GetDlgItem(hwnd, IDC_CONSOLE_INPUT), GWL_WNDPROC,
										(LONG) consoleInput);

			SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_SETREADONLY, TRUE, 0);
			SetDlgItemText(hwnd, IDC_CONSOLE_INPUT, "");
			SetFocus(GetDlgItem(hwnd, IDC_CONSOLE_INPUT));
	    	return TRUE;
	    	
	    case WM_CLOSE:
	    	DestroyWindow(hwnd);
	    	return TRUE;

		case WM_CONSOLE_TEXT:
			l = SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, WM_GETTEXTLENGTH, 0, 0);
			if (l > MAX_CONSOLE_SCROLL_LENGTH) {
				SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_SETSEL, 0, 200);
				SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_REPLACESEL, 0, (LPARAM) "");
				l = SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, WM_GETTEXTLENGTH, 0, 0);
			}
			SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_SETSEL, l, l);
			SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_REPLACESEL, 0, lParam);
			SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_SCROLLCARET, 0, 0);
			GlobalFree((LPSTR) lParam);
			return TRUE;

        case WM_COMMAND:
		    switch ((short) WM_COMMAND_ID(wParam)) {

		    	case IDOK:
		        	PostMessage(hwnd, WM_CLOSE, 0, 0L);
		        	break;
		        	
                case ID_HELP:
                	displayHelpTopic(IDS_HELP_CONSOLE);
                	break;

				case IDC_CONSOLE_CLEAR:
					SetDlgItemText(hwnd, IDC_CONSOLE_OUTPUT, "");
					break;

				case IDC_CONSOLE_SUBMIT:
					{
						char s[256];
						int n;

						//	Echo command to console log

						strcpy(s, rstring(IDS_CONSOLE_COMMAND_ECHO));
						l = strlen(s);
						if ((n = GetDlgItemText(hwnd, IDC_CONSOLE_INPUT, s + l, sizeof(s) - (l + 4))) > 0) {
							while ((n > 0) && isspace(s[(l + n) - 1])) {
								n--;
							}
							strcpy(s + l + n, "\r\n");
							if (n > 0) {
								int tl = SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, WM_GETTEXTLENGTH, 0, 0);

								if (tl > MAX_CONSOLE_SCROLL_LENGTH) {
									SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_SETSEL, 0, 200);
									SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_REPLACESEL, 0, (LPARAM) "");
									tl = SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, WM_GETTEXTLENGTH, 0, 0);
								}
								SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_SETSEL, tl, tl);
								SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_REPLACESEL, 0, (LPARAM) s);
								SendDlgItemMessage(hwnd, IDC_CONSOLE_OUTPUT, EM_SCROLLCARET, 0, 0);
							}
						}
					}

					consoleProcessCommand(hwnd);

					//	Clear console input line
					SetDlgItemText(hwnd, IDC_CONSOLE_INPUT, "");
					SetFocus(GetDlgItem(hwnd, IDC_CONSOLE_INPUT));
					break;

				case IDC_CONSOLE_INPUT:
                	if (WM_COMMAND_NOTIFY == WM_EDITRETURN) {
	                	PostMessage(hwnd, WM_COMMAND, IDC_CONSOLE_SUBMIT, 0L);
					}
					break;
		    }
        	return TRUE;
	    	
	    case WM_DESTROY:
	    	hDlgConsole = NULL;
	    	return 0;
    }
    return FALSE;
}

//	CONSOLEDIALOGUE  --  Diagnostic console dialogue

VOID consoleDialogue(HWND hwndParent)
{
	if (hDlgConsole == NULL) {
		hDlgConsole = CreateDialog(hInst, MAKEINTRESOURCE(IDD_CONSOLE),
    					hwndParent, consoleDlgProc);
	}
}

//	CONSOLELOG  --  Post console output to scrolling area

void consoleLog(char *text)
{
	//	If the console window is open, post the text to it.

	if (hDlgConsole != NULL) {
		char *mtext = GlobalAlloc(GMEM_FIXED, strlen(text) + 4);

		if (mtext != NULL) {
			strcpy(mtext, text);
			strcat(mtext, "\r\n");
			PostMessage(hDlgConsole, WM_CONSOLE_TEXT, 0, (LPARAM) mtext);
		}
	}
}

//	CPRINTF, VCPRINTF  --  Print a formatted string on the console

void vcPrintf(LPCSTR lpFormat, va_list arglist)
{
	char s[1024];

	vsprintf(s, lpFormat, arglist);
	consoleLog(s);
}

void cPrintf(LPCSTR lpFormat, ...)
{
	va_list args;

	va_start(args, lpFormat);
	vcPrintf(lpFormat, args);
	va_end(args);
}