/*
 * A simple application using Windows Resources.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <windows.h>
#include <commctrl.h>
#include <winbase.h>
#include <tchar.h>
#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
	#include <aygshell.h>
#endif

#include <mmsystem.h>
#include <shlobj.h>

#include "osmroute.h"
#include "wince_port.h"
#include "draw.h"
#include "gui.h"
#include "system.h"
#include "routing.h"


/* scale: km/per pixel */
HINSTANCE	hi;
HWND		hMainWnd;

BOOL InitApplication(HINSTANCE hinstance);
BOOL InitInstance(HINSTANCE hinstance, int nCmdShow);
LRESULT CALLBACK WndProcedure(HWND, UINT, WPARAM, LPARAM);
void DoMenuActions(HWND w, INT id);
const WCHAR	*WindowCaption = L"Resource Test";


/*
 * functions which are might usefull
 */
void wince_taskbar(HWND hWnd, int show) {

#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
	RECT rc;
	static int lastshow = -1;
	static int initbottom = -1;
	static int inittop = -1;

	if (!hWnd) return;

	/* prevent from hiding or displaying the bar twice */
	// d_printf ("%s:%d wince_taskbar function is wrong --> so just return. The window size is somehow always wrong..", __FILE__, __LINE__);
	// return;

	if (lastshow == show) return;
	lastshow = show;
	GetWindowRect( hWnd, &rc );

	if (initbottom == -1) {
		initbottom = rc.bottom;
		inittop = rc.top;
	}

	d_printf ("wince_taskbar show/hide: %d dest size: %d, %d, %d, %d", show, rc.left, rc.top, rc.right, rc.bottom);
	

	HWND hWndTB=FindWindow(TEXT("HHTaskbar"),NULL);

	if (show) {
		SHFullScreen( hWnd, SHFS_SHOWTASKBAR | (SHFS_SHOWSIPBUTTON + SHFS_SHOWSTARTICON) );
		ShowWindow( hWndTB, SW_SHOW );
		MoveWindow( hWnd, 
					rc.left, 
					inittop, 
					rc.right, 
					rc.bottom,
					TRUE
				  );
	}
	else {
		SHFullScreen( hWnd, SHFS_HIDETASKBAR | (SHFS_HIDESIPBUTTON + SHFS_HIDESTARTICON) );
		ShowWindow( hWndTB, SW_HIDE );
		MoveWindow( hWnd, 
					rc.left, 
					inittop - MENU_HEIGHT,
					rc.right, 
					initbottom + MENU_HEIGHT,
					TRUE
				  );
	}

#endif
};


/*
 * converting between wchar and char
 */
int wchar2char (char *c, int clen, WCHAR *wc) {
	int len = lstrlenW(wc);
	
    WideCharToMultiByte(CP_UTF8, 0, wc, -1, c, clen, NULL, NULL);
    return len;
};


int wchar2oem (char *c, int clen, WCHAR *wc) {
	int len = lstrlenW(wc);
	
    WideCharToMultiByte(CP_ACP, 0, wc, -1, c, clen, NULL, NULL);
    return len;
};


int char2wchar (WCHAR *wc, int wclen, char *c) {
    return MultiByteToWideChar(CP_UTF8, 0, c, -1, wc, wclen)-1;
};


void SetDlgItemText_wa (HWND hwnd, int id, char *str) {
#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
	WCHAR str_w[1024];
	char2wchar (str_w, 1024, str);
	SetDlgItemText(hwnd, id, str_w);
#else
	SetDlgItemText(hwnd, id, str);
#endif
};


void GetDlgItemText_wa (HWND hwnd, int id, char *str, int cnt) {
#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
	WCHAR str_w[1024];
	GetDlgItemText(hwnd, id, str_w, 1024);
	wchar2char (str, cnt, str_w);
#else
	GetDlgItemText(hwnd, id, str, cnt);
#endif
};


void SendMessage_SetText_wa (HWND hwnd, UINT msg, WPARAM wParam, LPARAM str) {
#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
	WCHAR str_w[1024];
	char2wchar (str_w, 1024, (char*) str);
	SendMessage (hwnd, msg, wParam, (LPARAM) str_w);
#else
	SendMessage (hwnd, msg, wParam, str);
#endif
};


void SendMessage_GetText_wa (HWND hwnd, UINT msg, WPARAM wParam, LPARAM str, int cnt) {
#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
	WCHAR str_w[1024];
	SendMessage (hwnd, msg, wParam, (LPARAM) str_w);
	wchar2char ((char*)str, cnt, (WCHAR *) str_w);
#else
	SendMessage (hwnd, msg, wParam, str);
#endif
};





