# -*- coding: utf-8 -*-
# Hah, don't you love the pervasiveness of Emacs?

"""
This module is the XML creator.
"""

from xml.dom.minidom import Document

import re


class MurrayXMLCreator:

    def __init__(self, vader):
        """Creates a minidom Document doc and a reference to its
        father vader."""
        self.doc = Document()
        self.vader = vader

    def createStream(self, connectionID):
        """Hardcoded XML declaration and <stream:stream> tag because
        as the good DOM implementation that xml.dom.minidom is it
        would output well formed XML, i.e. <stream:stream/> which
        would effectively end the communication..."""
        
        return "<?xml version='1.0' ?>\n<stream:stream id='" + connectionID + "' from='localhost' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>\n"
    
    def destroyStream(self):
        """End the communication by sending the closing
        <stream:stream> tag."""
        
        return "</stream:stream>\n"

    def deliverMessage(self, sender, type, message):
        """FIXME(HTML? parameter?)"""

        msg = self.doc.createElement("message")

        msg.setAttribute("from", sender)
        msg.setAttribute("type", type)

        return self.msg.toxml() + "\n"

    def registrationRequirements(self, id):
        """Returns the registration requirements, which look like
        this:
        
        <iq type='result'>
          <query xmlns='jabber:iq:register'>
            <instructions>
              Please choose a username and a password to register with the Murray network
            </instructions>
            <name/>
            <email/>
            <username/>
            <password/>
          </query>
        </iq>"""

        iq = self.doc.createElement("iq")

        iq.setAttribute("type", "result")
        if id is not None: iq.setAttribute("id", id)

        query = self.doc.createElement("query")
        query.setAttribute("xmlns", "jabber:iq:register")

        instructions = self.doc.createElement("instructions")
        instructionsText = self.doc.createTextNode("Please choose a username and a password to register with the Murray network")
        instructions.appendChild(instructionsText)

        # name = self.doc.createElement("name")
        # email = self.doc.createElement("email")
        username = self.doc.createElement("username")
        password = self.doc.createElement("password")

        query.appendChild(instructions)
        # query.appendChild(name)
        # query.appendChild(email)
        query.appendChild(username)
        query.appendChild(password)

        iq.appendChild(query)

        return iq.toxml() + "\n"

    def registrationResults(self, id, username, password):
        """Returns the registration results, which look like this: <iq
        type='result'/>.  Or, if either of the supplied username or
        password is empty/does not match the requirements an error
        message."""

        iq = self.doc.createElement("iq")
        iq.setAttribute("type", "result")
        if id is not None: iq.setAttribute("id", id)
            
        return iq.toxml() + "\n"


    def authenticationInfo(self, id, unam):
        """FIXME()"""
        iq = self.doc.createElement("iq")
        iq.setAttribute("type", "result")
        if id is not None: iq.setAttribute("id", id)

        query = self.doc.createElement("query")
        query.setAttribute("xmlns", "jabber:iq:auth")

        username = self.doc.createElement("username")
        usernameText = self.doc.createTextNode(unam)
        username.appendChild(usernameText)

        password = self.doc.createElement("password")

        resource = self.doc.createElement("resource")

        query.appendChild(username)
        query.appendChild(password)
        query.appendChild(resource)

        iq.appendChild(query)

        return iq.toxml() + "\n"


    def registrationError(self, id, unam, pw):
        """FIXME()"""
        if pw is None: pw = ""
        if unam is None: unam = ""
            
        query = self.doc.createElement("query")
        query.setAttribute("xmlns", "jabber:iq:register")

        username = self.doc.createElement("username")
        password = self.doc.createElement("password")

        usernameText = self.doc.createTextNode(unam)
        passwordText = self.doc.createTextNode(pw)

        username.appendChild(usernameText)
        password.appendChild(passwordText)

        query.appendChild(username)
        query.appendChild(password)
            
        iq = self.error("406", "Not Acceptable", id, query)

        return iq.toxml() + "\n"


    def authenticationResult(self, authenticationSuccess, id, username, password):
        """FIXME()"""
        if authenticationSuccess:
            iq = self.doc.createElement("iq")
            iq.setAttribute("type", "result")
            if id is not None: iq.setAttribute("id", id)

        else:
            iq = self.error("401", "Not authorized", id, None)

        return iq.toxml() + "\n"
                

    def error(self, num, text, id, query):
        """FIXME()"""
        
        # <iq type='error'>
        #   <query xmlns='jabber:iq:register'>
        #     <username>dj</username>
        #     <password>secret</password>
        #   </query>
        #   <error code='409'>Username Not Available</error>
        # </iq>


        # FIXME(need to add the query)
        iq = self.doc.createElement("iq")
        iq.setAttribute("type", "error")
        if id is not None: iq.setAttribute("id", id)

        error = self.doc.createElement("error")
        error.setAttribute("code", num)
        errorText = self.doc.createTextNode(text)
        error.appendChild(errorText)

        if not query is None: iq.appendChild(query)
        iq.appendChild(error)

        return iq

    def roster(self, id, roster):
        """<iq xmlns='jabber:client' id='foo' type='result'>
             <query xmlns='jabber:iq:roster'>
               <item jid='shiels@jabber.org' subscription='both' name='Robert'>
                 <group>Friends</group>
               </item>
               <item jid='sabine@pipetree.com' subscription='to' name='Sabine'>
                 <group>Friends</group>
               </item>
               <item jid='jim@company-a.com' subscription='from' name='Jim'>
                 <group>Work</group>
               </item>
               <item jid='jim@company-b.com' subscription='none' ask='subscribe' name='John'>
                 <group>Work</group>
               </item>
             </query>
           </iq>"""
        
        iq = self.doc.createElement("iq")
        iq.setAttribute("type", "error")
        if id is not None: iq.setAttribute("id", id)

        query = self.doc.createElement("query")
        query.setAttribute("xmlns", "jabber:iq:roster")

        for murray_id, alias in self.vader.contacts.getAll().items():
            item = self.doc.createElement("item")
            item.setAttribute("jid", self.vader.midToJid(murray_id, alias, False))
            item.setAttribute("subscription", "both")
            item.setAttribute("name", alias)

            item.appendChild(__createElementWithTextNode("group", "Murray Network"))

            query.appendChild(item)

        iq.appendChild(query)

        return iq.toxml() + "\n"

    def presence(self, id, type="available", to=None, sender=None, 
    show=None, status=None, priority=None):
        """Create a presence according to the passed parameters.  At
        the moment it only creates an available or a subscribed
        stanza."""

        presence = self.doc.createElement("presence")
        presence.setAttribute("id", id)
        presence.setAttribute("type", type)
        presence.setAttribute("from", sender)

        if type == "available":
            """If the status is available create show, status and
            priority subelement if necessary and applicable."""

            if not show is None:
                presence.appendChild(__createElementWithTextNode("show", show))
                
            if not status is None:
                presence.appendChild(__createElementWithTextNode("status", status))

            if not priority is None:
                presence.appendChild(__createElementWithTextNode("priority", priority))

        # FIXME()
        elif type == "subscribed":
            pass
            
        return presence.toxml() + "\n"

    def message(self, id, type="normal", to=None, sender=None, body=None, subject=None, thread=None, error=None):
        """Construct a message"""

        message = self.doc.createElement("message")
        message.setAttribute("id", id)
        message.setAttribute("type", type)
        message.setAttribute("from", sender)

        if not body is None:
            message.appendChild(__createElementWithTextNode("body", body))
            
        if not subject is None:
            message.appendChild(__createElementWithTextNode("subject", subject))

        if not thread is None:
            message.appendChild(__createElementWithTextNode("thread", thread))

        if type == "error":
            if not error is None:
                message.appendChild(__createElementWithTextNode("error", error))


        return message.toxml() + "\n"

    def __createElementWithTextNode(self, element, text):
        """Creates an element and a coresponding text node."""

        e = self.doc.createElement(element)
        eText = self.doc.createTextNode(text)
        e.appendChild(eText)

        return e
