# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os
from random import randint
from threading import Thread
import time
from edgetpu.basic.basic_engine import BasicEngine
import model
import pygame
from pygame.locals import *
import queue

from random import randrange
from adafruit_servokit import ServoKit

import board
import busio
import adafruit_pca9685
import time

i2c = busio.I2C(board.SCL, board.SDA)
hat = adafruit_pca9685.PCA9685(i2c)
hat.frequency = 60

kit = ServoKit(channels=16) # set number of channels
#kit.servo[0].actuation_range = 160
#kit.servo[0].set_pulse_width_range(1000, 2000)

# up, mid and down settings for left and right arms
up_l = 35
md_l = 90
dn_l = 160
up_r = 160
md_r = 90
dn_r = 35

lft= 15  # number of servo port, left servo (0-8)
rgt= 11  # number of servo port, right servo (0-8)

led_channel_0 = hat.channels[0]  # LED set on port 0
led_channel_0.duty_cycle = 0  #turn on LED 100%

#list of arm settings for nine positions
position = [(md_l,md_r),
            (up_l,up_r),(up_l,md_r),(up_l,dn_r),
            (md_l,up_r),(md_l,md_r),(md_l,dn_r),
            (dn_l,up_r),(dn_l,md_r),(dn_l,dn_r)]
# defines 9 JumpingJack positions, indicated by integers 0-9

dance1 =(0,8,7,4,1,2,3,6,9,8,5,2,1,4,7,8,9,6,3,2,0) # a "dance"
  
class Controler(object):     #Callback function
    def __init__(self, q):
        self._q = q

    def callback(self, command):
        self._q.put(command)

class App:

  def __init__(self):
    self._running = True

  def on_init(self):
    pygame.init()

    self.game_started = True
    self._running = True
    return True

  def on_event(self, event):
    if event.type == pygame.QUIT:
      self._running = False

  def JumpingJack0(self, keys):    # controls Jumping Jack, keywords: "position x"
        key = int(keys)
        p = position[key]
        a = p[0]
        b = p[1]
        print ("Position: ", key, "  left/right: ",a,"/",b,"degree")
#       sys.stdout.write("Position: ", key, "  left/right: ",a,"/",b,"degree")
        kit.servo[lft].angle = a
        kit.servo[rgt].angle = b
        time.sleep(0.1)
        
  def JumpingJack1(self):    # controls Jumping Jack dance, keyword: "next game"
        dnce = dance1
        sp=(len(dnce))
        for r in range (sp):     #dancing order of positions, sp steps
         dc = dnce[r]
         if (dc not in range(10)):
  #         print ("input error at position ", sp)
            dc=4
         p = position[dc]
         a = p[0]
         b = p[1]
         kit.servo[lft].angle = a
         kit.servo[rgt].angle = b
         time.sleep(0.25)  # sets velocity of movements
        
  def JumpingJack2(self, keys):    # controls Jumping Jack LEDs, keywords: "switch on/off"
        led = int(keys)
        
        if led == 1:
            led_channel_0.duty_cycle = 0xffff  #turn on LED 100%
            time.sleep (0.1)

        if led == 0:
            led_channel_0.duty_cycle = 0 # turn off LED
            time.sleep (0.1)
        
        if led ==  2 :    # blink
            led_channel_0.duty_cycle = 0xffff  #turn on LED 100%
            time.sleep (0.5)
            led_channel_0.duty_cycle = 0  #turn on LED 100%
            time.sleep (0.5)
            led_channel_0.duty_cycle = 0xffff  #turn on LED 100%
            time.sleep (0.5)
            led_channel_0.duty_cycle = 0  #turn on LED 100%
            time.sleep (0.5)
            led_channel_0.duty_cycle = 0xffff  #turn on LED 100%
            time.sleep (0.1)

  def JumpingJack3(self):    # controls Jumping Jack dance, keyword: "random game"
