karo 0.1.2

Spreadsheet export
Documentation
#[cfg(test)]
mod tests;

use crate::workbook::DocProperties;
use crate::{Result, XmlWritable, XmlWriter};
use indexmap::{indexmap, IndexMap, IndexSet};

pub(crate) struct App<'a> {
    pub heading_pairs: IndexMap<String, String>,
    pub part_names: IndexSet<String>,
    pub properties: &'a DocProperties,
}

impl XmlWritable for App<'_> {
    fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        let attrs = indexmap! {
            "xmlns" => "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",
            "xmlns:vt" => "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes",
        };

        let tag = "Properties";

        w.start_tag_with_attrs(tag, attrs)?;

        self.write_application(w)?;
        self.write_doc_security(w)?;
        self.write_scale_crop(w)?;
        self.write_heading_pairs(w)?;
        self.write_titles_of_parts(w)?;
        self.write_manager(w)?;
        self.write_company(w)?;
        self.write_links_up_to_date(w)?;
        self.write_shared_doc(w)?;
        self.write_hyperlink_base(w)?;
        self.write_hyperlinks_changed(w)?;
        self.write_app_version(w)?;

        w.end_tag(tag)?;
        Ok(())
    }
}

impl App<'_> {
    fn write_application<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        w.tag_with_text("Application", "Microsoft Excel")
    }

    fn write_doc_security<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        w.tag_with_text("DocSecurity", "0")
    }

    fn write_scale_crop<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        w.tag_with_text("ScaleCrop", "false")
    }

    fn write_heading_pairs<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        let tag = "HeadingPairs";
        w.start_tag(tag)?;
        self.write_vt_vector_heading_pairs(w)?;
        w.end_tag(tag)?;
        Ok(())
    }

    fn write_vt_vector_heading_pairs<W: XmlWriter>(
        &self,
        w: &mut W,
    ) -> Result<()> {
        let tag = "vt:vector";
        let attrs = indexmap! {
            "size" => format!("{}", self.heading_pairs.len() * 2),
            "baseType" => "variant".to_string(),
        };
        w.start_tag_with_attrs(tag, attrs)?;

        for (key, value) in self.heading_pairs.iter() {
            self.write_vt_variant(w, key, value)?;
        }

        w.end_tag(tag)?;
        Ok(())
    }

    fn write_vt_variant<W: XmlWriter>(
        &self,
        w: &mut W,
        key: &str,
        value: &str,
    ) -> Result<()> {
        let tag = "vt:variant";

        {
            w.start_tag(tag)?;
            self.write_vt_lpstr(w, key)?;
            w.end_tag(tag)?;
        }
        {
            w.start_tag(tag)?;
            self.write_vt_i4(w, value)?;
            w.end_tag(tag)?;
        }

        Ok(())
    }

    fn write_vt_lpstr<W: XmlWriter>(
        &self,
        w: &mut W,
        string: &str,
    ) -> Result<()> {
        w.tag_with_text("vt:lpstr", string)
    }

    fn write_vt_i4<W: XmlWriter>(
        &self,
        w: &mut W,
        string: &str,
    ) -> Result<()> {
        w.tag_with_text("vt:i4", string)
    }

    fn write_titles_of_parts<W: XmlWriter>(
        &self,
        w: &mut W,
    ) -> Result<()> {
        let tag = "TitlesOfParts";
        w.start_tag(tag)?;
        self.write_vt_vector_lpstr_named_parts(w)?;
        w.end_tag(tag)?;
        Ok(())
    }

    fn write_vt_vector_lpstr_named_parts<W: XmlWriter>(
        &self,
        w: &mut W,
    ) -> Result<()> {
        let attrs = indexmap! {
            "size" => format!("{}", self.part_names.len()),
            "baseType" => "lpstr".to_string(),
        };
        let tag = "vt:vector";
        w.start_tag_with_attrs(tag, attrs)?;
        for name in self.part_names.iter() {
            self.write_vt_lpstr(w, name)?;
        }
        w.end_tag(tag)?;
        Ok(())
    }

    fn write_manager<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        if !self.properties.manager.is_empty() {
            w.tag_with_text("manager", &self.properties.manager)?;
        }
        Ok(())
    }

    fn write_company<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        w.tag_with_text("Company", &self.properties.company)
    }

    fn write_links_up_to_date<W: XmlWriter>(
        &self,
        w: &mut W,
    ) -> Result<()> {
        w.tag_with_text("LinksUpToDate", "false")
    }

    fn write_shared_doc<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        w.tag_with_text("SharedDoc", "false")
    }

    fn write_hyperlink_base<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        if !self.properties.hyperlink_base.is_empty() {
            w.tag_with_text(
                "HyperlinkBase",
                &self.properties.hyperlink_base,
            )?;
        }
        Ok(())
    }

    fn write_hyperlinks_changed<W: XmlWriter>(
        &self,
        w: &mut W,
    ) -> Result<()> {
        w.tag_with_text("HyperlinksChanged", "false")
    }

    fn write_app_version<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        w.tag_with_text("AppVersion", "12.0000")
    }
}