# -------------------------------------------------------------
# file.py - generates new filenames
# June-July 2018 - Hrutvik Kanabar
# -------------------------------------------------------------

"""
Handles the naming of files.

Provides classes to encapsulate data file names, display file names,
and temporary file names.

"""

__all__ = (
    'DataFileName',
    'TempFileName'
)

import logging
import os
from datetime import datetime

from marple.common import paths

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)


class _FileName:
    """
    Base class for a file name.

    Files are of the format <path>/<date>_<option>.<extension> and reside in
    paths.OUT_DIR by default.
    However they can be given a custom name and stored in paths.OUT_DIR,
    or alternatively given both a custom name and a path.

    """
    def __init__(self, option, extension, given_name=None, path=paths.OUT_DIR):
        """
        Initialise the file name.

        :param option:
            An optional field directly before the '.<extension>' (see above).
        :param extension:
            The extension of the file.
        :param given_name:
            The optional desired name of the file.
        :param path:
            The optional desired path of the file.

        """
        self.datetime = datetime.now()
        self.option = option
        self.extension = extension
        if given_name == "":
            raise FileNotFoundError("Cannot have empty file name.")
        elif given_name is None:
            self.given_name = None
            self.path = path
        else:
            dir_name = os.path.dirname(given_name)
            if os.path.isdir(dir_name):
                self.path = dir_name + "/"
                self.given_name = os.path.basename(given_name)
            else:
                self.path = path
                self.given_name = given_name

    def __str__(self):
        """
        Converts the file object to a string, which includes path to the file.

        As described above, file strings are of the format
        <path>/<date>_<option>.<extension> where <path> = paths.OUT_DIR by
        default.
        However, if <given_name> is specified, the file is named
        <given_name> - output is then <path>/<given_name>, where as before
        <path> = paths.OUT_DIR. by default.

        :return:
            The resulting string.

        """
        if self.given_name is None:
            date = self.datetime.strftime("%Y-%m-%d_%H:%M:%S.%f")
            result = self.path + date
            if self.option is None:
                result += "." + self.extension
            else:
                result += "_" + self.option + "." + self.extension
        else:
            result = self.path + self.given_name
        return result

    def __repr__(self):
        """ Give a unique representation of a file object. """
        return str(self.__class__) + "." + self.__str__()


class DataFileName(_FileName):
    """ Class for data file names (generated by the collect module). """
    def __init__(self, given_name=None):
        """
        Initialise a data file name.

        As above in :class:`_FileName`, but there is no option and the extension
        is set to 'marple'. All files are named <date>.marple as a result,
        unless <given_name> is set.

        :param given_name:
            As above in :class:`_Filename`.

        """
        super().__init__(None, "marple", given_name)

    def export_filename(self):
        """
        Export a data file name.

        Write the current data file name to disk in a known temp file, so that
        future marple invocations can read this file to determine the last
        written data.

        """
        with open(paths.VAR_DIR + "filename", "w") as file:
            file.write(str(self))

    @classmethod
    def import_filename(cls):
        """
        Import a data file name.

        Read a filename from disk from a known temp file, so that data from
        the previous marple invocation is easily found.

        :raises FileNotFoundError:
            If the known file cannot be found.

        """
        try:
            with open(paths.VAR_DIR + "filename", "r") as saved_filename:
                return saved_filename.readline().strip()
        except FileNotFoundError:
            logger.error("Unable to find filename helper file in %s",
                         str(paths.VAR_DIR))
            raise


class TempFileName(_FileName):
    """ Class for temporary file names. """
    def __init__(self):
        """
        Initialise a temporary file name.

        As above in :class:`_FileName`, but all files have no option,
        have extension 'tmp' and are in the paths.TMP_DIR directory.
        All files are therefore named <paths.TMP_DIR>/<date>.tmp

        """
        super().__init__(None, "tmp", path=paths.TMP_DIR)