#      for h in range (10):
         dr= randrange (9)  

         p = position[dr]
         a = p[0]
         b = p[1]
         kit.servo[lft].angle = a
         kit.servo[rgt].angle = b
         time.sleep(0.25)  # sets velocity of movements
            

  def spotter(self, args):
    engine = BasicEngine(args.model_file)

    mic = args.mic if args.mic is None else int(args.mic)
    model.classify_audio(mic, engine,
                         labels_file="config/labels_gc2.raw.txt",
                         commands_file="config/commands_v2_hampelmann.txt",
                         dectection_callback=self._controler.callback,
                         sample_rate_hz=int(args.sample_rate_hz),
                         num_frames_hop=int(args.num_frames_hop))

  def on_execute(self, args):
    if not self.on_init():
      self._running = False

    q = model.get_queue()
    self._controler = Controler(q)

    if not args.debug_keyboard:
      t = Thread(target=self.spotter, args=(args,))
      t.daemon = True
      t.start()

    item = -1
    while self._running:
      pygame.event.pump()
      if args.debug_keyboard:
        keys = pygame.key.get_pressed()
      else:
        try:
          new_item = q.get(True, 0.1)
        except queue.Empty:
          new_item = None

        if new_item is not None:
          item = new_item

      if (args.debug_keyboard and keys[pygame.K_ESCAPE]) or item == "stop":
        self._running = False

#      if (args.debug_keyboard and keys[pygame.K_SPACE]) or item == "go":
#        self.JumpingJack0(7)
#
      if (args.debug_keyboard and keys[pygame.K_RIGHT]) or item == "right":
          self.JumpingJack0(6)

      if (args.debug_keyboard and keys[pygame.K_LEFT]) or item == "left":
          self.JumpingJack0(4)

      if (args.debug_keyboard and keys[pygame.K_UP]) or item == "up":
          self.JumpingJack0(1)

      if (args.debug_keyboard and keys[pygame.K_DOWN]) or item == "down":
          self.JumpingJack0(9)

      if (args.debug_keyboard and keys[pygame.K_0]) or item == "0":
          self.JumpingJack0(0)

      if (args.debug_keyboard and keys[pygame.K_1]) or item == "1":
          self.JumpingJack0(1)

      if (args.debug_keyboard and keys[pygame.K_2]) or item == "2":
          self.JumpingJack0(2)

      if (args.debug_keyboard and keys[pygame.K_3]) or item == "3":
          self.JumpingJack0(3)

      if (args.debug_keyboard and keys[pygame.K_4]) or item == "4":
          self.JumpingJack0(4)

      if (args.debug_keyboard and keys[pygame.K_5]) or item == "5":
          self.JumpingJack0(5)

      if (args.debug_keyboard and keys[pygame.K_6]) or item == "6":
          self.JumpingJack0(6)

      if (args.debug_keyboard and keys[pygame.K_7]) or item == "7":
          self.JumpingJack0(7)

      if (args.debug_keyboard and keys[pygame.K_8]) or item == "8":
          self.JumpingJack0(8)

      if (args.debug_keyboard and keys[pygame.K_9]) or item == "9":
          self.JumpingJack0(9)
          
      if (args.debug_keyboard and keys[pygame.K_a]) or item == "d":
          self.JumpingJack1() #dancing Jack, on "next_game"

      if (args.debug_keyboard and keys[pygame.K_j]) or item == "j":
          self.JumpingJack2(0) #LED on, ON "switch_on"
      
      if (args.debug_keyboard and keys[pygame.K_k]) or item == "k":
          self.JumpingJack2(1) #LED off, on "swithch off"

      if (args.debug_keyboard and keys[pygame.K_l]) or item == "l":
          self.JumpingJack2(1) #LED blink "target"

      if (args.debug_keyboard and keys[pygame.K_r]) or item == "r":
          self.JumpingJack3() #random dance "random game"
      
      
      time.sleep(0.05)
    self.on_cleanup()


if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument(
      '--debug_keyboard',
      help='Use the keyboard to control the JumpingJack.',
      action='store_true',
      default=False)
  model.add_model_flags(parser)
  args = parser.parse_args()
  the_app = App()
  the_app.on_execute(args)
