from .composite_builder import CompositeBuilder
from ..copy import Copy


class SequentialBuilder(CompositeBuilder):
    """A composite builder that runs subbuilders in sequence (i.e. wait for
    one to finish before starting the next)

    Attributes
    ----------
    chain_on_create : bool
        If True (default), chain the parameters and outfilepath of the
        subbuilders to follow each other.
    copy : bool
        If True (default), the last subbuilders will be a Copy build to copy
        the result to the final outfilepath. This only applies if use_cache is
        False, in which case the final generated file is copied from the
        cache directory to the target directory.
    subbuilder_for_outfilename : Optional[:obj:`.builders.Builder`]
        The subbuilder instance to use for generating the outfilepath
        of the SequentialBuilder. Specifying this class name is useful for
        SequentialBuilders that use the filename hash generated by some
        subbuilders, like JinjaRender or SaveTempFile.

    Notes
    -----
    With chain_on_create is enabled, he build filepaths for subbuilders are
    set as follows, with user-supplied paths in parentheses:

    .. code-block:: text

        builder => subbuilder1 (parameters) => outfilepath1
                => subbuilder2 outfilepath2 => outfilepath3
                => subbuilder3 outfilepath3 => outfilepath4
                => outfilepath4 => (outfilepath)
    """

    action = 'sequential build'
    parallel = False

    use_cache = False
    chain_on_creation = True
    copy = True
    subbuilder_for_outfilename = None

    def __init__(self, env, **kwargs):
        super().__init__(env, **kwargs)

        # Make the last subbuilder a copy builder to copy the result of the
        # sub-builders to the final outfilepath.
        # This only applies if other subbuilders are present and the final
        # result needs to be copied to a non-cache directory--i.e. use_cache
        # is False.
        if self.copy and self.subbuilders:  # and not self.use_cache:
            cp_builder = Copy(env, use_cache=self.use_cache)
            self.subbuilders.append(cp_builder)

        # Order the subbuilders, if subbuilders are present
        if self.chain_on_creation and self.subbuilders:
            self.chain_subbuilders()

    def chain_subbuilders(self):
        """Chain the parameters and outfilepath of the subbuilders to follow
        each other"""
        # Set the parameters and outfilepaths
        current_parameters = self.parameters
        for subbuilder in self.subbuilders:
            # For the subbuilders to work together, reset their parameters
            # and outfilepath
            if current_parameters:
                subbuilder.parameters = current_parameters
            subbuilder.outfilepath = None

            # Convert the output of subbuilder into an infilepath for the
            # next subbuilder. Include the other parameters in the input
            # parameters
            outfilepath = subbuilder.outfilepath
            if outfilepath:
                current_parameters = [outfilepath] + subbuilder.not_infilepaths

        # Set the copy builder to point to the final outfilepath
        if isinstance(self.subbuilders[-1], Copy):
            self.subbuilders[-1].outfilepath = self.outfilepath

        # Chain any sequential builder subbuilders
        for subbuilder in self.subbuilders:
            if not hasattr(subbuilder, 'chain_subbuilders'):
                continue
            subbuilder.chain_subbuilders()

    @property
    def outfilepath(self):
        # Use the render builder's outfilepath if None is specified. This is
        # because the render builder's outfilepath is a hash of the input text,
        # which is unique.
        if self._outfilepath is None:
            # By default, use the parent's outfilepath, if no
            # subbuilder_for_outfilename attribute was specified
            outfilepath = CompositeBuilder.outfilepath.fget(self)

            # Otherwise use one from the subbuilders
            subbuilder = self.subbuilder_for_outfilename

            # Replace the outfilepath's filename
            if subbuilder is not None:
                sb_outfilepath = subbuilder.outfilepath
                outfilepath = outfilepath.use_name(sb_outfilepath.name)

            # Replace the extension
            out_ext = self.outfilepath_ext
            if out_ext is not None:
                outfilepath = outfilepath.use_suffix(out_ext)

            self._outfilepath = outfilepath
        return self._outfilepath

    @outfilepath.setter
    def outfilepath(self, value):
        self._outfilepath = value
