/* 
 * tclWinCEmain.c --
 *
 *	This file contains the main entry point for tclsh on Windows CE.
 *	It is adapted with minor modifications from Rainer Keuchel's
 *	celib-based w32console package, wmain.c file.
 *	celib Time-stamp: <09/02/02 07:27:49 keuchel@netwave.de>
 *
 * Copyright (c) 2003 ActiveState Corporation
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: Exp $
 */

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <shellapi.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "tclWinCEconsole.h"

#define CLASSNAME   "ConsoleClass"
#define CLASSNAMEW  L"ConsoleClass"

#ifdef UNDER_CE
#include "celib.h"
#include "ceshared.h"
#endif

HINSTANCE hInst;
HWND hMainWnd;
char     szTitle[126];
char    *szClassName  = CLASSNAME;
wchar_t *szClassNameW = CLASSNAMEW;

#define IDM_EXIT 0x100

#define WM_START (WM_USER+100)

BOOL InitApplication(HINSTANCE);
HWND InitInstance(HINSTANCE, INT);
void Message(HWND hwnd, const char *fmt, ...);

void DoExit();

int APIENTRY
wWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance, 
#ifdef UNDER_CE
	LPWSTR    lpCmdLine, 
#else
	LPSTR     lpCmdLine, 
#endif
	int       nCmdShow)
{
    MSG msg;
    HWND hwnd;
    char *p;
    BOOL bNoConsole = FALSE;
    LPWSTR pw;

    if ((pw = wcsstr(lpCmdLine, L"--noconsole")) != NULL) {
	bNoConsole = TRUE;

	while (*pw && *pw != ' ')
	    *pw++ = ' ';
    }

    // must be called before init!
    if (xceshared_getshowwindow() == 0) {
	bNoConsole = TRUE;
    }

    //XCEShowMessageW(L"%s", lpCmdLine);

    xceinit(lpCmdLine);

    if (bNoConsole) {
	DoExit(main(__xceargc, __xceargv, environ));
	// NOT REACHED
	return 0;
    }

    if ((p = strrchr(__xceargv[0], '/')) == NULL)
	p = __xceargv[0];
    else
	p++;

    strcpy(szTitle, p);

    if ((p = strrchr(szTitle, '.')) != NULL)
	*p = 0;

#if 0
    // When two programms use console, and one starts the other,
    // FindWindow hangs until the first has exited! Why is this???
    // Might be possible that this happens only in CE300!
    if ((hwnd = FindWindow(szClassName, szTitle)) != NULL) {
	SetForegroundWindow(hwnd);
	SetActiveWindow(hwnd);
	return 0;
    }
#endif

    if (!hPrevInstance) {
	if (!InitApplication(hInstance)) {
	    return FALSE;  
	}
    }

    if ((hMainWnd = hwnd = InitInstance(hInstance, nCmdShow)) == NULL) {
	return FALSE;
    }

#if 0
    // Cursor Blink Timer
    SetTimer(hMainWnd, 23, 1000, NULL);
#endif

#if 0
    // handle WM_PAINTS...
    // infinite loop in emulator, not needed...
    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
	TranslateMessage(&msg);
	DispatchMessage(&msg); 
    }
#endif

    SendMessage(hwnd, WM_START, 0, 0L);

    while (GetMessage(&msg, NULL, 0, 0)) {
	TranslateMessage(&msg);
	DispatchMessage(&msg); 
    }
    return TRUE;
}

int APIENTRY
WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance, 
#ifdef UNDER_CE
	LPWSTR    lpCmdLine, 
#else
	LPSTR     lpCmdLine, 
