import numpy as np
import time

from utils import send_update

from humidifier import Humidifier, HumidifierV2
from humidifier_v3 import HumidifierV3

class Controller:
  def __init__(self, humidifiers):
    self.target_lower = 83
    self.target_upper = 87
    self.feedforward_coeff = 50
    self.last_toggle = 0

    self._manual_mode = False
    self.manual_on = False
    self.manual_timeout = 0
    self.manual_duration = 40

    self.humidifier_history = np.zeros(50)
    self.first_sample = False
    self.humidifiers = humidifiers

  @property
  def manual_mode(self):
    return self._manual_mode

  @manual_mode.setter
  def manual_mode(self, on):
    self._manual_mode = on
    send_update({"status": {"manual_mode": on}})

  def set_checked(self, s, humidifier, on):
    if time.time() - self.last_toggle > 0.8:
      print("setting {} to {}".format(humidifier, on))
      if isinstance(humidifier, HumidifierV3):
        humidifier.set(s, on)
      elif isinstance(humidifier, Humidifier) or isinstance(humidifier, HumidifierV2):
        humidifier.toggle(s)
      self.last_toggle = time.time()

  def update(self, s, humidity):
    if self.first_sample:
      self.humidifier_history[:] = humidity
      self.first_sample = False
    else:
      self.humidifier_history[:-1] = self.humidifier_history[1:]
      self.humidifier_history[-1] = humidity

    # compensate for the slow response time by adding a little feed forward
    # using the slope of the humidifier data
    slope = (self.humidifier_history[-1] - self.humidifier_history[0])/self.humidifier_history.shape[0]
    comp_humidity = humidity + self.feedforward_coeff*slope

    if self.manual_mode and time.time() > self.manual_timeout:
      self.manual_mode = False

    if self.manual_mode:
      for humidifier in self.humidifiers:
        if not humidifier.on and self.manual_on:
          self.set_checked(s, humidifier, True)
        elif not humidifier.off and not self.manual_on:
          self.set_checked(s, humidifier, False)
    else:
      if comp_humidity < self.target_lower:
        for humidifier in self.humidifiers:
          if not humidifier.on:
            self.set_checked(s, humidifier, True)
      elif comp_humidity > self.target_upper:
        for humidifier in self.humidifiers:
          if not humidifier.off:
            self.set_checked(s, humidifier, False)