/********************************************************************************************************
 *
 * load all configs and init the main window
 *
 */
#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
int WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
#else
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { 
#endif
    MSG msg; 
    BOOL fGotMessage;

	app_init (nCmdShow, lpCmdLine);

    if (!InitApplication(hinstance)) 
        return FALSE; 
 
    if (!InitInstance(hinstance, nCmdShow)) 
        return FALSE; 

	while ((fGotMessage = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0 && fGotMessage != -1) { 
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }

	app_shutdown ();

	return msg.wParam; 
} 

BOOL InitApplication(HINSTANCE hinstance) 
{ 
#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
	WNDCLASS	WndCls;
	HWND hWnd;
	SHInitExtraControls();
	int e;
	
	hWnd = FindWindow(L"osmRoute", NULL);	
	e = GetLastError();
	if (hWnd && e != ERROR_CLASS_DOES_NOT_EXIST) {
		/* another process is still running.. */
		if (SetForegroundWindow((HWND)((ULONG) hWnd | 0x01)) != 0) {
			return 0;
		}
	}
	
	//
	// create the ressource and stup the window
	//
	WndCls.style		= CS_HREDRAW | CS_VREDRAW;
	WndCls.lpfnWndProc	= WndProcedure;
	WndCls.cbClsExtra	= 0;
	WndCls.cbWndExtra	= 0;
	WndCls.hIcon		= NULL;
	WndCls.hCursor		= NULL;
	WndCls.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	WndCls.lpszMenuName	= NULL;
	WndCls.lpszClassName	= L"osmRoute";
	WndCls.hInstance	= hinstance;

	return RegisterClass(&WndCls);

#else
	WNDCLASSEX wcx; 
 
    // Fill in the window class structure with parameters 
    // that describe the main window. 
    wcx.cbSize = sizeof(wcx);          // size of structure 
    wcx.style = CS_HREDRAW | 
        CS_VREDRAW;                    // redraw if size changes 
    wcx.lpfnWndProc = WndProcedure;    // points to window procedure 
    wcx.cbClsExtra = 0;                // no extra class memory 
    wcx.cbWndExtra = 0;                // no extra window memory 
    wcx.hInstance = hinstance;         // handle to instance 
    wcx.hIcon = LoadIcon(NULL, 
        IDI_APPLICATION);              // predefined app. icon 
    wcx.hCursor = LoadCursor(NULL, 
        IDC_ARROW);                    // predefined arrow 
    wcx.hbrBackground = GetStockObject( 
        WHITE_BRUSH);                  // white background brush 
 //   wcx.lpszMenuName =  MAKEINTRESOURCE(IDR_MAINMENU);    // name of menu resource 
    wcx.lpszClassName = "osmRoute";  // name of window class 
	wcx.lpszMenuName = NULL; 
    wcx.hIconSm = LoadImage(hinstance, // small class icon 
        MAKEINTRESOURCE(5),
        IMAGE_ICON, 
        GetSystemMetrics(SM_CXSMICON), 
        GetSystemMetrics(SM_CYSMICON), 
        LR_DEFAULTCOLOR); 

    // Register the window class. 
    return RegisterClassEx(&wcx); 
#endif
} 

BOOL InitInstance(HINSTANCE hinstance, int nCmdShow) 
{ 
#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
	hi = hinstance;
	hMainWnd = CreateWindow(L"osmRoute", L"wceOSMroute", WS_VISIBLE | WS_MAXIMIZE ,
			CW_USEDEFAULT, CW_USEDEFAULT,
			CW_USEDEFAULT, CW_USEDEFAULT,
			NULL, NULL,	hinstance, NULL); 

	if (!hMainWnd) 
        return FALSE; 

//	wince_taskbar (hMainWnd, FALSE );
	ShowWindow(hMainWnd, SW_SHOWMAXIMIZED);
#else
    // Save the application-instance handle. 
    hi = hinstance; 
    hMainWnd = CreateWindow( 
        "osmRoute",        // name of window class 
        "wceOSMroute",            // title-bar string 
        WS_OVERLAPPEDWINDOW, // top-level window 
        CW_USEDEFAULT,       // default horizontal position 
        CW_USEDEFAULT,       // default vertical position 
        240,       // default width 
        320,       // default height 
        (HWND) NULL,         // no owner window 
        (HMENU) NULL,         // use class menu 
        hinstance,           // handle to application instance 
        (LPVOID) NULL);      // no window-creation data 

	if (!hMainWnd) 
        return FALSE; 
 
    // Show the window and send a WM_PAINT message to the window 
    // procedure. 
    ShowWindow(hMainWnd, nCmdShow); 
#endif
    UpdateWindow(hMainWnd); 
	return TRUE; 
}


LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
	static int timer_cyclicloop = -1;
	static int timer_active = 0;
	int x ,y;
	GUIEvent gevent;
	RECT rc;

	switch (Msg) {
		case WM_CREATE:
			{
#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
 				wince_taskbar (hWnd, FALSE);

/*				SHMENUBARINFO mbi;
				ZeroMemory(&mbi, sizeof(SHMENUBARINFO));

				mbi.cbSize     = sizeof(SHMENUBARINFO);
				mbi.hwndParent = hWnd;
				mbi.nToolBarId = IDR_MAINMENU;
				mbi.hInstRes   = hi;
				mbi.dwFlags    = SHCMBF_HMENU;
				if(!SHCreateMenuBar(&mbi)) {
	 				wince_taskbar (hWnd, TRUE);
					DestroyWindow(hWnd);
					PostQuitMessage(1);
					return(-1);
				}
				else {
					HWND g_hwndMb = mbi.hwndMB;
					HMENU g_hMenu;
                    TBBUTTONINFO tbbi = {0};

                    tbbi.cbSize       = sizeof(tbbi);
                    tbbi.dwMask       = TBIF_LPARAM | TBIF_BYINDEX;
                    SendMessage(g_hwndMb, TB_GETBUTTONINFO,0, (LPARAM)&tbbi);
                    g_hMenu           = (HMENU)tbbi.lParam;
				} */
#else
#endif
				timer_cyclicloop = SetTimer(hWnd, WINTIMER_CYCLICLOOP, 0, NULL);
				gfx_resize (100,100);
            }
            break;
#if defined(__MINGW32CE__) || defined(_WIN32_WCE)
		case WM_ACTIVATE:
//  		if (LOWORD(wParam)!=WA_INACTIVE) {
//				  wince_taskbar (hWnd, FALSE);
//     		} else {
//				  wince_taskbar (hWnd, TRUE);
//      		}
			break;
#endif
		case WM_DESTROY:
			wince_taskbar (hWnd, TRUE);
			route_stop ();
			gps_stop ();
			KillTimer (hWnd, timer_cyclicloop);
			PostQuitMessage(WM_QUIT);
			break;
		case WM_TIMER:
			if (timer_active) break;
			else timer_active = 1;
			draw_mouseloop ();
			if (gps_isrunning ()) {
				struct gps_data *gpsdata;
				if ((gpsdata = gps_loop ()))
					drawgps_set_pos (gpsdata);
				main_wnd_update ();
			}
			timer_active = 0;
			break;
		case WM_PAINT:
			GetWindowRect( hWnd, &rc );
			gfx_resize (rc.right-rc.left, rc.bottom-rc.top);

			draw_wm_paint = 1;
			draw ();
			draw_wm_paint = 0;
			break;
		case WM_LBUTTONUP:
			x = (lParam & 0xFFFF);
			y = (lParam >> 16);
			gevent.scr_mpos.x = x;
			gevent.scr_mpos.y = y;
			gevent.mousebtn = 1;
			gevent.event = EGUI_MOUSERELEASED;
			if (gui_event (gevent) == 0) draw_mousebtnup (x, y, 1);
			break;
		case WM_LBUTTONDOWN:
			x = (lParam & 0xFFFF);
			y = (lParam >> 16);
			gevent.scr_mpos.x = x;
			gevent.scr_mpos.y = y;
			gevent.mousebtn = 1;
			gevent.event = EGUI_MOUSEPRESSED;
			if (gui_event (gevent) == 0) draw_mousebtndown (x, y, 1);
			break;
		case WM_MOUSEMOVE: 
			x = (lParam & 0xFFFF);
			y = (lParam >> 16);
			gevent.scr_mpos.x = x;
			gevent.scr_mpos.y = y;
			gevent.mousebtn = 0;
			gevent.event = EGUI_MOUSEMOVE;
			gui_event (gevent);
			draw_mousemove (x, y, -1);
			break;		
		case WM_CHAR:
			if (wParam < ' ') gevent.keychar = 0xff00 | wParam;
			else gevent.keychar = wParam;
			gevent.event = EGUI_KEYCHAR;
			d_printf ("char wParam:%x keyval:%x", wParam, gevent.keychar);
			if (gui_event (gevent) != 0) draw();
			break;
//		case WM_KEYUP:
//			if (wParam == 0x03) gevent.keyval = 0xff1b;
//			else if (wParam == 0x08) gevent.keyval = 0xff08;
//			else if (wParam == 0x0d) gevent.keyval = 0xff0d;
//			else {
//				break;
//			}
//			gevent.event = EGUI_KEYRELEASED;
//			if (gui_event (gevent) != 0) draw();
//			break;
		case WM_COMMAND:
			/* Handle the menu items */
			DoMenuActions(hWnd, LOWORD(wParam));
			break;
		default:
			return DefWindowProc(hWnd, Msg, wParam, lParam);;
	}

	return 0;
}


