// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"syscall"
	"os"
	"unsafe"
)

// some help functions

func abortf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stdout, format, a...)
	os.Exit(1)
}

func abortErrNo(funcname string, err int) {
	abortf("%s failed: %d %s\n", funcname, err, syscall.Errstr(err))
}

// global vars

var (
	mh uint32
	bh uint32
)

// WinProc called by windows to notify us of all windows events we might be interested in.
func WndProc(hwnd, msg uint32, wparam, lparam int32) uintptr {
	var rc int32
	switch msg {
	case WM_CREATE:
		var e int
		// CreateWindowEx
		bh, e = CreateWindowEx(
			0,
			syscall.StringToUTF16Ptr("button"),
			syscall.StringToUTF16Ptr("Quit"),
			WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
			75, 70, 140, 25,
			hwnd, 1, mh, 0)
		if e != 0 {
			abortErrNo("CreateWindowEx", e)
		}
		fmt.Printf("button handle is %x\n", bh)
		rc = DefWindowProc(hwnd, msg, wparam, lparam)
	case WM_COMMAND:
		switch uint32(lparam) {
		case bh:
			e := PostMessage(hwnd, WM_CLOSE, 0, 0)
			if e != 0 {
				abortErrNo("PostMessage", e)
			}
		default:
			rc = DefWindowProc(hwnd, msg, wparam, lparam)
		}
	case WM_CLOSE:
		DestroyWindow(hwnd)
	case WM_DESTROY:
		PostQuitMessage(0)
	default:
		rc = DefWindowProc(hwnd, msg, wparam, lparam)
	}
	//fmt.Printf("WndProc(0x%08x, %d, 0x%08x, 0x%08x) (%d)\n", hwnd, msg, wparam, lparam, rc)
	return uintptr(rc)
}

func rungui() int {
	var e int

	// GetModuleHandle
	mh, e = GetModuleHandle(nil)
	if e != 0 {
		abortErrNo("GetModuleHandle", e)
	}

	// Get icon we're going to use.
	myicon, e := LoadIcon(0, IDI_APPLICATION)
	if e != 0 {
		abortErrNo("LoadIcon", e)
	}

	// Get cursor we're going to use.
	mycursor, e := LoadCursor(0, IDC_ARROW)
	if e != 0 {
		abortErrNo("LoadCursor", e)
	}

	// Create callback
	wproc := syscall.NewCallback(WndProc)

	// RegisterClassEx
	wcname := syscall.StringToUTF16Ptr("myWindowClass")
	var wc Wndclassex
	wc.Size = uint32(unsafe.Sizeof(wc))
	wc.WndProc = wproc
	wc.Instance = mh
	wc.Icon = myicon
	wc.Cursor = mycursor
	wc.Background = COLOR_BTNFACE + 1
	wc.MenuName = nil
	wc.ClassName = wcname
	wc.IconSm = myicon
	if _, e := RegisterClassEx(&wc); e != 0 {
		abortErrNo("RegisterClassEx", e)
	}

	// CreateWindowEx
	wh, e := CreateWindowEx(
		WS_EX_CLIENTEDGE,
		wcname,
		syscall.StringToUTF16Ptr("My window"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
		0, 0, mh, 0)
	if e != 0 {
		abortErrNo("CreateWindowEx", e)
	}
	fmt.Printf("main window handle is %x\n", wh)

	// ShowWindow
	ShowWindow(wh, SW_SHOWDEFAULT)

	// UpdateWindow
	if e := UpdateWindow(wh); e != 0 {
		abortErrNo("UpdateWindow", e)
	}

	// Process all windows messages until WM_QUIT.
	var m Msg
	for {
		r, e := GetMessage(&m, 0, 0, 0)
		if e != 0 {
			abortErrNo("GetMessage", e)
		}
		if r == 0 {
			// WM_QUIT received -> get out
			break
		}
		TranslateMessage(&m)
		DispatchMessage(&m)
	}
	return int(m.Wparam)
}

func main() {
	rc := rungui()
	os.Exit(rc)
}
