#!/usr/bin/python3 -s
import os
import shutil
from l3tlib import CommandError
from l3tlib.command import L3tCommand


class GetAttachment(L3tCommand):

    descr = "Downloads attachments from a bug"
    usage = "%prog [-b BUG | -a ATTACHID]"

    def init_parser(self, parser):
        super(GetAttachment, self).init_parser(parser)
        parser.add_option("-a", "--attachment", type="int", default=None,
                          help="Get attachment")
        parser.add_option("-d", "--dest", default=".",
                          help="Save file into DEST directory")
        parser.add_option("-b", "--bug", type="int", default=None,
                          help="Download all attachments from BUG")
        parser.add_option("-F", "--force-overwrite", default=False,
                          action="store_true",
                          help="Overwrite existing files")

    def parse_args(self, parser, args):
        opts, values = super(GetAttachment, self).parse_args(parser, args)
        if values:
            parser.error("no extra arguments accepted")
        return opts, values

    def _prepare_dest(self, path):
        if not os.path.exists(path):
            try:
                os.makedirs(path)
            except EnvironmentError as e:
                raise CommandError("failed to create %s: %s" %
                                   (path, e))

    def _should_skip(self, path, size):
        skip = False
        if os.path.exists(path):
            try:
                stat = os.stat(path)
            except EnvironmentError as e:
                raise CommandError("failed to check file %s: %s" % (path,
                                                                    e))
            skip = stat.st_size == size and not self.opts.force_overwrite
        return skip

    @staticmethod
    def _get_dest_name(att_id, name):
        name = att_id + "_" + name if name else att_id
        name = name.replace(os.path.sep, "")
        return name

    def _get_attachments_from_bug(self, bug_id):
        bug = self.l3t.get_bug(bug_id=self.opts.bug)
        to_download = []  # [(id, dest, size), ...]
        obsolete = sum(att["isobsolete"] for att in bug.attachments)
        obsolete_part = "(%d obsolete)" % (obsolete) if obsolete else ""
        print("%s attachments found%s" % (len(bug.attachments), obsolete_part))
        for att in bug.attachments:
            name = self._get_dest_name(att["attachid"], att["filename"])
            if att["isobsolete"]:
                print("Skipping obsolete attachment %s" % \
                    (att["filename"]))
                continue
            dest = os.path.join(self.opts.dest, name)
            try:
                size = int(att["size"])
            except ValueError:
                size = 0
            if self._should_skip(dest, size):
                print("Skipping existing %s (%s KiB)" % (dest, size / 1024))
                continue
            to_download.append(str(att["attachid"]))
        return to_download

    def run(self):
        if self.opts.attachment:
            to_download = [str(self.opts.attachment)]
        else:
            to_download = self._get_attachments_from_bug(self.opts.bug)
        for att_id in to_download:
            bz_name, size, data = self.l3t.get_attachment(att_id)
            name = self._get_dest_name(att_id, bz_name)
            dest = os.path.join(self.opts.dest, name)
            self._prepare_dest(self.opts.dest)
            print("Downloading to %s (%s KiB)" % (dest, size / 1024))
            try:
                with open(dest, "w") as f:
                    shutil.copyfileobj(data, f)
            except EnvironmentError as e:
                raise CommandError("failed to write %s: %s" % (dest, e))


GetAttachment().main()
