import smtplib
from email.mime.text import MIMEText
from abc import ABCMeta, abstractmethod
import configparser
import logging

class AlertManager:

    def __init__(self, config):
        self.logger = logging.getLogger('hydrobot')
        self.from_addr = config.get("alerts", "from_address")
        self.to_addr  = config.get("alerts", "to_address")
        self.mail_server = config.get("alerts", "mail_server")
        self.username = config.get("alerts", "username")
        self.password = config.get("alerts", "password")
        
        self.alerts = []
        self.load_alerts(config)
        
    def load_alerts(self, config):
        
        for section in config.sections():
            if "alert" in section and section != "alerts":
                type = config.get(section, "type")
                if type == "output_feedback":
                    name = config.get(section, "name")
                    output_module = config.get(section, "output_module")
                    output_type = config.get(section, "output_type")
                    output_number = config.get(section, "output_number")
                    input_module = config.get(section, "input_module")
                    input_type = config.get(section, "input_type")
                    input_number = config.get(section, "input_number")
                    on_threshold = config.getfloat(section, "on_threshold")
                    off_threshold = config.getfloat(section, "off_threshold")
                    hysteresis = config.getfloat(section, "hysteresis")
                    self.alerts.append(OutputFeedbackAlert(self, name, output_module, output_type, output_number, input_module, input_type, input_number, on_threshold, off_threshold, hysteresis))
                elif type == "measurement":
                    name = config.get(section, "name")
                    input_module = config.get(section, "input_module")
                    input_type = config.get(section, "input_type")
                    input_number = config.get(section, "input_number")
                    high_threshold = config.getfloat(section, "high_threshold")
                    low_threshold = config.getfloat(section, "low_threshold")
                    hysteresis = config.getfloat(section, "hysteresis")
                    self.alerts.append(MeasurementAlert(self, name, input_module, input_type, input_number, high_threshold, low_threshold, hysteresis))
                
    
    def send_alert(self, message):
        
        msg = MIMEText(message)
        msg['Subject'] = "HydroBot Alert"
        msg['From'] = self.from_addr
        msg['To'] = self.to_addr
        
        try:
            server = smtplib.SMTP(self.mail_server)
            server.ehlo()
            server.starttls()
            server.login(self.username, self.password)
            server.send_message(msg)
            server.quit()
            self.logger.debug("Sent email alert: " + message)
        except:
            self.logger.error("Sending email alert failed!")
            
        
    def evaluate_alerts(self):
        for alert in self.alerts:
            alert.evalutate()

class Alert(metaclass=ABCMeta):
    
    def __init__(self, manager, name):
        self.manager = manager
        self.name = name
        
    @abstractmethod
    def evalutate(self):
        pass
        
class OutputFeedbackAlert(Alert):
    
    def __init__(self, manager, name, output_module, output_type, output_number, input_module, input_type, input_number, on_threshold, off_threshold, hysteresis):
        super(OutputFeedbackAlert, self).__init__(manager, name)
        
        self.output_module = output_module
        self.output_type = output_type
        self.output_number = output_number
        self.input_module = input_module
        self.input_type = input_type
        self.input_number = input_number
        self.on_threshold = on_threshold
        self.off_threshold = off_threshold
        self.hysteresis = hysteresis
        
    def evalutate(self):
        
        #get output status
        output_status = 1
        #get input status
        input_status = 0
        if output_status == 1:
            if input_status < self.on_threshold:
                #alert!
                print("Alert! " + self.name + " did not turn on!")
                self.manager.send_alert("Alert! " + self.name + " did not turn on!")
        if output_status == 0:
            if input_status > self.off_threshold:
                #alert!
                print("Alert! " + self.name + " did not turn off!")
                self.manager.send_alert("Alert! " + self.name + " did not turn off!")
            
        
class MeasurementAlert(Alert):
    
    def __init__(self, manager, name, input_module, input_type, input_number, high_threshold, low_threshold, hysteresis):
        super(MeasurementAlert, self).__init__(manager, name)
        
        self.input_module = input_module
        self.input_type = input_type
        self.input_number = input_number
        self.high_threshold = high_threshold
        self.low_threshold = low_threshold
        self.hysteresis = hysteresis
        
    def evalutate(self):
        #get input status
        input_status = 0
        if input_status > self.high_threshold:
            #alert!
            print("Alert! " + self.name + " is too high!")
            self.manager.send_alert("Alert! " + self.name + " is too high!")
        if input_status < self.low_threshold:
            #alert!
            print("Alert! " + self.name + " is too low!")
            self.manager.send_alert("Alert! " + self.name + " is too low!")

