// Copyright 2009 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.

// NaCl GUI events.
// Clients do not have raw access to the event stream
// (only filtered through the lens of package draw)
// but perhaps they will.

package av

import (
	"encoding/binary"
	"exp/draw"
	"image"
	"log"
	"os"
	"time"
)

// An eventType identifies the type of a Native Client Event.
type eventType uint8

const (
	eventActive = 1 + iota
	eventExpose
	eventKeyDown
	eventKeyUp
	eventMouseMotion
	eventMouseButtonDown
	eventMouseButtonUp
	eventQuit
	eventUnsupported
)

// A key represents a key on a keyboard.
type key uint16

const (
	keyUnknown      = 0
	keyFirst        = 0
	keyBackspace    = 8
	keyTab          = 9
	keyClear        = 12
	keyReturn       = 13
	keyPause        = 19
	keyEscape       = 27
	keySpace        = 32
	keyExclaim      = 33
	keyQuotedbl     = 34
	keyHash         = 35
	keyDollar       = 36
	keyAmpersand    = 38
	keyQuote        = 39
	keyLeftparen    = 40
	keyRightparen   = 41
	keyAsterisk     = 42
	keyPlus         = 43
	keyComma        = 44
	keyMinus        = 45
	keyPeriod       = 46
	keySlash        = 47
	key0            = 48
	key1            = 49
	key2            = 50
	key3            = 51
	key4            = 52
	key5            = 53
	key6            = 54
	key7            = 55
	key8            = 56
	key9            = 57
	keyColon        = 58
	keySemicolon    = 59
	keyLess         = 60
	keyEquals       = 61
	keyGreater      = 62
	keyQuestion     = 63
	keyAt           = 64
	keyLeftbracket  = 91
	keyBackslash    = 92
	keyRightbracket = 93
	keyCaret        = 94
	keyUnderscore   = 95
	keyBackquote    = 96
	keyA            = 97
	keyB            = 98
	keyC            = 99
	keyD            = 100
	keyE            = 101
	keyF            = 102
	keyG            = 103
	keyH            = 104
	keyI            = 105
	keyJ            = 106
	keyK            = 107
	keyL            = 108
	keyM            = 109
	keyN            = 110
	keyO            = 111
	keyP            = 112
	keyQ            = 113
	keyR            = 114
	keyS            = 115
	keyT            = 116
	keyU            = 117
	keyV            = 118
	keyW            = 119
	keyX            = 120
	keyY            = 121
	keyZ            = 122
	keyDelete       = 127
	keyWorld0       = 160
	keyWorld1       = 161
	keyWorld2       = 162
	keyWorld3       = 163
	keyWorld4       = 164
	keyWorld5       = 165
	keyWorld6       = 166
	keyWorld7       = 167
	keyWorld8       = 168
	keyWorld9       = 169
	keyWorld10      = 170
	keyWorld11      = 171
	keyWorld12      = 172
	keyWorld13      = 173
	keyWorld14      = 174
	keyWorld15      = 175
	keyWorld16      = 176
	keyWorld17      = 177
	keyWorld18      = 178
	keyWorld19      = 179
	keyWorld20      = 180
	keyWorld21      = 181
	keyWorld22      = 182
	keyWorld23      = 183
	keyWorld24      = 184
	keyWorld25      = 185
	keyWorld26      = 186
	keyWorld27      = 187
	keyWorld28      = 188
	keyWorld29      = 189
	keyWorld30      = 190
	keyWorld31      = 191
	keyWorld32      = 192
	keyWorld33      = 193
	keyWorld34      = 194
	keyWorld35      = 195
	keyWorld36      = 196
	keyWorld37      = 197
	keyWorld38      = 198
	keyWorld39      = 199
	keyWorld40      = 200
	keyWorld41      = 201
	keyWorld42      = 202
	keyWorld43      = 203
	keyWorld44      = 204
	keyWorld45      = 205
	keyWorld46      = 206
	keyWorld47      = 207
	keyWorld48      = 208
	keyWorld49      = 209
	keyWorld50      = 210
	keyWorld51      = 211
	keyWorld52      = 212
	keyWorld53      = 213
	keyWorld54      = 214
	keyWorld55      = 215
	keyWorld56      = 216
	keyWorld57      = 217
	keyWorld58      = 218
	keyWorld59      = 219
	keyWorld60      = 220
	keyWorld61      = 221
	keyWorld62      = 222
	keyWorld63      = 223
	keyWorld64      = 224
	keyWorld65      = 225
	keyWorld66      = 226
	keyWorld67      = 227
	keyWorld68      = 228
	keyWorld69      = 229
	keyWorld70      = 230
	keyWorld71      = 231
	keyWorld72      = 232
	keyWorld73      = 233
	keyWorld74      = 234
	keyWorld75      = 235
	keyWorld76      = 236
	keyWorld77      = 237
	keyWorld78      = 238
	keyWorld79      = 239
	keyWorld80      = 240
	keyWorld81      = 241
	keyWorld82      = 242
	keyWorld83      = 243
	keyWorld84      = 244
	keyWorld85      = 245
	keyWorld86      = 246
	keyWorld87      = 247
	keyWorld88      = 248
	keyWorld89      = 249
	keyWorld90      = 250
	keyWorld91      = 251
	keyWorld92      = 252
	keyWorld93      = 253
	keyWorld94      = 254
	keyWorld95      = 255

	// Numeric keypad
	keyKp0        = 256
	keyKp1        = 257
	keyKp2        = 258
	keyKp3        = 259
	keyKp4        = 260
	keyKp5        = 261
	keyKp6        = 262
	keyKp7        = 263
	keyKp8        = 264
	keyKp9        = 265
	keyKpPeriod   = 266
	keyKpDivide   = 267
	keyKpMultiply = 268
	keyKpMinus    = 269
	keyKpPlus     = 270
	keyKpEnter    = 271
	keyKpEquals   = 272

	// Arrow & insert/delete pad
	keyUp       = 273
	keyDown     = 274
	keyRight    = 275
	keyLeft     = 276
	keyInsert   = 277
	keyHome     = 278
	keyEnd      = 279
	keyPageup   = 280
	keyPagedown = 281

	// Function keys
	keyF1  = 282
	keyF2  = 283
	keyF3  = 284
	keyF4  = 285
	keyF5  = 286
	keyF6  = 287
	keyF7  = 288
	keyF8  = 289
	keyF9  = 290
	keyF10 = 291
	keyF11 = 292
	keyF12 = 293
	keyF13 = 294
	keyF14 = 295
	keyF15 = 296

	// Modifier keys
	keyNumlock   = 300
	keyCapslock  = 301
	keyScrollock = 302
	keyRshift    = 303
	keyLshift    = 304
	keyRctrl     = 305
	keyLctrl     = 306
	keyRalt      = 307
	keyLalt      = 308
	keyRmeta     = 309
	keyLmeta     = 310
	keyLsuper    = 311
	keyRsuper    = 312
	keyMode      = 313
	keyCompose   = 314

	// Misc keys
	keyHelp   = 315
	keyPrint  = 316
	keySysreq = 317
	keyBreak  = 318
	keyMenu   = 319
	keyPower  = 320
	keyEuro   = 321
	keyUndo   = 322

	// Add any other keys here
	keyLast
)

