"""Module logging

Functionality for logging in pyzo.

"""

import os
import sys
import time
import pyzo

# todo: enable logging to a file?

# Define prompts
try:
    sys.ps1  # noqa: B018
except AttributeError:
    sys.ps1 = ">>> "
try:
    sys.ps2  # noqa: B018
except AttributeError:
    sys.ps2 = "... "


class DummyStd:
    """For when std is not available."""

    def __init__(self):
        self._closed = False

    def write(self, text):
        pass

    def encoding(self):
        return "utf-8"

    @property
    def closed(self):
        return self._closed

    def close(self):
        self._closed = False

    def flush(self):
        pass


original_print = print


def print(*args, **kwargs):
    ts = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    preamble = ts + ":"
    if kwargs.get("sep", " ") != " ":
        preamble += " "
    original_print(preamble, *args, **kwargs)


def splitConsole(stdoutFun=None, stderrFun=None):
    """Splits the stdout and stderr streams.

    On each call to their write methods, in addition to the original
    write method being called, will call the given functions.
    Returns the history of the console (combined stdout and stderr).
    Used by the logger shell.
    """

    # Split stdout and stderr
    sys.stdout = OutputStreamSplitter(sys.stdout)
    sys.stderr = OutputStreamSplitter(sys.stderr)

    # Make them share their history
    sys.stderr._history = sys.stdout._history

    # Set defer functions
    if stdoutFun:
        sys.stdout._deferFunction = stdoutFun
    if stderrFun:
        sys.stderr._deferFunction = stderrFun

    # Return history
    return "".join(sys.stdout._history)


class OutputStreamSplitter:
    """This class is used to replace stdout and stderr output
    streams. It defers the stream to the original and to
    a function that can be registered.
    Used by the logger shell.
    """

    def __init__(self, fileObject):
        # Init, copy properties if it was already a splitter
        if isinstance(fileObject, OutputStreamSplitter):
            self._original = fileObject._original
            self._history = fileObject._history
            self._deferFunction = fileObject._deferFunction
        else:
            self._original = fileObject
            self._history = []
            self._deferFunction = self.dummyDeferFunction

        # Replace original with a dummy if None
        if self._original is None:
            self._original = DummyStd()

    def dummyDeferFunction(self, text):
        pass

    def write(self, text):
        """Write method."""
        self._original.write(text)
        self._history.append(text)
        if os.getenv("PYZO_LOG", ""):
            with open(os.getenv("PYZO_LOG"), "at") as f:
                f.write(text)
        try:
            self._deferFunction(text)
        except Exception:
            pass  # self._original.write("error writing to deferred stream")
        # Show in statusbar
        if pyzo.config.view.showStatusbar and len(text) > 1:
            if pyzo.main:
                pyzo.main.statusBar().showMessage(text, 5000)

    def flush(self):
        return self._original.flush()

    @property
    def closed(self):
        return self._original.closed

    def close(self):
        return self._original.close()

    def encoding(self):
        return self._original.encoding()


# Split now, with no defering
splitConsole()
