"""Module containing the :class:`pirec.artefacts.Artefact` base class and subclasses."""

from __future__ import absolute_import
import os.path
from .utils import file_sha1sum


class Artefact(object):
    """Base class for Pirec artefacts (files consumed by and generated by processes).

    Args:
        filename (str): The filename of the artefact.
        extension (str): The extension of the artefact's filename.

    Keyword args:
        exists (boolean): If true raise an exception if the file does not exist.

    Raises:
        :class:`exceptions.ValueError`: If ``filename`` does not end with ``extension``.
        :class:`exceptions.IOError`: If ``filename`` does not exist.
    """

    def __init__(self, filename, extension, exists=True):
        """Initialize the artefact."""
        if not filename.endswith(extension):
            raise ValueError('Extension is not {0!r}'.format(extension))
        if exists and not os.path.exists(filename):
            raise IOError('No such file: {0!r}'.format(filename))
        self._filename = filename
        self._ext_length = len(extension)
        self._abspath = os.path.abspath(filename)

    def checksum(self):
        """Calculate the SHA-1 checksum of the file."""
        return file_sha1sum(self.filename)

    def exists(self):
        """Return ``True`` if :attr:`Artefact.filename` exists."""
        return os.path.exists(self.filename)

    @property
    def abspath(self):
        """The file's absolute path."""
        return self._abspath

    @property
    def basename(self):
        """The filename without the extension and directory components.

        .. code:: python

            >> Artefact('/dir/file.txt').basename
            '/dir/file'
        """
        return self._filename[:-self._ext_length]

    @property
    def justname(self):
        """The filename without the extension and directory components.

        .. code:: python

            >> Artefact('/dir/file.txt').justname
            'file'
        """
        return os.path.basename(self._filename)[:-self._ext_length]

    @property
    def dirname(self):
        """Return the directory component of the filename.

        .. code:: python

            >> Artefact('/dir/file.txt').dirname()
            '/dir'
        """
        return os.path.dirname(self._filename)

    def dereference(self):
        """Remove any directory components from the filename.

        .. code:: python

            >> a = Artefact('/dir/file.txt')
            >> a.dereference()
            >> a.filename
            'file.txt'
        """
        self._filename = os.path.basename(self._filename)

    @property
    def filename(self):
        """The artefact's filename."""
        return self._filename

    def __repr__(self):
        return '{0}({1!r})'.format(self.__class__.__name__, self.filename)


class NiiGzImage(Artefact):
    """An artefact for ``.nii.gz`` images.

    Args:
        filename (str): The filename of the artefact.

    Keyword args:
        exists (boolean): If true raise an exception if the file does not exist.
    """

    def __init__(self, filename, exists=True):
        """Initialize the artefact."""
        super(NiiGzImage, self).__init__(filename, '.nii.gz', exists)

    def __repr__(self):
        return '{0}({1!r})'.format(self.__class__.__name__, self.filename)


class TextFile(Artefact):
    """An artefact for ``.txt`` files.

    Args:
        filename (str): The filename of the artefact.

    Keyword args:
        exists (boolean): If true raise an exception if the file does not exist.
    """

    def __init__(self, filename, exists=True):
        """Initialize the artefact."""
        super(TextFile, self).__init__(filename, '.txt', exists=True)

    def __repr__(self):
        return '{0}({1!r})'.format(self.__class__.__name__, self.filename)
