#!/usr/bin/env python3
import sys
import time
import socket
import threading
from threading import Thread, current_thread
import subprocess
from six.moves import input
from zeroconf import ServiceBrowser, Zeroconf
import uuid

server_address = ""
server_port = 0

class Client(object):
  def __init__(self, server, port, connection_lost, padnum):
    self.server = server
    self.port = port
    self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    self.sock.settimeout(100)
    self.connection_lost = connection_lost
    self.padnum = padnum

    try:
      self.sock.connect(self.server, self.port)
      listen = threading.Thread(target = self.acceptCommand)
      listen.start()
      print("pad ", self.padnum, " connected\n")
    except:
      print("Could not connect to server at address: ", self.server, ":", self.port, "\n")
      connection_lost.set()


  def acceptCommand(self):
    buffer = 1024
    cl = CommandList()
    while True:
      try:
        command = str(self.sock.recv(buffer).decode())
        if command:
          execute = threading.Thread(target = cl.call, args = (command, self.sock, self.connection_lost, self.padnum))
          execute.start()
        else:
          print("pad ", self.padnum, " disconnected\n")
          self.sock.close()
          self.connection_lost.set()
          return False
      except:
        print("acceptCommand read error\n")
        self.sock.close()
        self.connection_lost.set()
        return False
    return True

class CommandList:
  def call(self, num, socket, connection_lost, padnum):
    num = str(num)

    if(num == "0"):
      print("Recieved 0 - Connection Terminated\n")
      socket.close()
    elif(num == "1"):
      print("Recieved 1 - Connection Established\n")
      socket.send(str.encode("1"))
      socket.send(str.encode("\n"))
      socket.send(str.encode(str(padnum)))
      socket.send(str.encode("\n"))
    elif(num == "2"):
      print("Recieved 2 - Sensor On, Detecting Impacts\n")
    elif(num == "3"):
      print("Recieved 3 - Target On\n")
      time.sleep(2)
      print("Hit - Sending 3\n")
      socket.send(str.encode("3"))
      socket.send(str.encode("\n"))
    elif(num == "4"):
      print("Recieved 4 - Turning off sensor\n")
    else:
      print("Number not recognized: ", num, "\n")

class Listener:
  def remove_service(self, zeroconf, type, name):
    pass

  def add_service(self, zeroconf, type, name):
    global server_address, server_port
    info = zeroconf.get_service_info(type, name)
    if info.name.find("skillcourtapp") >= 0:
      server_address = socket.inet_ntoa(info.addresses[0])
      server_port = info.port

class Utilities(object):
  def findAppConnection(self, event_handler):
    print("Looking for server address and port of Agineek App\n")
    thread = threading.Thread(target = self.appBrowse, args = (event_handler,))
    thread.start()
    print("App browsing thread started\n")

  def appBrowse(self, event_handler):
    zeroconf = Zeroconf()
    listener = Listener()
    browser = ServiceBrowser(zeroconf, "_http._tcp.local.", listener)
    while server_port == 0:
      pass
    event_handler.set()
    zeroconf.close()
    return True

if __name__ == "__main__":
  server_found = threading.Event()
  connection_lost = threading.Event()

  pads = []

  while True:
    try:
      Utilities().findAppConnection(server_found)
      print("Waiting for discovery...\n")
      server_found.wait()

      pad1 = threading.Thread(target = Client, args = (server_address, server_port, connection_lost, 100), daemon=True)
      pad2 = threading.Thread(target = Client, args = (server_address, server_port, connection_lost, 100), daemon=True)
      pad3 = threading.Thread(target = Client, args = (server_address, server_port, connection_lost, 100), daemon=True)
      pad4 = threading.Thread(target = Client, args = (server_address, server_port, connection_lost, 100), daemon=True)

      pads.append(pad1)
      pads.append(pad2)
      pads.append(pad3)
      pads.append(pad4)

      for pad in pads:
        pad.start()

      for pad in pads:
        pad.join()

      connection_lost.wait()
      connection_lost.clear()
      server_found.clear()
      server_address = ""
      server_port = 0
    except KeyboardInterrupt:
      print("Interrupted by CTRL-C\n")
      sys.exit()
      break