// A keymod is a set of bit flags
type keymod uint16

const (
	keymodNone     = 0x0000
	keymodLshift   = 0x0001
	keymodRshift   = 0x0002
	keymodLctrl    = 0x0040
	keymodRctrl    = 0x0080
	keymodLalt     = 0x0100
	keymodRalt     = 0x0200
	keymodLmeta    = 0x0400
	keymodRmeta    = 0x0800
	keymodNum      = 0x1000
	keymodCaps     = 0x2000
	keymodMode     = 0x4000
	keymodReserved = 0x8000
)

const (
	mouseButtonLeft   = 1
	mouseButtonMiddle = 2
	mouseButtonRight  = 3
	mouseScrollUp     = 4
	mouseScrollDown   = 5
)

const (
	mouseStateLeftButtonPressed   = 1
	mouseStateMiddleButtonPressed = 2
	mouseStateRightButtonPressed  = 4
)

const (
	activeMouse       = 1 //  mouse leaving/entering
	activeInputFocus  = 2 // input focus lost/restored
	activeApplication = 4 // application minimized/restored
)

const maxEventBytes = 64

type activeEvent struct {
	EventType eventType
	Gain      uint8
	State     uint8
}

type exposeEvent struct {
	EventType eventType
}

type keyboardEvent struct {
	EventType eventType
	Device    uint8
	State     uint8
	Pad       uint8
	ScanCode  uint8
	Pad1      uint8
	Key       key
	Mod       keymod
	Unicode   uint16
}