#endif
	int       nCmdShow)
{
    return wWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

int
HandleWMPaint(HWND hwnd)
{
    Window *pWnd;

    pWnd = (Window *) GetWindowLongW(hwnd, GWL_USERDATA);

    if (pWnd) {
	window_handle_paint(pWnd, hwnd);
	return 0;
    }
    return 1;
}

int
HandleWMTimer(HWND hwnd)
{
    Window *pWnd;

    pWnd = (Window *) GetWindowLongW(hwnd, GWL_USERDATA);

    if (pWnd) {
	window_handle_timer(pWnd, hwnd);
	return 0;
    }
    return 1;
}

LRESULT CALLBACK 
WndProc(HWND hwnd,
	UINT uMessage,
	WPARAM wparam,
	LPARAM lparam)
{
    switch(uMessage) {
	case WM_DESTROY:
	    KillTimer(hMainWnd, 23);
	    if (hwnd == hMainWnd)
		DoExit(0);
	    break;
	case WM_COMMAND:
	    switch(GET_WM_COMMAND_ID(wparam,lparam)) {
		case IDM_EXIT:
		    DestroyWindow(hwnd);
		    DoExit(0);
		    break;
	    }
	    break;
	case WM_PAINT:
	    return HandleWMPaint(hwnd);
	    break;
	case WM_TIMER:
	    return HandleWMTimer(hwnd);
	    break;
	case WM_START:
	    console_start();
#ifdef HANDLE_EXCEPTIONS
	    __try {
		//DebugBreak(); // MIPS does not get DebugExceptions!
#endif
		DoExit(main(__xceargc, __xceargv, environ));
#ifdef HANDLE_EXCEPTIONS
	    }
	    __except(EXCEPTION_EXECUTE_HANDLER) {
		XCEShowMessageA("Exception in main()");
	    }
#endif
	    break;
	default:
	    return DefWindowProcW(hwnd, uMessage, wparam, lparam);
    }
    return 0;
}

BOOL 
InitApplication(HINSTANCE hInstance)
{
    WNDCLASSW wc;

    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = (WNDPROC)WndProc;       
    wc.cbClsExtra    = 0;                      
    wc.cbWndExtra    = 0;                      
    wc.hInstance     = hInstance;              
    wc.hIcon         = NULL;
    wc.hCursor       = NULL;
    wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = szClassNameW;

    if (!RegisterClassW((LPWNDCLASSW)&wc.style))
	return FALSE;

    return TRUE;
}

HWND
InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hwnd;
#ifndef UNDER_CE
    HMENU hMenuFile;
    HMENU hMenuFileDrop;
#endif
    DWORD dwStyle;
    DWORD dwExStyle;

    hInst = hInstance; 

    dwExStyle = 0;

    dwStyle = 0;
    dwStyle |= WS_CAPTION;
    dwStyle |= WS_OVERLAPPED;
    dwStyle |= WS_CAPTION;
    dwStyle |= WS_SYSMENU;
    dwStyle |= WS_MINIMIZEBOX|WS_MAXIMIZEBOX;

    hwnd = CreateWindowEx(
	dwExStyle,
	szClassName, 
	szTitle,        
	dwStyle,
	CW_USEDEFAULT, 0,   
	CW_USEDEFAULT, 0,   
	NULL,               
	NULL,               
	hInstance,           
	NULL);               
    
    if (!hwnd)
	return NULL;

#ifndef UNDER_CE
    // init menu
    hMenuFile = CreateMenu();
    hMenuFileDrop = CreateMenu();
    AppendMenu(hMenuFile, MF_POPUP, (UINT) hMenuFileDrop, "&File");
    AppendMenu(hMenuFileDrop, MF_STRING, IDM_EXIT, "E&xit");
    SetMenu(hwnd, hMenuFile);
#endif

    nCmdShow = SW_SHOWNORMAL;
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    return hwnd;
}

void
Message(HWND hwnd, const char *fmt, ...)
{
    va_list ap;
    char buf[1024];

    va_start(ap, fmt);
    vsprintf(buf, fmt, ap);
    MessageBox(hwnd, buf, "Info", MB_OK);
}

void
DoExit(int code)
{
    XCETrace("Exitcode %d", code);

#ifdef _WIN32_WCE_EMULATION
    // NOTE: does not flush file buffers!!!!
    TerminateProcess(GetCurrentProcess(), code);
#else
    exit(code);
#endif
}
