from roundup.cgi.actions import Action
from email.message import Message
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.encoders import encode_base64

class MboxAction(Action):
    ## These get set in handle() by a dirty hack (see "setattr").
    activity = None             # issue / patch
    actor = None                # issue / patch
    assignedto = None           # issue / patch (used)
    creation = None             # issue / patch
    creator = None              # issue / patch
    darcswatchurl = None        # patch
    messages = None             # issue / patch (used)
    nosy = None                 # issue / patch (used)
    priority = None             # issue (used)
    status = None               # issue / patch (used)
    title = None                # issue / patch (used)
    topic = None                # issue (used)

    def handle(self):
        if self.classname != "issue" and self.classname != "patch":
            raise ValueError, "Only an issue or patch can become an mbox."
        if self.nodeid is None:
            raise ValueError, "Cannot iterate over multiple issues at once."

        ## This saves typing later.  It's naughty, because AFAICT
        ## self.db.issue.get() does some extra magic that isn't
        ## reproduced here.
        for (key, val) in self.db.getnode (self.classname, self.nodeid).items ():
            setattr (self, key, val)

        if not self.messages:
            raise ValueError, "Can't make an mbox without messages."
        self.client.additional_headers ["Content-Type"] = "application/mbox"
        self.client.header ()
        if self.client.env["REQUEST_METHOD"] == "HEAD":
            return None      # Stop now, as the mbox wasn't requested.

        mbox = []               # The accumulator.
        for message_id in self.messages:
            message = MIMEText (self.db.msg.get (message_id, "content"),
                                "plain", "utf-8") # hard-code as UTF-8 for now.
            files = self.db.msg.get (message_id, "files")
            if files:
                message_body = message
                message_body ["Content-Disposition"] = "inline"
                message = MIMEMultipart ()
                message.attach (message_body)
                for it in files:
                    attachment = Message ()
                    attachment.add_header ("Content-Disposition", "attachment",
                                           filename=self.db.file.get (it, "name"))
                    attachment ["Content-Type"] = self.db.file.get (it, "type")
                    attachment.set_payload (self.db.file.get (it, "content"))
                    encode_base64 (attachment) # bloated, but reliable.
                    message.attach (attachment)

            message ["Date"] = self.db.msg.get (message_id, "date").pretty ("%a, %d %b %Y %H:%M:%S +0000")
            message ["From"] = self.address (self.db.msg.get (message_id, "author"))
            it = self.db.msg.get (message_id, "recipients")
            if it: message ["CC"] = ", ".join ([self.address (recipient) for recipient in it])
            message ["Message-ID"] = self.db.msg.get(message_id, "messageid") or None
            message ["In-Reply-To"] = self.db.msg.get(message_id, "inreplyto") or None

            ## The remaining header fields are identical for all
            ## messages in the mbox, at least until such time as I
            ## work out how to reconcile the "journal" with the list
            ## of messages.
            message ["Reply-To"] = self.db.config.TRACKER_EMAIL
            message ["Subject"] = "[" + self.classname + self.nodeid + "] " + self.title
            if self.priority:
                message ["X-Roundup-Priority"] = self.db.priority.get (self.priority, "name")
            if self.status:
                message ["X-Roundup-Status"] = self.db.status.get (self.status, "name")
            if self.assignedto:
                message ["X-Roundup-Assigned-To"] = self.db.user.get (self.assignedto, "username")
            if self.nosy:
                message ["X-Roundup-Nosy-List"] = ", ".join([self.db.user.get (nose, "username")
                                                             for nose in self.nosy])
            if self.topic:
                message ["X-Roundup-Topics"] = ", ".join([self.db.keyword.get (topic, "name")
                                                             for topic in self.topic])

            mbox.append (message)

        return "\n".join ([str (message) for message in mbox])

    def address(self, x):
        get = self.db.user.get
        return (get(x, "realname") or get(x, "username")) + ":;"

def init(tracker):
    tracker.registerAction("mbox", MboxAction)
