karo 0.1.2

Spreadsheet export
Documentation
use crate::{AsPaletteColor, Result, XmlWritable, XmlWriter};
use indexmap::{indexmap, IndexSet};
use rgb::RGB8;
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Default, Clone, Debug, Hash, Eq, PartialEq)]
pub struct Fill {
    pub fg_color: Option<RGB8>,
    pub bg_color: Option<RGB8>,
    pub pattern: Option<Pattern>,
}

#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub enum Pattern {
    Solid,
    MediumGray,
    DarkGray,
    LightGray,
    DarkHorizontal,
    DarkVertical,
    DarkDown,
    DarkUp,
    DarkGrid,
    DarkTrellis,
    LightHorizontal,
    LightVertical,
    LightDown,
    LightUp,
    LightGrid,
    LightTrellis,
    Gray125,
    Gray0625,
}

impl Pattern {
    fn xml_string(&self) -> &'static str {
        match self {
            Pattern::Solid => "solid",
            Pattern::MediumGray => "mediumGray",
            Pattern::DarkGray => "darkGray",
            Pattern::LightGray => "lightGray",
            Pattern::DarkHorizontal => "darkHorizontal",
            Pattern::DarkVertical => "darkVertical",
            Pattern::DarkDown => "darkDown",
            Pattern::DarkUp => "darkUp",
            Pattern::DarkGrid => "darkGrid",
            Pattern::DarkTrellis => "darkTrellis",
            Pattern::LightHorizontal => "lightHorizontal",
            Pattern::LightVertical => "lightVertical",
            Pattern::LightDown => "lightDown",
            Pattern::LightUp => "lightUp",
            Pattern::LightGrid => "lightGrid",
            Pattern::LightTrellis => "lightTrellis",
            Pattern::Gray125 => "gray125",
            Pattern::Gray0625 => "gray0625",
        }
    }
}

#[derive(Default, Debug)]
struct Inner {
    fills: IndexSet<Fill>,
}

#[derive(Clone, Debug)]
pub(crate) struct Fills {
    inner: Rc<RefCell<Inner>>,
}

impl Default for Fills {
    fn default() -> Self {
        let mut inner = Inner::default();
        inner.fills.insert(Fill::default());
        inner.fills.insert(Fill {
            fg_color: None,
            bg_color: None,
            pattern: Some(Pattern::Gray125),
        });
        Fills {
            inner: Rc::new(RefCell::new(inner)),
        }
    }
}

impl Fills {
    pub fn create_or_get_index(
        &mut self,
        fill: Option<&Fill>,
    ) -> Option<usize> {
        let mut inner = self.inner.borrow_mut();
        fill.map(|f| inner.fills.insert_full(f.clone()).0)
    }
}

impl XmlWritable for Fills {
    fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        self.inner.borrow().write_xml(w)
    }
}

impl XmlWritable for Inner {
    fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        if !self.fills.is_empty() {
            let tag = "fills";
            let attrs = indexmap! {
                "count" => format!("{}", self.fills.len()),
            };
            w.start_tag_with_attrs(tag, attrs)?;
            for font in self.fills.iter() {
                font.write_xml(w)?;
            }
            w.end_tag(tag)?;
        }
        Ok(())
    }
}

impl XmlWritable for Fill {
    fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        let tag = "fill";
        w.start_tag(tag)?;
        self.write_pattern_fill(w)?;
        w.end_tag(tag)?;
        Ok(())
    }
}

impl Fill {
    fn write_pattern_fill<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
        let tag = "patternFill";
        let pattern = self
            .pattern
            .map(|p| p.xml_string())
            .unwrap_or_else(|| "none");
        let attrs = indexmap! {
            "patternType" => pattern
        };

        match (self.bg_color, self.fg_color) {
            (Some(bg_color), Some(fg_color)) => {
                w.start_tag_with_attrs(tag, attrs)?;
                Self::write_color(w, "bgColor", bg_color)?;
                Self::write_color(w, "fgColor", fg_color)?;
                w.end_tag(tag)?;
            }
            (Some(bg_color), None) => {
                w.start_tag_with_attrs(tag, attrs)?;
                Self::write_color(w, "bgColor", bg_color)?;
                w.end_tag(tag)?;
            }
            (None, Some(fg_color)) => {
                w.start_tag_with_attrs(tag, attrs)?;
                Self::write_color(w, "fgColor", fg_color)?;
                w.end_tag(tag)?;
            }
            (None, None) => {
                w.empty_tag_with_attrs(tag, attrs)?;
            }
        }

        Ok(())
    }

    fn write_color<W: XmlWriter>(
        w: &mut W,
        tag: &str,
        color: RGB8,
    ) -> Result<()> {
        let attrs = indexmap! { "rgb" => color.as_palette_color(), };
        w.empty_tag_with_attrs(tag, attrs)
    }
}