from compressor.conf import settings
from compressor.base import Compressor, SOURCE_HUNK, SOURCE_FILE


class JsCompressor(Compressor):

    output_mimetypes = {"text/javascript"}

    def split_contents(self):
        if self.split_content:
            return self.split_content
        self.extra_nodes = []
        for elem in self.parser.js_elems():
            attribs = self.parser.elem_attribs(elem)
            if "src" in attribs:
                basename = self.get_basename(attribs["src"])
                filename = self.get_filename(basename)
                content = (SOURCE_FILE, filename, basename, elem)
            else:
                content = (SOURCE_HUNK, self.parser.elem_content(elem), None, elem)
            self.split_content.append(content)
            if "async" in attribs:
                extra = " async"
            elif "defer" in attribs:
                extra = " defer"
            else:
                extra = ""
            # Append to the previous node if it had the same attribute
            append_to_previous = self.extra_nodes and self.extra_nodes[-1][0] == extra
            if append_to_previous and settings.COMPRESS_ENABLED:
                self.extra_nodes[-1][1].split_content.append(content)
            else:
                node = self.copy(content=self.parser.elem_str(elem))
                node.split_content.append(content)
                self.extra_nodes.append((extra, node))
        return self.split_content

    def output(self, *args, **kwargs):
        if (
            settings.COMPRESS_ENABLED
            or settings.COMPRESS_PRECOMPILERS
            or kwargs.get("forced", False)
        ):
            self.split_contents()
            if hasattr(self, "extra_nodes"):
                ret = []
                for extra, subnode in self.extra_nodes:
                    subnode.extra_context.update({"extra": extra})
                    ret.append(subnode.output(*args, **kwargs))
                return "\n".join(ret)
        return super().output(*args, **kwargs)

    def filter_input(self, forced=False):
        """
        Passes each hunk (file or code) to the 'input' methods
        of the compressor filters.
        """
        content = []
        for hunk in self.hunks(forced):
            # If a file ends with a function call, say, console.log()
            # but doesn't have a semicolon, and the next file starts with
            # a (, the individual files are ok, but when combined you get an
            # error like TypeError...
            # Forcing a semicolon in between fixes it.
            if settings.COMPRESS_ENABLED or forced:
                hunk += ";"
            content.append(hunk)
        return content
