#!/usr/bin/env python

# Copyright (C) 2017 Seeed Technology Limited
#
# 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
#
#     http://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 modules.pixel_ring import pixel_ring
import numpy
import time
import threading
try:
    import queue as Queue
except ImportError:
    import Queue as Queue


class GoogleHomeLights:
    def __init__(self):
        self.basis = numpy.array([0] * 4 * 12)
        self.basis[0 * 4 + 0] = 2
        self.basis[3 * 4 + 2] = 2
        self.basis[6 * 4 + 1] = 1
        self.basis[6 * 4 + 2] = 1
        self.basis[9 * 4 + 1] = 2

        self.pixels = self.basis * 0
        self.write(self.pixels)

        pixel_ring.write(0, [6, 0, 0, 0])

        self.next = threading.Event()
        self.queue = Queue.Queue()
        self.thread = threading.Thread(target=self._run)
        self.thread.daemon = True
        self.thread.start()

    def wakeup(self, direction=0):
        def f():
            self._wakeup(direction)
        self.queue.put(f)

    def listen(self):
        self.next.set()
        self.queue.put(self._listen)

    def think(self):
        self.next.set()
        self.queue.put(self._think)

    def speak(self):
        self.next.set()
        self.queue.put(self._speak)

    def off(self):
        self.next.set()
        self.queue.put(self._off)


    def _run(self):
        while True:
            func = self.queue.get()
            func()

    def _wakeup(self, direction=0):
        position = int((direction + 15) / 30) % 12

        basis = numpy.roll(self.basis, position * 4)
        for i in range(1, 25):
            pixels = basis * i
            self.write(pixels)
            time.sleep(0.005)

        pixels =  numpy.roll(pixels, 4)
        self.write(pixels)
        time.sleep(0.1)

        for i in range(2):
            new_pixels = numpy.roll(pixels, 4)
            self.write(new_pixels * 0.5 + pixels)
            pixels = new_pixels
            time.sleep(0.1)

        self.write(pixels)
        self.pixels = pixels

    def _listen(self):
        pixels = self.pixels
        for i in range(1, 25):
            self.write(pixels * i / 24)
            time.sleep(0.01)

    def _think(self):
        pixels = self.pixels

        self.next.clear()
        while not self.next.is_set():
            pixels = numpy.roll(pixels, 4)
            self.write(pixels)
            time.sleep(0.2)

        t = 0.1
        for i in range(0, 5):
            pixels = numpy.roll(pixels, 4)
            self.write(pixels * (4 - i) / 4)
            time.sleep(t)
            t /= 2

        # time.sleep(0.5)

        self.pixels = pixels

    def _speak(self):
        pixels = self.pixels

        self.next.clear()
        while not self.next.is_set():
            for i in range(5, 25):
                self.write(pixels * i / 24)
                time.sleep(0.01)

            time.sleep(0.3)

            for i in range(24, 4, -1):
                self.write(pixels * i / 24)
                time.sleep(0.01)

            time.sleep(0.3)

        self._off()

    def _off(self):
        self.write([0] * 4 * 12)

    def write(self, data):
        if type(data) is list:
            pixel_ring.write(3, data)
        else:
            pixel_ring.write(3, data.astype('uint8').tostring())


lights = GoogleHomeLights()


if __name__ == '__main__':
    while True:

        try:
            lights.wakeup()
            time.sleep(3)
            lights.think()
            time.sleep(3)
            lights.speak()
            time.sleep(3)
            lights.off()
            time.sleep(3)
        except KeyboardInterrupt:
            break


    pixel_ring.off()
