# -*- coding: utf-8 -*-
# Copyright 2019 - 2022 Avram Lubkin, All Rights Reserved

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

"""
Provides a terminal class primarily for accessing functions that depend on
a terminal which has been previously setup as well as those functions
"""

import importlib
import io
import platform
import sys

from jinxed.terminfo import BOOL_CAPS, NUM_CAPS
from jinxed._util import BASESTRING, error, raise_from_none

if platform.system() == 'Windows':  # pragma: no branch
    from jinxed.win32 import get_term  # pragma: no cover
else:
    from jinxed._util import get_term


TERM = None


class Terminal(object):
    """
    Persistent terminal object for functions that require a previously configured state
    """

    def __init__(self, term=None, fd=-1):  # pylint: disable=invalid-name

        # Type check for term
        if term is not None and not isinstance(term, BASESTRING):
            raise TypeError('term must be a string or None, not %s' % type(term).__name__)

        # Type check and default handling for fd
        if fd == -1:
            try:
                self.stream_fd = sys.stdout.fileno()
            except (AttributeError, TypeError, io.UnsupportedOperation):
                self.stream_fd = None
        elif not isinstance(fd, int):
            raise TypeError('fd must be an integer, not %s' % type(fd).__name__)
        else:
            self.stream_fd = fd

        # Try to dynamically determine terminal type
        if term is None:
            term = get_term(self.stream_fd)

        try:
            self.terminfo = importlib.import_module('jinxed.terminfo.%s' % term.replace('-', '_'))
        except ImportError:
            raise_from_none(error('Could not find terminal %s' % term))

    def tigetstr(self, capname):
        """
        Reimplementation of curses.tigetstr()
        """

        return self.terminfo.STR_CAPS.get(capname, None)

    def tigetnum(self, capname):
        """
        Reimplementation of curses.tigetnum()
        """

        return self.terminfo.NUM_CAPS.get(capname, -1 if capname in NUM_CAPS else -2)

    def tigetflag(self, capname):
        """
        Reimplementation of curses.tigetflag()
        """

        if capname in self.terminfo.BOOL_CAPS:
            return 1
        return 0 if capname in BOOL_CAPS else -1


def setupterm(term=None, fd=-1):  # pylint: disable=invalid-name
    """
    Reimplementation of :py:func:`curses.setupterm`
    """

    global TERM  # pylint: disable=global-statement
    TERM = Terminal(term, fd)


def tigetflag(capname):
    """
    Reimplementation of :py:func:`curses.tigetflag`
    """

    if TERM is None:
        raise error('Must call setupterm() first')
    return TERM.tigetflag(capname)


def tigetnum(capname):
    """
    Reimplementation of :py:func:`curses.tigetnum`
    """

    if TERM is None:
        raise error('Must call setupterm() first')
    return TERM.tigetnum(capname)


def tigetstr(capname):
    """
    Reimplementation of :py:func:`curses.tigetstr`
    """

    if TERM is None:
        raise error('Must call setupterm() first')
    return TERM.tigetstr(capname)
