package main

//go:generate nswrap

import (
	"fmt"
	"git.wow.st/gmp/nswrap/examples/app/ns"
	"runtime"
	"time"
)

//Shortcut for literal NSStrings
var nst = ns.NSStringWithGoString

func pb1(self ns.GButton, super ns.GButtonSupermethods) {
	fmt.Println("Pushed button 1")
}

func pb2(self ns.GButton, super ns.GButtonSupermethods) {
	fmt.Println("Pushed button 2")
	a.Terminate(a)
}

func db(self ns.GButton, super ns.GButtonSupermethods) {
	fmt.Println("button deallocated")
}

func didFinishLaunching(self ns.AppDelegate, n *ns.NSNotification) {
	fmt.Println("Go: did finish launching")
	fmt.Printf("Notification: %s\n", n.Name().UTF8String())
	//Set up an NSWindow
	win = ns.NSWindowAlloc().InitWithContentRectStyleMask(
		ns.NSMakeRect(200, 200, 600, 600),
		ns.NSWindowStyleMask(ns.NSWindowStyleMaskTitled|ns.NSWindowStyleMaskClosable|
			ns.NSWindowStyleMaskResizable),
		ns.NSBackingStoreType(ns.NSBackingStoreBuffered),
		0,
	)
	// We do not need to retain this because we are in garbage collection mode
	// and have assigned it to a global variable.
	//win.Retain()

	win.SetTitle(nst("Hi World"))
	win.MakeKeyAndOrderFront(win)
	win.SetAlphaValue(0.85)

	//Build a basic menu
	m1 := ns.NSMenuAlloc().InitWithTitle(nst("Main"))
	appItem := ns.NSMenuItemAlloc()
	fileItem := ns.NSMenuItemAlloc()
	m1.AddItem(appItem)
	m1.AddItem(fileItem)

	appMenu := ns.NSMenuAlloc().InitWithTitle(nst("App"))
	fileMenu := ns.NSMenuAlloc().InitWithTitle(nst("File"))
	m1.SetSubmenu(appMenu, appItem)
	m1.SetSubmenu(fileMenu, fileItem)

	appMenu.AddItemWithTitle(nst("About"), nil, nst(""))
	appMenu.AddItemWithTitle(nst("Preferences"), nil, nst(""))
	appMenu.AddItemWithTitle(nst("Quit"), ns.Selector("terminate:"), nst("q"))
	a.SetMainMenu(m1)
	fileMenu.AddItemWithTitle(nst("Open"), nil, nst(""))
	fileMenu.AddItemWithTitle(nst("New"), nil, nst(""))

	a.SetMainMenu(m1)

	//add some custom buttons

	b1 := ns.GButtonAlloc()
	b2 := ns.GButtonAlloc()

	b1.Init()
	b1.PressedCallback(pb1)
	b1.DeallocCallback(db)
	b1.SetAction(ns.Selector("pressed"))
	b1.SetTarget(b1)
	b1.SetTitle(nst("PUSH"))

	b2.Init()
	b2.PressedCallback(pb2)
	b2.DeallocCallback(db)
	b2.SetTarget(b2)
	b2.SetAction(ns.Selector("pressed"))
	b2.SetTitle(nst("QUIT"))

	//add some layout constraints

	b1.SetTranslatesAutoresizingMaskIntoConstraints(0)
	b2.SetTranslatesAutoresizingMaskIntoConstraints(0)

	cv := win.ContentView()

	cv.AddSubview(&b1.NSView)
	cv.AddSubview(&b2.NSView)

	viewmap := ns.NSDictionaryWithObjectsForKeys(
		ns.NSArrayWithObjects(b1, b2),
		ns.NSArrayWithObjects(nst("b1"), nst("b2")))

	cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
		nst("V:|-[b1]"), 0, nil, viewmap))
	cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
		nst("H:|-[b1]"), 0, nil, viewmap))
	cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
		nst("H:[b1]-[b2]"), ns.NSLayoutFormatOptions(ns.NSLayoutFormatAlignAllBaseline), nil, viewmap))

	a.ActivateIgnoringOtherApps(1)
}

func shouldTerminateAfterLastWindowClosed(self ns.AppDelegate, s *ns.NSApplication) ns.BOOL {
	fmt.Println("Go: should terminate after last window closed")
	return 1
}

func willTerminate(self ns.AppDelegate, n *ns.NSNotification) {
	fmt.Println("Go: will terminate")
}

func didBecomeActive(self ns.AppDelegate, n *ns.NSNotification) {
	fmt.Println("Go: did become active")
	fmt.Printf("Notification: %s\n", n.Name().UTF8String())
}

var (
	a   *ns.NSApplication
	del *ns.AppDelegate
	win *ns.NSWindow
)

func app() {
	// Lock OS thread because Cocoa uses thread-local storage
	runtime.LockOSThread()
	a = ns.NSApplicationSharedApplication()
	a.SetActivationPolicy(ns.NSApplicationActivationPolicy(ns.NSApplicationActivationPolicyRegular))

	// Set up an AppDelegate
	// assign it to a global variable so it doesn't get garbage collected
	del = ns.AppDelegateAlloc()
	del.ApplicationDidFinishLaunchingCallback(didFinishLaunching)
	del.ApplicationShouldTerminateAfterLastWindowClosedCallback(shouldTerminateAfterLastWindowClosed)
	del.ApplicationWillTerminateCallback(willTerminate)
	del.ApplicationDidBecomeActiveCallback(didBecomeActive)

	a.SetDelegate(del)

	// Run the app
	a.Run()
}

func main() {
	// Run GC every second to ensure pointers are not being prematurely released.
	go func() {
		for {
			runtime.GC()
			time.Sleep(time.Second)
		}
	}()

	// Run our app in an autorelease pool just for fun
	go app()
	select {}
}
