#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# System modules
import sys
from time import sleep

# Other templates
from ..config.constants import camera_state, filter_state, image_state
from ..devices import cam, sof, tel
from ..utils.logger import log


class BaseTemplate:
    '''Base template. Other templates inherit from this, by filling up
       the "content" method.'''

    def __init__(self):
        '''Contructor'''

        self.name = __name__
        self.description = "Other templates inherit from this"
        self.error = []         # List of errors
        self.paused = False     # pause flag
        self.aborted = False    # abort flag
        self.filename = ""      # Current filename
        self.filenames = []     # List of saved filenames
        self.output = {}        # Other output produced by template (txt?)

    # Exception decorator does NOT go here
    def content(self, params):
        '''
        Here the inherited template will be developed
        '''

    # Exception decorator goes here
    def run(self, params, extra={}):
        '''
        Check the params and run the content method.
        '''

        log.info(f"Running template {self.name}")

        if not params:
            log.warning(f"Params are empty: {params}")
        else:
            log.debug(f"Params:")
            for key, value in params.items():
                log.debug(f"{key:>10}  {str(value):<6}")

        log.info(f"Running content {self.name}")
        self.aborted = False
        self.paused = False

        # Here the content is executed
        self.content(params)

        log.info(f"Template {self.name} ended")

    def check_pause_or_abort(self):
        '''
        Pause/Resume/Stop the execution of the template.
        '''

        if self.aborted:
            log.warning("Abort flag detected!")
            self.abort()
            return True

        if self.paused:
            log.warning("Pause flag detected!")

        while self.paused:
            sleep(0.1)
            if self.aborted:
                log.warning("Abort flag detected!")
                self.abort()
                return True

        return False

    def abort(self):
        '''
        Abort this template.
        '''

        msg = f"Aborting template {self.name}"
        log.error(msg)
        self.error.append(msg)

        try:
            if sof.state:
                # To be checked:
                # if the camera is off, here cam.state=[],
                # while in ipython cam.state=None
                if (cam.state != 0) or (cam.is_moving != 0) or (cam.ready != 1):
                    log.warning(f"Camera is {camera_state[cam.state]}")
                    log.warning(f"Filter is {filter_state[cam.is_moving]}")
                    log.warning(f"Buffer is {image_state[cam.ready]}")
                    log.error(f"Aborting camera.")
                    cam.abort()

                while (cam.state != 0) or (cam.is_moving != 0):
                    log.warning(
                        f"Waiting, camera still {camera_state[cam.state]}")
                    log.warning(
                        f"Waiting, filter still {filter_state[cam.is_moving]}")
                    log.warning(
                        f"Waiting, buffer still {image_state[cam.ready]}")
                    sleep(0.5)

        except Exception as e:
            msg = f"Interrupt triggered in {__name__}"
            log.error(msg)
            log.error(e)
            self.error.append(msg)
            self.error.append(e)

        try:
            log.warning(f"Exiting {__name__}")
            self.aborted = True  # This maybe work if called outside the sequencer
            # sys.exit(1) # This only works for sequencer
        except Exception as e:
            log.error(f"sys.exit() does not work here: {e}")
            raise e
