use crate::{
grid::{
ansi::ANSIBuf,
config::{ColoredConfig, Entity, Sides},
records::{ExactRecords, Records},
},
settings::{object::Object, Color, TableOption},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Colorization {
pattern: ColorizationPattern,
colors: Vec<Color>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum ColorizationPattern {
Column,
Row,
ByRow,
ByColumn,
Chess,
}
impl Colorization {
pub fn chess(white: Color, black: Color) -> Self {
Self::new(vec![white, black], ColorizationPattern::Chess)
}
pub fn exact<I, O>(colors: I, target: O) -> ExactColorization<O>
where
I: IntoIterator,
I::Item: Into<Color>,
{
let colors = colors.into_iter().map(Into::into).collect();
ExactColorization::new(colors, target)
}
pub fn rows<I>(colors: I) -> Self
where
I: IntoIterator,
I::Item: Into<Color>,
{
Self::new(colors, ColorizationPattern::Row)
}
pub fn columns<I>(colors: I) -> Self
where
I: IntoIterator,
I::Item: Into<Color>,
{
Self::new(colors, ColorizationPattern::Column)
}
pub fn by_row<I>(colors: I) -> Self
where
I: IntoIterator,
I::Item: Into<Color>,
{
Self::new(colors, ColorizationPattern::ByRow)
}
pub fn by_column<I>(colors: I) -> Self
where
I: IntoIterator,
I::Item: Into<Color>,
{
Self::new(colors, ColorizationPattern::ByColumn)
}
fn new<I>(colors: I, pattern: ColorizationPattern) -> Self
where
I: IntoIterator,
I::Item: Into<Color>,
{
let colors = colors.into_iter().map(Into::into).collect();
Self { colors, pattern }
}
}
impl<R, D> TableOption<R, ColoredConfig, D> for Colorization
where
R: Records + ExactRecords,
{
fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
if self.colors.is_empty() {
return;
}
let count_columns = records.count_columns();
let count_rows = records.count_rows();
match self.pattern {
ColorizationPattern::Column => colorize_columns(&self.colors, count_columns, cfg),
ColorizationPattern::Row => colorize_rows(&self.colors, count_rows, cfg),
ColorizationPattern::ByRow => {
colorize_by_row(&self.colors, count_rows, count_columns, cfg)
}
ColorizationPattern::ByColumn => {
colorize_by_column(&self.colors, count_rows, count_columns, cfg)
}
ColorizationPattern::Chess => {
colorize_diogonals(&self.colors, count_rows, count_columns, cfg)
}
}
}
}
fn colorize_columns(colors: &[Color], count_columns: usize, cfg: &mut ColoredConfig) {
for (col, color) in (0..count_columns).zip(colors.iter().cycle()) {
colorize_entity(color, Entity::Column(col), cfg);
}
}
fn colorize_rows(colors: &[Color], count_rows: usize, cfg: &mut ColoredConfig) {
for (row, color) in (0..count_rows).zip(colors.iter().cycle()) {
colorize_entity(color, Entity::Row(row), cfg);
}
}
fn colorize_by_row(
colors: &[Color],
count_rows: usize,
count_columns: usize,
cfg: &mut ColoredConfig,
) {
let mut color_peek = colors.iter().cycle();
for row in 0..count_rows {
for col in 0..count_columns {
let color = color_peek.next().unwrap();
colorize_entity(color, Entity::Cell(row, col), cfg);
}
}
}
fn colorize_by_column(
colors: &[Color],
count_rows: usize,
count_columns: usize,
cfg: &mut ColoredConfig,
) {
let mut color_peek = colors.iter().cycle();
for col in 0..count_columns {
for row in 0..count_rows {
let color = color_peek.next().unwrap();
colorize_entity(color, Entity::Cell(row, col), cfg);
}
}
}
fn colorize_diogonals(
colors: &[Color],
count_rows: usize,
count_columns: usize,
cfg: &mut ColoredConfig,
) {
let mut color_peek = colors.iter().cycle();
for mut row in 0..count_rows {
let color = color_peek.next().unwrap();
for col in 0..count_columns {
colorize_entity(color, Entity::Cell(row, col), cfg);
row += 1;
if row == count_rows {
break;
}
}
}
let _ = color_peek.next().unwrap();
for mut col in 1..count_columns {
let color = color_peek.next().unwrap();
for row in 0..count_rows {
colorize_entity(color, Entity::Cell(row, col), cfg);
col += 1;
if col == count_columns {
break;
}
}
}
}
fn colorize_entity(color: &Color, pos: Entity, cfg: &mut ColoredConfig) {
let ansi_color = ANSIBuf::from(color.clone());
let _ = cfg.set_color(pos, ansi_color.clone());
cfg.set_justification_color(pos, Some(ansi_color.clone()));
cfg.set_padding_color(
pos,
Sides::new(
Some(ansi_color.clone()),
Some(ansi_color.clone()),
Some(ansi_color.clone()),
Some(ansi_color),
),
);
}
#[derive(Debug, Clone)]
pub struct ExactColorization<O> {
colors: Vec<Color>,
target: O,
}
impl<O> ExactColorization<O> {
fn new(colors: Vec<Color>, target: O) -> Self {
Self { colors, target }
}
}
impl<R, D, O> TableOption<R, ColoredConfig, D> for ExactColorization<O>
where
O: Object<R>,
{
fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
if self.colors.is_empty() {
return;
}
let mut color_peek = self.colors.iter().cycle();
for pos in self.target.cells(records) {
let color = color_peek.next().unwrap();
colorize_entity(color, pos, cfg);
}
}
}