#!/usr/bin/env python3
"""SC-Controller - Input Display
"""


import logging
import os
import signal
import sys

from gi.repository import Gtk

from scc.constants import LEFT, RIGHT, STICK, STICK_PAD_MAX, SCButtons
from scc.gui.daemon_manager import DaemonManager
from scc.gui.svg_widget import SVGWidget
from scc.osd import OSDWindow

log = logging.getLogger("osd.InputDisplay")


class InputDisplay(OSDWindow):
	IMAGE = "inputdisplay.svg"
	HILIGHT_COLOR = "#FF00FF00"  # ARGB
	OBSERVE_COLOR = "#00007FFF"  # ARGB

	def __init__(self, imagepath="/usr/share/scc/images"):
		OSDWindow.__init__(self, "osd-menu")
		self.daemon = None
		self.config = None
		self.hilights = {self.HILIGHT_COLOR: set(), self.OBSERVE_COLOR: set()}
		self.imagepath = imagepath

		self._eh_ids = []

	def show(self):
		self.main_area = Gtk.Fixed()
		self.background = SVGWidget(os.path.join(self.imagepath, self.IMAGE))
		self.lpadTest = Gtk.Image.new_from_file(os.path.join(self.imagepath, "inputdisplay-cursor.svg"))
		self.rpadTest = Gtk.Image.new_from_file(os.path.join(self.imagepath, "inputdisplay-cursor.svg"))
		self.stickTest = Gtk.Image.new_from_file(os.path.join(self.imagepath, "inputdisplay-cursor.svg"))

		self.main_area.set_property("margin-left", 10)
		self.main_area.set_property("margin-right", 10)
		self.main_area.set_property("margin-top", 10)
		self.main_area.set_property("margin-bottom", 10)

		self.main_area.put(self.background, 0, 0)
		self.main_area.put(self.lpadTest, 40, 40)
		self.main_area.put(self.rpadTest, 290, 90)
		self.main_area.put(self.stickTest, 150, 40)

		self.add(self.main_area)

		OSDWindow.show(self)
		self.lpadTest.hide()
		self.rpadTest.hide()
		self.stickTest.hide()

	def run(self):
		self.daemon = DaemonManager()
		self._connect_handlers()
		OSDWindow.run(self)

	def use_daemon(self, d):
		"""Allows (re)using already existing DaemonManager instance in same process.
		use_config() should be be called before parse_argumets() if this is used.
		"""
		self.daemon = d
		self._connect_handlers()
		self.on_daemon_connected(self.daemon)

	def _connect_handlers(self):
		self._eh_ids += [
			(self.daemon, self.daemon.connect("dead", self.on_daemon_died)),
			(self.daemon, self.daemon.connect("error", self.on_daemon_died)),
			(self.daemon, self.daemon.connect("alive", self.on_daemon_connected)),
		]

	def on_daemon_connected(self, *a):
		c = self.daemon.get_controllers()[0]
		c.unlock_all()
		c.observe(
			DaemonManager.nocallback,
			self.on_observe_failed,
			"A",
			"B",
			"C",
			"X",
			"Y",
			"START",
			"BACK",
			"LB",
			"RB",
			"LPAD",
			"RPAD",
			"LGRIP",
			"RGRIP",
			"LT",
			"RT",
			"LEFT",
			"RIGHT",
			"STICK",
			"STICKPRESS",
		)
		c.connect("event", self.on_daemon_event_observer)
		c.connect("lost", self.on_controller_lost)

	def on_observe_failed(self, error):
		log.error("Failed to enable test mode: %s", error)
		if "Sniffing" in error:
			log.error("")
			log.error("=================================================================================")
			log.error("[!!] Please, enable 'Input Test Mode' on 'Advanced' tab in SC Controller settings")
			log.error("=================================================================================")
		self.quit(3)

	def on_daemon_event_observer(self, daemon, what, data):
		if what in (LEFT, RIGHT, STICK):
			widget, area = {
				LEFT: (self.lpadTest, "LPADTEST"),
				RIGHT: (self.rpadTest, "RPADTEST"),
				STICK: (self.stickTest, "STICKTEST"),
			}[what]
			# Check if stick or pad is released
			if data[0] == data[1] == 0:
				widget.hide()
				return
			if not widget.is_visible():
				widget.show()
			# Grab values
			ax, ay, aw, trash = self.background.get_area_position(area)
			cw = widget.get_allocation().width
			# Compute center
			x, y = ax + aw * 0.5 - cw * 0.5, ay + 1.0 - cw * 0.5
			# Add pad position
			x += data[0] * aw / STICK_PAD_MAX * 0.5
			y -= data[1] * aw / STICK_PAD_MAX * 0.5
			# Move circle
			self.main_area.move(widget, x, y)
		elif what in ("LT", "RT", "STICKPRESS"):
			what = {"LT": "LEFT", "RT": "RIGHT", "STICKPRESS": "STICK"}[what]
			if data[0]:
				self.hilights[self.OBSERVE_COLOR].add(what)
			else:
				self.hilights[self.OBSERVE_COLOR].remove(what)
			self._update_background()
		elif hasattr(SCButtons, what):
			try:
				if data[0]:
					self.hilights[self.OBSERVE_COLOR].add(what)
				else:
					self.hilights[self.OBSERVE_COLOR].remove(what)
				self._update_background()
			except KeyError:
				# Non fatal
				pass
		else:
			print("event", what)

	def _update_background(self):
		h = {}
		for color in self.hilights:
			for i in self.hilights[color]:
				h[i] = color
		self.background.hilight(h)


def sigint(*a):
	print("\n*break*")
	sys.exit(0)


if __name__ == "__main__":
	signal.signal(signal.SIGINT, sigint)

	import gi

	gi.require_version("Gtk", "3.0")
	gi.require_version("Rsvg", "2.0")
	gi.require_version("GdkX11", "3.0")

	from scc.tools import init_logging

	init_logging()

	m = InputDisplay()
	if not m.parse_argumets(sys.argv):
		sys.exit(1)
	m.run()
	sys.exit(m.get_exit_code())
