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

# It script it publish under GNU GENERAL PUBLIC LICENSE
# http://www.gnu.org/licenses/gpl-3.0.en.html
# Author: the Galaxie EveLoop Team, all rights reserved

import logging


class Hooks(object):
    def __init__(self, debug=None):
        self.__debug = None
        self.__statement = None
        self.__parsing = None
        self.__pre = None
        self.__cmd = None
        self.__post = None
        self.__finalization = None
        self.__dispatch = None
        self.__keyboard_interruption = None

        self.debug = debug
        self.statement = None
        self.parsing = None
        self.pre = None
        self.cmd = None
        self.post = None
        self.finalization = None
        self.dispatch = None
        self.keyboard_interruption = None

    @property
    def debug(self):
        return self.__debug

    @debug.setter
    def debug(self, debug=None):
        """
        Set the debugging level of information's display on the stdscr.

        Generally it highly stress the console and is here for future maintenance of that Application.

        Enjoy future dev it found it function ;)

        :param debug: True is debugging mode is enable, False for disable it.
        :type debug: bool
        :raise TypeError: when "debug" argument is not a :py:__area_data:`bool`
        """
        if debug is None:
            debug = False
        if type(debug) != bool:
            raise TypeError('"debug" must be a boolean type')
        if self.debug != debug:
            self.__debug = debug

    @property
    def statement(self):
        """
        Register a hook to be called before parsing information, support to iterate th the application

        :return: A callable function
        :rtype: callable
        """
        return self.__statement

    @statement.setter
    def statement(self, value):
        """
        Set the ``statement`` property value

        :param value: A callable function
        :type value: callable
        :raise TypeError: When ``statement`` property is not a ``callable`` or None
        """
        if value and not hasattr(value, '__call__'):
            raise TypeError("'statement' property value must be a callable")

        if value != self.statement:
            if self.debug:
                logging.debug("{0}: [STATEMENT] {1}".format(self.__class__.__name__, value))
            self.__statement = value

    @property
    def parsing(self):
        """
        Register a hook to be called after have receive ``statement`` from the application.

        :return: A callable function
        :rtype: callable
        """
        return self.__parsing

    @parsing.setter
    def parsing(self, value):
        """
        Set the ``parsing`` property value

        :param value: A callable function
        :type value: callable
        :raise TypeError: When ``parsing`` property is not a ``callable`` or None
        """
        if value and not hasattr(value, '__call__'):
            raise TypeError("'parsing' property value must be a callable")

        if value != self.parsing:
            if self.debug:
                logging.debug("{0}: [PARSING] {1}".format(self.__class__.__name__, value))
            self.__parsing = value

    @property
    def pre(self):
        """
        Register a hook to be called before the command function.

        :return: A callable function
        :rtype: callable
        """
        return self.__pre

    @pre.setter
    def pre(self, value):
        """
        Set the ``cmd`` property value

        :param value: A callable function
        :type value: callable
        :raise TypeError: When ``pre`` property is not a ``callable`` or None
        """
        if value and not hasattr(value, '__call__'):
            raise TypeError("'pre' property value must be a callable")

        if value != self.pre:
            if self.debug:
                logging.debug("{0}: [PRE] {1}".format(self.__class__.__name__, value))
            self.__pre = value

    @property
    def cmd(self):
        """
        Register a hook to be called as the command function.

        :return: A callable function
        :rtype: callable
        """
        return self.__cmd

    @cmd.setter
    def cmd(self, value):
        """
        Set the ``cmd`` property value

        :param value: A callable function
        :type value: callable
        :raise TypeError: When ``cmd`` property is not a ``callable`` or None
        """
        if value and not hasattr(value, '__call__'):
            raise TypeError("'cmd' property value must be a callable")

        if value != self.cmd:
            if self.debug:
                logging.debug("{0}: [CMD] {1}".format(self.__class__.__name__, value))
            self.__cmd = value

    @property
    def post(self):
        """
        Register a hook to be called after the command function.

        :return: A callable function
        :rtype: callable
        """
        return self.__post

    @post.setter
    def post(self, value):
        """
        Set the ``post`` property value

        :param value: A callable function
        :type value: callable
        :raise TypeError: When ``post`` property is not a ``callable`` or None
        """
        if value and not hasattr(value, '__call__'):
            raise TypeError("'post' property value must be a callable")

        if value != self.post:
            if self.debug:
                logging.debug("{0}: [POST] {1}".format(self.__class__.__name__, value))
            self.__post = value

    @property
    def finalization(self):
        """
        Register a hook to be called just before mainloop exit, whether it completes successfully or not.

        :return: A callable function
        :rtype: callable
        """
        return self.__finalization

    @finalization.setter
    def finalization(self, value):
        """
        Set the ``finalization`` property value

        :param value: A callable function
        :type value: callable
        :raise TypeError: When ``finalization`` property is not a ``callable`` or None
        """
        if value and not hasattr(value, '__call__'):
            raise TypeError("'finalization' property value must be a callable")

        if value != self.finalization:
            if self.debug:
                logging.debug("{0}: [FINALIZATION] {1}".format(self.__class__.__name__, value))
            self.__finalization = value

    @property
    def dispatch(self):
        """
        Should be remove soon

        :return: A callable function
        :rtype: callable
        """
        return self.__dispatch

    @dispatch.setter
    def dispatch(self, value):
        """
        Set the ``dispatch`` property value

        :param value: A callable function
        :type value: callable
        :raise TypeError: When ``dispatch`` property is not a ``callable`` or None
        """
        if value and not hasattr(value, '__call__'):
            raise TypeError("'dispatch' property value must be a callable")

        if value != self.dispatch:
            if self.debug:
                logging.debug("{0}: [STATEMENT] {1}".format(self.__class__.__name__, value))
            self.__dispatch = value

    @property
    def keyboard_interruption(self):
        """
        Register a hooks it Shortcut KeyboardInterrupt during the mainloop execution

        :return: A callable function
        :rtype: callable
        """
        return self.__keyboard_interruption

    @keyboard_interruption.setter
    def keyboard_interruption(self, value):
        """
        Set the ``keyboard_interruption`` property value

        :param value: A callable function
        :type value: callable
        :raise TypeError: When ``keyboard_interruption`` property is not a ``callable`` or None
        """
        if value and not hasattr(value, '__call__'):
            raise TypeError("'keyboard_interruption' property value must be a callable")

        if value != self.keyboard_interruption:
            if self.debug:
                logging.debug("{0}: [KEYBOARD_INTERRUPTION] {1}".format(self.__class__.__name__, value))
            self.__keyboard_interruption = value
