karo 0.1.2

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

use crate::workbook::DocProperties;
use crate::{Result, XmlWritable, XmlWriter};
use chrono::{DateTime, Utc};
use indexmap::indexmap;

pub(crate) struct Core<'a> {
    pub properties: &'a DocProperties,
}

impl XmlWritable for Core<'_> {
    fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        let tag = "cp:coreProperties";
        let attrs = indexmap! {
            "xmlns:cp" =>
                "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
        "xmlns:dc" => "http://purl.org/dc/elements/1.1/",
        "xmlns:dcterms" => "http://purl.org/dc/terms/",
            "xmlns:dcmitype" => "http://purl.org/dc/dcmitype/",
            "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
        };
        w.start_tag_with_attrs(tag, attrs)?;

        self.write_dc_title(w)?;
        self.write_dc_subject(w)?;
        self.write_dc_creator(w)?;
        self.write_cp_keywords(w)?;
        self.write_dc_description(w)?;
        self.write_cp_last_modified_by(w)?;
        self.write_dcterms_created(w)?;
        self.write_dcterms_modified(w)?;
        self.write_cp_category(w)?;
        self.write_cp_content_status(w)?;

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

impl Core<'_> {
    fn write_if_not_empty<W: XmlWriter>(
        w: &mut W,
        tag: &str,
        string: &str,
    ) -> Result<()> {
        if !string.is_empty() {
            w.tag_with_text(tag, string)?;
        }
        Ok(())
    }

    fn write_dc_title<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        Self::write_if_not_empty(w, "dc:title", &self.properties.title)
    }

    fn write_dc_subject<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        Self::write_if_not_empty(w, "dc:subject", &self.properties.subject)
    }

    fn write_dc_creator<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        w.tag_with_text("dc:creator", &self.properties.author)
    }

    fn write_cp_keywords<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        Self::write_if_not_empty(
            w,
            "cp:keywords",
            &self.properties.keywords,
        )
    }

    fn write_dc_description<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        Self::write_if_not_empty(
            w,
            "dc:description",
            &self.properties.comments,
        )
    }

    fn write_cp_last_modified_by<W: XmlWriter>(
        &self,
        w: &mut W,
    ) -> Result<()> {
        w.tag_with_text("cp:lastModifiedBy", &self.properties.author)
    }

    fn write_dcterms_created<W: XmlWriter>(
        &self,
        w: &mut W,
    ) -> Result<()> {
        let tag = "dcterms:created";
        let attrs = indexmap! {"xsi:type" => "dcterms:W3CDTF"};
        let text = self
            .properties
            .created
            .clone()
            .unwrap_or_else(Utc::now)
            .formatted();
        w.tag_with_attrs_and_text(tag, attrs, &text)
    }

    fn write_dcterms_modified<W: XmlWriter>(
        &self,
        w: &mut W,
    ) -> Result<()> {
        let tag = "dcterms:modified";
        let attrs = indexmap! {"xsi:type" => "dcterms:W3CDTF"};
        let text = self
            .properties
            .created
            .clone()
            .unwrap_or_else(Utc::now)
            .formatted();
        w.tag_with_attrs_and_text(tag, attrs, &text)
    }

    fn write_cp_category<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        Self::write_if_not_empty(
            w,
            "cp:category",
            &self.properties.category,
        )
    }

    fn write_cp_content_status<W: XmlWriter>(
        &self,
        w: &mut W,
    ) -> Result<()> {
        Self::write_if_not_empty(
            w,
            "cp:contentStatus",
            &self.properties.status,
        )
    }
}

trait Formatted {
    fn formatted(&self) -> String;
}

impl Formatted for DateTime<Utc> {
    fn formatted(&self) -> String {
        self.format("%Y-%m-%dT%H:%M:%SZ").to_string()
    }
}