use crate::{grid::records::vec_records::Text, Table};
use super::Builder;
#[derive(Debug, Clone)]
pub struct IndexBuilder {
index: Vec<Text<String>>,
name: Option<Text<String>>,
print_index: bool,
transposed: bool,
data: Vec<Vec<Text<String>>>,
count_columns: usize,
}
impl IndexBuilder {
pub fn hide(mut self) -> Self {
self.print_index = false;
self
}
pub fn name(mut self, name: Option<String>) -> Self {
self.name = name.map(Text::new);
self
}
pub fn column(mut self, column: usize) -> Self {
if column >= self.count_columns {
return self;
}
self.index = get_column(&mut self.data, column);
let name = self.index.remove(0);
self.name = Some(name);
self
}
pub fn transpose(mut self) -> Self {
if self.data.is_empty() {
return self;
}
let mut columns = self.data.remove(0);
std::mem::swap(&mut self.index, &mut columns);
let count_columns = columns.len();
rotate_vector(&mut self.data, self.index.len());
self.data.insert(0, columns);
self.transposed = !self.transposed;
self.count_columns = count_columns;
self
}
pub fn build(self) -> Table {
let builder: Builder = self.into();
builder.build()
}
}
impl From<Builder> for IndexBuilder {
fn from(builder: Builder) -> Self {
let count_columns = builder.count_columns();
let data: Vec<Vec<_>> = builder.into();
let mut index = Vec::new();
if !data.is_empty() {
let count_rows = data.len() - 1;
index = build_range_index(count_rows);
}
Self {
index,
data,
count_columns,
name: None,
print_index: true,
transposed: false,
}
}
}
impl From<IndexBuilder> for Builder {
fn from(b: IndexBuilder) -> Self {
build_index(b)
}
}
fn build_index(mut b: IndexBuilder) -> Builder {
if b.index.is_empty() && b.count_columns == 0 {
return Builder::default();
}
if b.print_index {
b.index.insert(0, Text::default());
insert_column(&mut b.data, b.index, 0);
}
if let Some(name) = b.name {
if b.transposed && b.print_index {
b.data[0][0] = name;
} else {
let count_columns = b.data[0].len();
let mut name_row = vec![Text::default(); count_columns];
name_row[0] = name;
b.data.insert(1, name_row);
}
}
Builder::from_vec(b.data)
}
fn build_range_index(n: usize) -> Vec<Text<String>> {
(0..n).map(|i| i.to_string()).map(Text::new).collect()
}
fn rotate_vector<T>(rows: &mut Vec<Vec<T>>, count_columns: usize)
where
T: Default + Clone,
{
let count_rows = rows.len();
let mut columns = vec![vec![T::default(); count_rows]; count_columns];
for col in 0..count_columns {
for (row, data) in rows.iter_mut().enumerate() {
let value = data.pop().expect("expected to be controlled");
let col = count_columns - col - 1;
columns[col][row] = value;
}
}
*rows = columns;
}
fn insert_column<T: Default>(v: &mut [Vec<T>], mut column: Vec<T>, col: usize) {
for row in v.iter_mut() {
let value = column.remove(col);
row.insert(col, value);
}
}
fn get_column<T>(v: &mut [Vec<T>], col: usize) -> Vec<T>
where
T: Default,
{
let mut column = Vec::with_capacity(v.len());
for row in v.iter_mut() {
let value = row.remove(col);
column.push(value);
}
column
}