type mouseMotionEvent struct {
	EventType eventType
	Device    uint8
	Buttons   uint8
	Pad       uint8
	X         uint16
	Y         uint16
	Xrel      int16
	Yrel      int16
}

type mouseButtonEvent struct {
	EventType eventType
	Device    uint8
	Button    uint8
	State     uint8
	X         uint16
	Y         uint16
}

type quitEvent struct {
	EventType eventType
}

type syncEvent struct{}

type event interface{}

type reader []byte

func (r *reader) Read(p []byte) (n int, err os.Error) {
	b := *r
	if len(b) == 0 && len(p) > 0 {
		return 0, os.EOF
	}
	n = copy(p, b)
	*r = b[n:]
	return
}

func (w *Window) readEvents() {
	buf := make([]byte, maxEventBytes)
	clean := false
	var (
		ea  *activeEvent
		ee  *exposeEvent
		ke  *keyboardEvent
		mme *mouseMotionEvent
		mbe *mouseButtonEvent
		qe  *quitEvent
	)
	var m draw.MouseEvent
	for {
		if err := videoPollEvent(buf); err != nil {
			if !clean {
				clean = w.eventc <- draw.ConfigEvent{image.Config{ColorModel, w.Image.Bounds().Dx(), w.Image.Bounds().Dy()}}
			}
			time.Sleep(10e6) // 10ms
			continue
		}
		clean = false
		var e event
		switch buf[0] {
		default:
			log.Print("unsupported event type", buf[0])
			continue
		case eventActive:
			ea = new(activeEvent)
			e = ea
		case eventExpose:
			ee = new(exposeEvent)
			e = ee
		case eventKeyDown, eventKeyUp:
			ke = new(keyboardEvent)
			e = ke
		case eventMouseMotion:
			mme = new(mouseMotionEvent)
			e = mme
		case eventMouseButtonDown, eventMouseButtonUp:
			mbe = new(mouseButtonEvent)
			e = mbe
		case eventQuit:
			qe = new(quitEvent)
			e = qe
		}
		r := reader(buf)
		if err := binary.Read(&r, binary.LittleEndian, e); err != nil {
			log.Print("unpacking %T event: %s", e, err)
			continue
		}
		// log.Printf("%#v\n", e);
		switch buf[0] {
		case eventExpose:
			w.eventc <- draw.ConfigEvent{image.Config{ColorModel, w.Image.Bounds().Dx(), w.Image.Bounds().Dy()}}
		case eventKeyDown:
			w.eventc <- draw.KeyEvent{int(ke.Key)}
		case eventKeyUp:
			w.eventc <- draw.KeyEvent{-int(ke.Key)}
		case eventMouseMotion:
			m.Loc.X = int(mme.X)
			m.Loc.Y = int(mme.Y)
			m.Buttons = int(mme.Buttons)
			m.Nsec = time.Nanoseconds()
			_ = w.eventc <- m
		case eventMouseButtonDown:
			m.Loc.X = int(mbe.X)
			m.Loc.Y = int(mbe.Y)
			// TODO(rsc): Remove uint cast once 8g bug is fixed.
			m.Buttons |= 1 << uint(mbe.Button-1)
			m.Nsec = time.Nanoseconds()
			_ = w.eventc <- m
		case eventMouseButtonUp:
			m.Loc.X = int(mbe.X)
			m.Loc.Y = int(mbe.Y)
			// TODO(rsc): Remove uint cast once 8g bug is fixed.
			m.Buttons &^= 1 << uint(mbe.Button-1)
			m.Nsec = time.Nanoseconds()
			_ = w.eventc <- m
		case eventQuit:
			close(w.eventc)
		}
	}
}
