use super::DoubleValue;
use super::StringValue;
use super::UInt32Value;
use md5::Digest;
use quick_xml::events::{BytesStart, Event};
use quick_xml::Reader;
use quick_xml::Writer;
use reader::driver::*;
use std::io::Cursor;
use structs::drawing::Theme;
use writer::driver::*;
const INDEXED_COLORS: &[&str] = &[
"FF000000", "FFFFFFFF", "FFFF0000", "FF00FF00", "FF0000FF", "FFFFFF00", "FFFF00FF", "FF00FFFF", "FF800000", "FF008000", "FF000080", "FF808000", "FF800080", "FF008080", "FFC0C0C0", "FF808080", "FF9999FF", "FF993366", "FFFFFFCC", "FFCCFFFF", "FF660066", "FFFF8080", "FF0066CC", "FFCCCCFF", "FF000080", "FFFF00FF", "FFFFFF00", "FF00FFFF", "FF800080", "FF800000", "FF008080", "FF0000FF", "FF00CCFF", "FFCCFFFF", "FFCCFFCC", "FFFFFF99", "FF99CCFF", "FFFF99CC", "FFCC99FF", "FFFFCC99", "FF3366FF", "FF33CCCC", "FF99CC00", "FFFFCC00", "FFFF9900", "FFFF6600", "FF666699", "FF969696", "FF003366", "FF339966", "FF003300", "FF333300", "FF993300", "FF993366", "FF333399", "FF333333", ];
#[derive(Default, Debug, Clone, PartialEq, PartialOrd)]
pub struct Color {
indexed: UInt32Value,
theme_index: UInt32Value,
argb: StringValue,
tint: DoubleValue,
}
impl Color {
pub const NAMED_COLORS: &'static [&'static str] = &[
"Black", "White", "Red", "Green", "Blue", "Yellow", "Magenta", "Cyan",
];
pub const COLOR_BLACK: &'static str = "FF000000";
pub const COLOR_WHITE: &'static str = "FFFFFFFF";
pub const COLOR_RED: &'static str = "FFFF0000";
pub const COLOR_DARKRED: &'static str = "FF800000";
pub const COLOR_BLUE: &'static str = "FF0000FF";
pub const COLOR_DARKBLUE: &'static str = "FF000080";
pub const COLOR_GREEN: &'static str = "FF00FF00";
pub const COLOR_DARKGREEN: &'static str = "FF008000";
pub const COLOR_YELLOW: &'static str = "FFFFFF00";
pub const COLOR_DARKYELLOW: &'static str = "FF808000";
pub fn get_argb(&self) -> &str {
self.argb.get_value()
}
pub fn set_argb<S: Into<String>>(&mut self, value: S) -> &mut Self {
self.indexed.remove_value();
self.theme_index.remove_value();
self.argb.set_value(value);
self
}
pub fn get_indexed(&self) -> &u32 {
self.indexed.get_value()
}
pub fn set_indexed(&mut self, index: u32) -> &mut Self {
self.indexed.set_value(index);
self.theme_index.remove_value();
self.argb
.set_value(match INDEXED_COLORS.get(index as usize - 1) {
Some(v) => v.to_string(),
None => String::from(""),
});
self
}
pub fn get_theme_index(&self) -> &u32 {
self.theme_index.get_value()
}
pub fn set_theme_index(&mut self, index: u32) -> &mut Self {
self.indexed.remove_value();
self.theme_index.set_value(index);
self.argb.remove_value();
self
}
pub(crate) fn set_argb_by_theme(&mut self, theme: &Theme) -> &mut Self {
if self.theme_index.has_value() {
self.argb.set_value(
match theme
.get_theme_elements()
.get_color_scheme()
.get_color_map()
.get(*self.theme_index.get_value() as usize)
{
Some(v) => v.to_string(),
None => String::from(""),
},
);
}
self
}
pub fn get_tint(&self) -> &f64 {
self.tint.get_value()
}
pub fn set_tint(&mut self, value: f64) -> &mut Color {
self.tint.set_value(value);
self
}
pub(crate) fn has_value(&self) -> bool {
self.theme_index.has_value()
|| self.indexed.has_value()
|| self.argb.has_value()
|| self.tint.has_value()
}
pub(crate) fn get_hash_code(&self) -> String {
format!(
"{:x}",
md5::Md5::digest(format!(
"{}{}{}{}",
&self.indexed.get_hash_string(),
&self.theme_index.get_hash_string(),
&self.argb.get_hash_string(),
&self.tint.get_hash_string()
))
)
}
pub(crate) fn set_attributes<R: std::io::BufRead>(
&mut self,
reader: &mut Reader<R>,
e: &BytesStart,
empty_flg: bool,
) {
for a in e.attributes().with_checks(false) {
match a {
Ok(ref attr) if attr.key.0 == b"indexed" => {
self.indexed
.set_value_string(get_attribute_value(attr).unwrap());
}
Ok(ref attr) if attr.key.0 == b"theme" => {
self.theme_index
.set_value_string(get_attribute_value(attr).unwrap());
}
Ok(ref attr) if attr.key.0 == b"rgb" => {
self.argb
.set_value_string(get_attribute_value(attr).unwrap());
}
Ok(ref attr) if attr.key.0 == b"tint" => {
self.tint
.set_value_string(get_attribute_value(attr).unwrap());
}
Ok(_) => {}
Err(_) => {}
}
}
if empty_flg {
return;
}
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::End(ref e)) => match e.name().into_inner() {
b"color" => return,
b"fgColor" => return,
b"bgColor" => return,
b"tabColor" => return,
_ => (),
},
Ok(Event::Eof) => panic!(
"Error not find {} end element",
"color,fgColor,bgColor,tabColor"
),
Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
_ => (),
}
buf.clear();
}
}
pub(crate) fn write_to_color(&self, writer: &mut Writer<Cursor<Vec<u8>>>) {
self.write_to(writer, "color");
}
pub(crate) fn write_to_fg_color(&self, writer: &mut Writer<Cursor<Vec<u8>>>) {
self.write_to(writer, "fgColor");
}
pub(crate) fn write_to_bg_color(&self, writer: &mut Writer<Cursor<Vec<u8>>>) {
self.write_to(writer, "bgColor");
}
pub(crate) fn write_to_tab_color(&self, writer: &mut Writer<Cursor<Vec<u8>>>) {
self.write_to(writer, "tabColor");
}
fn write_to(&self, writer: &mut Writer<Cursor<Vec<u8>>>, tag_name: &str) {
let mut attributes: Vec<(&str, &str)> = Vec::new();
let theme_index = self.theme_index.get_value_string();
let indexed = self.indexed.get_value_string();
if self.theme_index.has_value() {
attributes.push(("theme", &theme_index));
} else if self.indexed.has_value() {
attributes.push(("indexed", &indexed));
} else if self.argb.has_value() {
attributes.push(("rgb", self.argb.get_value_string()));
}
let tint = self.tint.get_value_string();
if self.tint.has_value() {
attributes.push(("tint", &tint));
}
if !attributes.is_empty() {
write_start_tag(writer, tag_name, attributes, true);
}
}
}