# By Dan Hagon (@axiomsofchoice)
# 05/06/2022 at a rainy EMFCamp
# MIT License

from tidal import *
from app import TextApp

from st7789_passthrough import tidal_display
import st7789

import accelerometer

from math import sin, cos, pi, sqrt, atan2
from random import uniform, randrange

class Particle():
  
  def __init__(self, disp_w, disp_h, cur_acc, max_speed=8., lifetime=10):
    self.position = (int(uniform(0., disp_w)), int(uniform(0., disp_h)))
    # Speed in pixels per tick (where tick is typically 100ms)
    speed = uniform(.75 * max_speed, max_speed)
    
    # Make sure the generated direction is within a sector of the circle
    norm = sqrt(cur_acc[0] * cur_acc[0] + cur_acc[1] * cur_acc[1])
    cur_dir = (cur_acc[0] / norm, cur_acc[1] / norm)
    rad_dir = uniform(atan2(cur_dir[0], cur_dir[1]) - (0.1 * pi),
                      atan2(cur_dir[0], cur_dir[1]) + 0.1 * pi)
    self.velocity = (speed * sin(rad_dir), speed * cos(rad_dir))

    self.lifetime = randrange(lifetime // 2, lifetime)
    self.life_line = []
  
  def update_pos(self, accel):
    self.position = (self.position[0] + self.velocity[0], self.position[1] + self.velocity[1])
    self.velocity = (self.velocity[0] + accel[0], self.velocity[1] + accel[1])
    self.lifetime -= 1
    self.life_line.append(self.position)

  def draw(self):
    if len(self.life_line) > 1:
      for i in range(len(self.life_line)-1):
        tidal_display.line(int(self.life_line[i][0]),
                           int(self.life_line[i][1]),
                           int(self.life_line[i+1][0]),
                           int(( self.life_line[i+1][1])),
                           st7789.BLUE)
    tidal_display.line(int(self.pos[0]),
                       int(self.pos[1]),
                       int(self.pos[0] + self.vel[0]),
                       int((self.pos[1] + self.vel[1])),
                       st7789.WHITE)
        
  @property
  def pos(self):
    return self.position
    
  @property
  def vel(self):
    return self.velocity

  @property
  def is_live(self):
    return self.lifetime > 0
  
class ParticlesApp(TextApp):

  BG = BLACK
  FG = WHITE

  def seed_particles(self, w, h, curr_acc, max_particles=18):
      if self.particle_state is None:
        self.particle_state = []
        
      num_parts = len(self.particle_state)
      self.particle_state.extend([Particle(w, h, curr_acc) for _ in range(max_particles - num_parts)])
    
  def on_activate(self):
    super().on_activate()

    w = tidal_display.width()
    h = tidal_display.height()

    self.particle_state = []
    #self.seed_particles(w, h)
    
    accelerometer.init()

    def animation_tick():

      # Get acceleromter value
      accel_vals = accelerometer.get_xyz()[:2]
      # Flip one of the directions
      accel_vals = (accel_vals[0], -accel_vals[1])
      
      # Update particle state
      for p in self.particle_state:
        p.update_pos(accel_vals)
      
      # Remove the dead particles
      self.particle_state = [p for p in self.particle_state if p.is_live]

      # If necessary add new particles
      self.seed_particles(w, h, accel_vals)

      # Redraw the screen
      self.window.cls()
      # Coords
      #self.window.println("(%f,\n%f)" % accel_vals)
      # Accelerometer
#       tidal_display.line(int(0.5 * w),
#                          int(0.5 * h),
#                          int((0.5 + (0.5 * accel_vals[0])) * w),
#                          int((0.5 + (0.5 * accel_vals[1])) * h),
#                          st7789.WHITE)
      # Draw particles
      for p in self.particle_state:
        p.draw()
      
    self.timer = self.periodic(100, animation_tick)

  def on_deactivate(self):
    super().on_deactivate()

    self.timer.cancel()

main = ParticlesApp