import base64
import xml.sax.saxutils

import gourmand.exporters.exporter as exporter
from gourmand.exporters.xml_exporter import XmlExporter


class rec_to_xml(XmlExporter):
    """A vastly simplified recipe XML exporter.

    The previous XML format was written as a format designed for
    itself (its design predated gourmet). This one is really written
    as a simple way to save, load and exchange Gourmet recipes. As a
    result, the code is much simpler, and the format should be quicker
    to write and more convenient for exchanging single recipes.

    This implementation actually uses the DOM to ensure correctness.
    """

    doc_element = "gourmetDoc"
    doctype_desc = ""
    dtd_path = ""
    ALLOW_PLUGINS_TO_WRITE_NEW_FIELDS = False

    def write_head(self):
        self.rec_el = self.create_element_with_attrs("recipe", {"id": self.r.id})
        self.top_element.appendChild(self.rec_el)

    def write_attr(self, attr, text):
        self.rec_el.appendChild(self.create_text_element(attr.replace(" ", ""), text))

    def write_text(self, attr, text):
        self.rec_el.appendChild(self.create_text_element(attr.replace(" ", ""), text))

    def write_image(self, image):
        image_el = self.create_element_with_attrs("image", {"format": "jpeg"})
        image_el.appendChild(self.xmlDoc.createCDATASection(base64.b64encode(image).decode()))
        self.rec_el.appendChild(image_el)

    def handle_italic(self, chunk):
        return "&lt;i&gt;" + chunk + "&lt;/i&gt;"

    def handle_bold(self, chunk):
        return "&lt;b&gt;" + chunk + "&lt;/b&gt;"

    def handle_underline(self, chunk):
        return "&lt;u&gt;" + chunk + "&lt;/u&gt;"

    def write_foot(self):
        if self.i_created_this_document:
            self.xmlDoc.writexml(self.ofi, newl="\n", addindent="\t", encoding="UTF-8")

    def write_inghead(self):
        self.inglist_el = self.xmlDoc.createElement("ingredient-list")
        self.top_inglist = self.inglist_el  # because groups will let us nest...
        self.rec_el.appendChild(self.inglist_el)

    def write_ingref(self, amount=1, unit=None, item=None, refid=None, optional=False):
        self.inglist_el.appendChild(self.create_text_element("ingref", item, {"refid": str(refid), "amount": amount}))

    def write_ing(self, amount=1, unit=None, item=None, key=None, optional=False):
        if optional:
            ing_el = self.create_element_with_attrs("ingredient", {"optional": "yes"})
        else:
            ing_el = self.create_element_with_attrs("ingredient", {})
        self.inglist_el.appendChild(ing_el)
        if amount:
            ing_el.appendChild(self.create_text_element("amount", amount))
        if unit:
            ing_el.appendChild(self.create_text_element("unit", unit))
        if item:
            ing_el.appendChild(self.create_text_element("item", item))
        if key:
            ing_el.appendChild(self.create_text_element("key", key))

    def write_grouphead(self, name):
        group_el = self.xmlDoc.createElement("inggroup")
        group_el.appendChild(self.create_text_element("groupname", name))
        self.inglist_el = group_el

    def write_groupfoot(self):
        self.top_inglist.appendChild(self.inglist_el)
        self.inglist_el = self.top_inglist


class recipe_table_to_xml(exporter.ExporterMultirec, XmlExporter):
    doc_element = "gourmetDoc"
    doctype_desc = ""
    dtd_path = ""

    def __init__(self, rd, recipe_table, out, one_file=True, change_units=False, mult=1):
        self.create_xmldoc()
        exporter.ExporterMultirec.__init__(
            self,
            rd,
            recipe_table,
            out,
            one_file=True,
            ext="xml",
            exporter=rec_to_xml,
            exporter_kwargs={
                "change_units": change_units,
                "mult": mult,
                "xmlDoc": self.xmlDoc,
                # This order is now in our DTD so we'd
                # better make it solid.
                "attr_order": (
                    "title",
                    "category",
                    "cuisine",
                    "source",
                    "link",
                    "rating",
                    "preptime",
                    "cooktime",
                    "yields",
                ),
                "order": ["attr", "image", "ings", "text"],
            },
        )

    def write_footer(self, *args):
        self.xmlDoc.writexml(self.ofi, newl="\n", addindent="\t", encoding="UTF-8")


def quoteattr(str):
    return xml.sax.saxutils.quoteattr(xml.sax.saxutils.escape(str))
