from components import APid
from components.pid.pid import Pid
import enum

DEFAULT_THRESHOLDS = {
	"HoldIdle": 0.1,
	"HoldHeat": 1.0,
	"IdleHeat": 1.0,
	"IdleHold": 0.1,
	"HeatHold": 1.0,
	"HeatIdle": 1.0
}

class States(enum.Enum):
	INIT = -1,
	IDLE = 0,
	HEAT = 1,
	HOLD = 2

class TempControllerBase(APid):

	def __init__(self, dt, params):
		APid.__init__(self)
		self.pid_hold = Pid(dt)
		self.pid_rate = Pid(dt)
		self.theta_ist_set = 0
		self.theta_soll_set = 0
		self.heatrate_ist_set = 0
		self.heatrate_soll_set = 1.0
		self.heatrate_soll = 1.0
		self.theta_ist = 0
		self.heatrate_ist = 0
		self.params = params
		self.thresholds = {**DEFAULT_THRESHOLDS, **params.get('Thresholds', {})}
		self.y = -1
		self.state = States.INIT
		self.pid_hold.set_params(params['Hold'])
		self.pid_rate.set_params(params['Heat'])
		self.is_startup = True

	def on_state_entered(self, state):
		pass

	def post_pid(self):
		pass

	def set_theta_ist(self, value):
		self.theta_ist_set = value
		if self.is_startup:
			self.is_startup = False

	def get_theta_ist(self):
		return self.theta_ist

	def set_heatrate_ist(self, value):
		self.heatrate_ist_set = value

	def get_heatrate_ist(self):
		return self.heatrate_ist

	def set_theta_soll(self, value):
		self.theta_soll_set = value

	def get_theta_soll(self):
		return self.theta_soll

	def get_theta_soll_set(self):
		return self.theta_soll_set

	def set_heatrate_soll(self, value):
		self.heatrate_soll_set = value

	def get_heatrate_soll(self):
		return self.heatrate_soll

	def get_heatrate_soll_set(self):
		return self.heatrate_soll_set

	def process_fsm(self, diff):
		state_next = self.state
		if self.state == States.INIT:
			if not self.is_startup:
				state_next = States.IDLE
		elif self.state == States.IDLE:
			if diff >= self.thresholds['IdleHeat']:
				state_next = States.HEAT
				self.pid_rate.reset()
			elif diff >= -self.thresholds['IdleHold']:
				state_next = States.HOLD
				self.pid_rate.reset()
		elif self.state == States.HOLD:
			if diff >= self.thresholds['HoldHeat']:
				state_next = States.HEAT
				self.pid_rate.reset()
			elif diff <= -self.thresholds['HoldIdle']:
				state_next = States.IDLE
		elif self.state == States.HEAT:
			if diff <= -self.thresholds['HeatIdle']:
				state_next = States.IDLE
			elif diff <= self.thresholds['HeatHold']:
				state_next = States.HOLD
				self.pid_hold.reset()

		if state_next != self.state:
			self.state = state_next
			self.on_state_entered(state_next)

	def process_pid(self, theta_err, heatrate_err, hold_scale=1.0):
		self.pid_hold.process(theta_err, -self.theta_ist, hold_scale)
		self.pid_rate.process(heatrate_err, -self.heatrate_ist)

		if self.state == States.IDLE:
			self.y = 0
		else:
			self.y = self.pid_rate.get_y()

		self.post_pid()

	def get_power(self):
		return self.y
