# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8

"""Contrôle d'exécution.
"""

__all__ = ('Status', 'OK_STATUS', 'ERROR_STATUS',
           'Exit', 'exit', 'die')

import sys

from .base import isnum
from .output import eerror

class Status:
    """Un objet qui peut être utilisé pour retourner un status pour l'exécution
    d'un programme ou d'une opération.

    Le status peut être OK ou ERROR. La valeur booléenne de cet objet est True
    ou False en fonction de la valeur du status. Un code de retour de programme
    associé est disponible avec la propriété exitcode.
    """

    ok = True
    exitcode = 0
    def __init__(self, ok=None, exitcode=None):
        if ok is not None:
            self.ok = ok
            if exitcode is None:
                if ok: exitcode = 0
                else: exitcode = 1
            self.exitcode = exitcode
        elif exitcode is not None:
            self.ok = exitcode == 0
            self.exitcode = exitcode

    def __nonzero__(self):
        return self.ok

OK_STATUS = Status(True)
ERROR_STATUS = Status(False)

def ensure_status(status):
    """Retourner une instance de Status.

    Si status est un entier, le prendre comme valeur de retour.
    Sinon, le considérer comme une valeur booléenne indiquant le status: OK ou ERREUR.
    """
    if isinstance(status, Status): return status
    elif isnum(status): return Status(exitcode=int(status))
    else: return Status(status)

class Exit(Exception):
    """Classe qui peut être utilisée pour propager un code de retour quand on
    quitte l'application.
    """
    def __init__(self, status):
        self.exitcode = ensure_status(status).exitcode

def exit(status=OK_STATUS):
    """Quitter le programme avec l'exception Exit, en propageant par défaut le
    status OK_STATUS.
    """
    raise Exit(status)

def die(msg=None, status=ERROR_STATUS):
    """Quitter le programme en affichant un message d'erreur, en propageant
    par défaut le status ERROR_STATUS.

    Si msg==None, on prend le message de la dernière exception capturée.
    """
    eerror(msg)
    raise Exit(status)

def enable_exit_control():
    """Installer un excepthook qui appelle sys.exit() quand on lève l'exception
    Exit.
    """
    prev_excepthook = sys.excepthook
    if prev_excepthook is sys.__excepthook__:
        prev_excepthook = None
    def exit(cls, obj, tb, prev_excepthook=prev_excepthook):
        if issubclass(cls, Exit): sys.exit(obj.exitcode)
        elif prev_excepthook is not None:
            prev_excepthook(cls, obj, tb)
        else: sys.__excepthook__(cls, obj, tb)
    sys.excepthook = exit