void DoMenuActions(HWND hWnd, INT id) {
	switch (id) {
		case IDM_MENU_EXIT:
			gps_stop ();
			route_stop ();
			wince_taskbar (hWnd, TRUE);
			PostQuitMessage(0);
			break;
		case IDM_MENU_MAP_PATH:
			{
				char *fn;
//				wince_taskbar (hWnd, TRUE);
				fn = select_dir_dialog ("MapData", cfg.mappath);
//				wince_taskbar (hWnd, FALSE);
				if (fn) {
					d_printf ("config: changed data path from '%s' to '%s'.", cfg.mappath, fn);
					map_clear();
					strncpy (cfg.mappath, fn, LEN_FILENAME);
					map_clear();
					draw_redrawmap ();
				}
			}
			break;
		case IDM_MENU_LOG_PATH:
			{
				char *fn;
//				wince_taskbar (hWnd, TRUE);
				fn = select_dir_dialog ("LOG Path", cfg.logpath);
//				wince_taskbar (hWnd, FALSE);
				if (fn) {
					d_printf ("config: changed log path from '%s' to '%s'.", cfg.logpath, fn);
					strncpy (cfg.logpath, fn, LEN_FILENAME);
				}
			}
			break;
		case IDM_MENU_MAP_REFRESHSEARCH:
			{
#ifndef _WINDOWSCE_
				char lfn[LEN_FILENAME];
				char rfn[LEN_FILENAME] = "search.mapidx";

				map_search_get_filename (lfn, LEN_FILENAME);
				map_webload (rfn, lfn, NULL);
				map_search_sort ();
#endif
				app_status (-1, "", 0.0);
			}
			break;
		case IDM_MENU_MAP_WEBLOAD: 
			{
				char fn[LEN_FILENAME];
				char rfn[LEN_FILENAME];

				map_ls_get_filename_only (fn, LEN_FILENAME, map_geo2igeo (view_lon), map_geo2igeo (view_lat));
				map_ls_get_filename (rfn, LEN_FILENAME, map_geo2igeo (view_lon), map_geo2igeo (view_lat));
#ifndef _WINDOWSCE_
				map_webload (fn, rfn, NULL);
#endif
				draw_redrawmap ();
			}
			break;
		case IDM_MENU_GPS_SETTING:
//			wince_taskbar (hWnd, TRUE);
			gps_wince_settings ();
//			wince_taskbar (hWnd, FALSE);
			break;
		case IDM_MENU_GPS_START:
			gps_start ();
			break;
		case IDM_MENU_GPS_STOP:
			gps_stop ();
			break;
		case IDM_MENU_GPS_LOGLOAD: 
			{
				char *fn;
//				wince_taskbar (hWnd, TRUE);
				fn = dialog_getfilename ("GPS-Logfile", "NMEA-File\0*.nmea\0All\0*.*\0", 0);
//				wince_taskbar (hWnd, FALSE);
				if (fn)
					gps_load_log (fn);
			}
			break;
		case IDM_MENU_GPX_EXPORT: 
			{
				char *fn;
//				wince_taskbar (hWnd, TRUE);
				fn = dialog_getfilename ("GPX-Export", "GPX-File\0*.gpx\0All\0*.*\0", 1);
//				wince_taskbar (hWnd, FALSE);
				if (fn)
					gpsroute_exportgpx (gpsroute, fn);
			}
			break;
		case IDM_MENU_ROUTESAVE: 
			{
				char *fn;
//				wince_taskbar (hWnd, TRUE);
				fn = dialog_getfilename ("Route Save", "Text File\0*.txt\0All\0*.*\0", 1);
//				wince_taskbar (hWnd, FALSE);
//				if (fn)
//					gpsroute_saveroute (gpsroute, fn);
			}
			break;
		case IDM_MENU_SEL_DIR: {
				d_printf ("nothing here yet..");
			}
			break;
	}
};


void main_wnd_loop (long long int cur, long long int max) {
	main_wnd_update ();
};


/******************************************************************************
 * update stausbar  - not finished in windows.. we have no status bar here yet.
 */
void main_wnd_update () {
	MSG message;
	if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
		TranslateMessage(&message);
    	DispatchMessage(&message);
	}
};
