import json
from bcad.binterpreter.singleton import Singleton
from bcad.binterpreter.rqq import replies, RP_PROGRESS, requests, RQ_CANCEL


class StopExecution(Exception):
    pass


def init_progress(total, label=""):
    Singleton._progress_total = total
    Singleton._progress_current = 0
    Singleton._progress_label = label
    Singleton._progress_label_stack = []
    Singleton._cancel_requested = False
    Singleton._last_progress_time = 0
    _send_progress()


def push_label(fragment=""):
    Singleton._progress_label_stack.append(fragment)
    _send_progress()


def pop_label():
    if Singleton._progress_label_stack:
        Singleton._progress_label_stack.pop()
    _send_progress()


def advance_progress(label=None):
    Singleton._progress_current += 1
    if label is not None:
        if Singleton._progress_label_stack:
            Singleton._progress_label_stack[-1] = label
        else:
            Singleton._progress_label = label
    _send_progress()


def set_progress_label(label):
    if Singleton._progress_label_stack:
        Singleton._progress_label_stack[-1] = label
    else:
        Singleton._progress_label = label
    _send_progress()


def adjust_progress_total(delta):
    Singleton._progress_total += delta
    _send_progress()


def _send_progress():
    stack = getattr(Singleton, '_progress_label_stack', [])
    if stack:
        fragments = [f for f in stack if f]
        if fragments:
            full_label = " / ".join(fragments)
        else:
            full_label = getattr(Singleton, '_progress_label', '')
    else:
        full_label = getattr(Singleton, '_progress_label', '')

    if hasattr(Singleton, 'sh_progress_current'):
        Singleton.sh_progress_current.value = Singleton._progress_current
        Singleton.sh_progress_total.value   = Singleton._progress_total
        Singleton.sh_progress_label.value   = full_label.encode('utf-8')[:255] + b'\0'


def check_cancel():
    if getattr(Singleton, '_cancel_requested', False):
        raise StopExecution()
    if hasattr(Singleton, 'pipe') and Singleton.pipe is not None:
        try:
            if Singleton.pipe.poll():
                msg = Singleton.pipe.recv()
                data = json.loads(msg)
                if data.get('rq') == requests[RQ_CANCEL]:
                    Singleton._cancel_requested = True
                    raise StopExecution()
        except StopExecution:
            raise
        except Exception:
            pass


def reset_cancel():
    Singleton._cancel_requested = False


