import SDL2


public class Keyboard
{
	public enum Keys
	{
		case a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z
		case right, left, down, up
	}

	public func keyDown(_ key: Keys) -> Bool
	{
		_keys[Int(key.sdlScancode.rawValue)] & Self._DOWN == Self._DOWN
	}

	public func keyPressed(_ key: Keys, repeat rep: Bool = false) -> Bool
	{
		var state = _keys[Int(key.sdlScancode.rawValue)]
		if rep { state &= ~Self._REPEAT }
		return state == Self._PRESS
	}

	public func keyReleased(_ key: Keys) -> Bool
	{
		_keys[Int(key.sdlKeycode.rawValue)] == Self._RELEASE
	}

	private static let _UP = UInt8(0b000), _DOWN = UInt8(0b010), _IMPULSE = UInt8(0b001)
	private static let _REPEAT = UInt8(0b100)
	private static let _PRESS: UInt8 = _DOWN | _IMPULSE
	private static let _RELEASE: UInt8 = _UP | _IMPULSE

	private var _keys = [UInt8](repeating: _UP, count: Int(SDL_NUM_SCANCODES.rawValue))

	internal func newTick()
	{
		_keys = _keys.map({ $0 & ~(Self._IMPULSE | Self._REPEAT) })
	}

	internal func pressEvent(scan: SDL_Scancode, repeat rep: Bool)
	{
		var newState = Self._PRESS
		if rep { newState |= Self._REPEAT }
		_keys[Int(scan.rawValue)] = newState
	}

	internal func releaseEvent(scan: SDL_Scancode)
	{
		_keys[Int(scan.rawValue)] = Self._RELEASE
	}
}

extension Keyboard.Keys
{
	internal var sdlKeycode: SDL_KeyCode
	{
		switch self
		{
		case .a: SDLK_a
		case .b: SDLK_b
		case .c: SDLK_c
		case .d: SDLK_d
		case .e: SDLK_e
		case .f: SDLK_f
		case .g: SDLK_g
		case .h: SDLK_h
		case .i: SDLK_i
		case .j: SDLK_j
		case .k: SDLK_k
		case .l: SDLK_l
		case .m: SDLK_m
		case .n: SDLK_n
		case .o: SDLK_o
		case .p: SDLK_p
		case .q: SDLK_q
		case .r: SDLK_r
		case .s: SDLK_s
		case .t: SDLK_t
		case .u: SDLK_u
		case .v: SDLK_v
		case .w: SDLK_w
		case .x: SDLK_x
		case .y: SDLK_y
		case .z: SDLK_z
		case .left:  SDLK_LEFT
		case .right: SDLK_RIGHT
		case .up:    SDLK_UP
		case .down:  SDLK_DOWN
		}
	}

	internal var sdlScancode: SDL_Scancode
	{
		switch self
		{
		case .a:     SDL_SCANCODE_A
		case .b:     SDL_SCANCODE_B
		case .c:     SDL_SCANCODE_C
		case .d:     SDL_SCANCODE_D
		case .e:     SDL_SCANCODE_E
		case .f:     SDL_SCANCODE_F
		case .g:     SDL_SCANCODE_G
		case .h:     SDL_SCANCODE_H
		case .i:     SDL_SCANCODE_I
		case .j:     SDL_SCANCODE_J
		case .k:     SDL_SCANCODE_K
		case .l:     SDL_SCANCODE_L
		case .m:     SDL_SCANCODE_M
		case .n:     SDL_SCANCODE_N
		case .o:     SDL_SCANCODE_O
		case .p:     SDL_SCANCODE_P
		case .q:     SDL_SCANCODE_Q
		case .r:     SDL_SCANCODE_R
		case .s:     SDL_SCANCODE_S
		case .t:     SDL_SCANCODE_T
		case .u:     SDL_SCANCODE_U
		case .v:     SDL_SCANCODE_V
		case .w:     SDL_SCANCODE_W
		case .x:     SDL_SCANCODE_X
		case .y:     SDL_SCANCODE_Y
		case .z:     SDL_SCANCODE_Z
		case .left:  SDL_SCANCODE_LEFT
		case .right: SDL_SCANCODE_RIGHT
		case .up:    SDL_SCANCODE_UP
		case .down:  SDL_SCANCODE_DOWN
		}
	}
}

extension SDL_KeyCode
{
	internal init(scancode: SDL_Scancode)
	{
		self.init(scancode.rawValue | UInt32(SDLK_SCANCODE_MASK))
	}
}