[((171, 4, 171, 20), 'modules.pixel_ring.pixel_ring.off', 'pixel_ring.off', ({}, {}), '()', False, 'from modules.pixel_ring import pixel_ring\n'), ((30, 21, 30, 46), 'numpy.array', 'numpy.array', ({(30, 33, 30, 45): '[0] * 4 * 12'}, {}), '([0] * 4 * 12)', False, 'import numpy\n'), ((40, 8, 40, 41), 'modules.pixel_ring.pixel_ring.write', 'pixel_ring.write', ({(40, 25, 40, 26): '(0)', (40, 28, 40, 40): '[6, 0, 0, 0]'}, {}), '(0, [6, 0, 0, 0])', False, 'from modules.pixel_ring import pixel_ring\n'), ((42, 20, 42, 37), 'threading.Event', 'threading.Event', ({}, {}), '()', False, 'import threading\n'), ((43, 21, 43, 34), 'Queue.Queue', 'Queue.Queue', ({}, {}), '()', True, 'import Queue as Queue\n'), ((44, 22, 44, 56), 'threading.Thread', 'threading.Thread', (), '', False, 'import threading\n'), ((78, 16, 78, 52), 'numpy.roll', 'numpy.roll', ({(78, 27, 78, 37): 'self.basis', (78, 39, 78, 51): 'position * 4'}, {}), '(self.basis, position * 4)', False, 'import numpy\n'), ((84, 18, 84, 39), 'numpy.roll', 'numpy.roll', ({(84, 29, 84, 35): 'pixels', (84, 37, 84, 38): '4'}, {}), '(pixels, 4)', False, 'import numpy\n'), ((86, 8, 86, 23), 'time.sleep', 'time.sleep', ({(86, 19, 86, 22): '(0.1)'}, {}), '(0.1)', False, 'import time\n'), ((82, 12, 82, 29), 'time.sleep', 'time.sleep', ({(82, 23, 82, 28): '(0.005)'}, {}), '(0.005)', False, 'import time\n'), ((89, 25, 89, 46), 'numpy.roll', 'numpy.roll', ({(89, 36, 89, 42): 'pixels', (89, 44, 89, 45): '4'}, {}), '(pixels, 4)', False, 'import numpy\n'), ((92, 12, 92, 27), 'time.sleep', 'time.sleep', ({(92, 23, 92, 26): '(0.1)'}, {}), '(0.1)', False, 'import time\n'), ((101, 12, 101, 28), 'time.sleep', 'time.sleep', ({(101, 23, 101, 27): '(0.01)'}, {}), '(0.01)', False, 'import time\n'), ((108, 21, 108, 42), 'numpy.roll', 'numpy.roll', ({(108, 32, 108, 38): 'pixels', (108, 40, 108, 41): '4'}, {}), '(pixels, 4)', False, 'import numpy\n'), ((110, 12, 110, 27), 'time.sleep', 'time.sleep', ({(110, 23, 110, 26): '(0.2)'}, {}), '(0.2)', False, 'import time\n'), ((114, 21, 114, 42), 'numpy.roll', 'numpy.roll', ({(114, 32, 114, 38): 'pixels', (114, 40, 114, 41): '4'}, {}), '(pixels, 4)', False, 'import numpy\n'), ((116, 12, 116, 25), 'time.sleep', 'time.sleep', ({(116, 23, 116, 24): 't'}, {}), '(t)', False, 'import time\n'), ((132, 12, 132, 27), 'time.sleep', 'time.sleep', ({(132, 23, 132, 26): '(0.3)'}, {}), '(0.3)', False, 'import time\n'), ((138, 12, 138, 27), 'time.sleep', 'time.sleep', ({(138, 23, 138, 26): '(0.3)'}, {}), '(0.3)', False, 'import time\n'), ((147, 12, 147, 37), 'modules.pixel_ring.pixel_ring.write', 'pixel_ring.write', ({(147, 29, 147, 30): '(3)', (147, 32, 147, 36): 'data'}, {}), '(3, data)', False, 'from modules.pixel_ring import pixel_ring\n'), ((160, 12, 160, 25), 'time.sleep', 'time.sleep', ({(160, 23, 160, 24): '(3)'}, {}), '(3)', False, 'import time\n'), ((162, 12, 162, 25), 'time.sleep', 'time.sleep', ({(162, 23, 162, 24): '(3)'}, {}), '(3)', False, 'import time\n'), ((164, 12, 164, 25), 'time.sleep', 'time.sleep', ({(164, 23, 164, 24): '(3)'}, {}), '(3)', False, 'import time\n'), ((166, 12, 166, 25), 'time.sleep', 'time.sleep', ({(166, 23, 166, 24): '(3)'}, {}), '(3)', False, 'import time\n'), ((130, 16, 130, 32), 'time.sleep', 'time.sleep', ({(130, 27, 130, 31): '(0.01)'}, {}), '(0.01)', False, 'import time\n'), ((136, 16, 136, 32), 'time.sleep', 'time.sleep', ({(136, 27, 136, 31): '(0.01)'}, {}), '(0.01)', False, 'import time\n')]