"""This module contains classes - NamedFileInTemporaryDirectory, TemporaryWorkingDirectory.

These classes add extra features such as creating a named file in temporary directory and
creating a context manager for the working directory which is also temporary.
"""

import os as _os
from io import BufferedWriter
from pathlib import Path
from tempfile import TemporaryDirectory
from types import TracebackType
from typing import Optional, Type


class NamedFileInTemporaryDirectory:
    def __init__(self, filename: str, mode: str, bufsize: int=-1, add_to_syspath: bool=False, **kwds):
        """
        Open a file named `filename` in a temporary directory.

        This context manager is preferred over `NamedTemporaryFile` in
        stdlib `tempfile` when one needs to reopen the file.

        Arguments `mode` and `bufsize` are passed to `open`.
        Rest of the arguments are passed to `TemporaryDirectory`.

        """
        self._tmpdir = TemporaryDirectory(**kwds)
        path = Path(self._tmpdir.name) / filename
        encoding = None if "b" in mode else "utf-8"
        self.file = open(path, mode, bufsize, encoding=encoding)

    def cleanup(self):
        self.file.close()
        self._tmpdir.cleanup()

    __del__ = cleanup

    def __enter__(self) -> BufferedWriter:
        return self.file

    def __exit__(self, type: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[TracebackType]):
        self.cleanup()


class TemporaryWorkingDirectory(TemporaryDirectory):
    """
    Creates a temporary directory and sets the cwd to that directory.
    Automatically reverts to previous cwd upon cleanup.
    Usage example:

        with TemporaryWorkingDirectory() as tmpdir:
            ...
    """

    def __enter__(self) -> str:
        self.old_wd = Path.cwd()
        _os.chdir(self.name)
        return super(TemporaryWorkingDirectory, self).__enter__()

    def __exit__(self, exc: Optional[Type[BaseException]], value: Optional[BaseException], tb: Optional[TracebackType]) -> None:
        _os.chdir(self.old_wd)
        return super(TemporaryWorkingDirectory, self).__exit__(exc, value, tb)
