use std::io::{Write, Error};
use std::iter::FromIterator;
use std::ops::{Index, IndexMut};
use term::Terminal;
use super::utils::NEWLINE;
use super::cell::Cell;
use super::format::TableFormat;
#[derive(Clone, Debug)]
pub struct Row {
cells: Vec<Cell>
}
impl Row {
pub fn new(cells: Vec<Cell>) -> Row {
return Row {
cells: cells
};
}
pub fn empty() -> Row {
return Self::new(vec![Cell::default(); 0]);
}
pub fn len(&self) -> usize {
return self.cells.len();
}
pub fn get_height(&self) -> usize {
let mut height = 1; for cell in &self.cells {
let h = cell.get_height();
if h > height {
height = h;
}
}
return height;
}
pub fn get_cell_width(&self, column: usize) -> usize {
return match self.cells.get(column) {
Some(cell) => cell.get_width(),
None => 0
}
}
pub fn get_cell(&self, idx: usize) -> Option<&Cell> {
return self.cells.get(idx);
}
pub fn get_mut_cell(&mut self, idx: usize) -> Option<&mut Cell> {
return self.cells.get_mut(idx);
}
pub fn set_cell(&mut self, cell: Cell, column: usize) -> Result<(), &str> {
if column >= self.len() {
return Err("Cannot find cell");
}
self.cells[column] = cell;
return Ok(());
}
pub fn add_cell(&mut self, cell: Cell) {
self.cells.push(cell);
}
pub fn insert_cell(&mut self, index: usize, cell: Cell) {
if index < self.cells.len() {
self.cells.insert(index, cell);
} else {
self.add_cell(cell);
}
}
pub fn remove_cell(&mut self, index: usize) {
if index < self.cells.len() {
self.cells.remove(index);
}
}
fn __print<T:Write+?Sized, F>(&self, out: &mut T, format: &TableFormat, col_width: &[usize], f: F) -> Result<(), Error>
where F: Fn(&Cell, &mut T, usize, usize) -> Result<(), Error>
{
for i in 0..self.get_height() {
try!(format.print_column_separator(out));
for j in 0..col_width.len() {
match self.get_cell(j) {
Some(ref c) => try!(f(c, out, i, col_width[j])),
None => try!(f(&Cell::default(), out, i, col_width[j]))
};
try!(format.print_column_separator(out));
}
try!(out.write_all(NEWLINE));
}
return Ok(());
}
pub fn print<T: Write+?Sized>(&self, out: &mut T, format: &TableFormat, col_width: &[usize]) -> Result<(), Error> {
return self.__print(out, format, col_width, Cell::print);
}
pub fn print_term<T: Terminal+?Sized>(&self, out: &mut T, format: &TableFormat, col_width: &[usize]) -> Result<(), Error> {
return self.__print(out, format, col_width, Cell::print_term);
}
}
impl Default for Row {
fn default() -> Row {
return Row::empty();
}
}
impl Index<usize> for Row {
type Output = Cell;
fn index(&self, idx: usize) -> &Self::Output {
return &self.cells[idx];
}
}
impl IndexMut<usize> for Row {
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
return &mut self.cells[idx];
}
}
impl <A: ToString> FromIterator<A> for Row {
fn from_iter<T>(iterator: T) -> Row where T: IntoIterator<Item=A> {
return Self::new(iterator.into_iter().map(|ref e| Cell::from(e)).collect());
}
}
impl <T, A> From<T> for Row where A: ToString, T : IntoIterator<Item=A> {
fn from(it: T) -> Row {
return Self::from_iter(it);
}
}
#[macro_export]
macro_rules! row {
(($($out:tt)*); $value:expr) => (vec![$($out)* cell!($value)]);
(($($out:tt)*); $value:expr, $($n:tt)*) => (row!(($($out)* cell!($value),); $($n)*));
(($($out:tt)*); $style:ident : $value:expr) => (vec![$($out)* cell!($style : $value)]);
(($($out:tt)*); $style:ident : $value:expr, $($n: tt)*) => (row!(($($out)* cell!($style : $value),); $($n)*));
($($content:expr), *) => ($crate::row::Row::new(vec![$(cell!($content)), *]));
($style:ident -> $($content:expr), *) => ($crate::row::Row::new(vec![$(cell!($style : $content)), *]));
($($content:tt)*) => ($crate::row::Row::new(row!((); $($content)*)));
}