use loc::Loc;
use focus_char::FocusChar;
use optimizer::Optimizer;
use svg_element::SvgElement;
use svg::node::element::SVG;
use svg::Node;
use svg::node::element::{
Definitions,
Marker,
Path as SvgPath,
Rectangle as SvgRect,
Style,
Circle as SvgCircle,
};
use element::Element;
use pom::TextInput;
use pom::parser::{sym,none_of};
use settings::Settings;
use unicode_width::UnicodeWidthChar;
#[derive(Debug)]
pub struct Grid {
pub settings: Settings,
/// cell value is in string instead of char to accomodate multiple width characters
/// each line is Vec<String>
index: Vec<Vec<String>>,
/// This are text elements that are escaped and are not processed for diagram
/// matching
text_elm: Vec<(usize, usize, String)>,
}
impl Grid {
/// instantiate a grid from input ascii text
/// Issues:
/// 1. 2-width, 5 bytes, single character i.e. 统
/// 2. 1-width, 2 bytes, single character i.e. ö
/// 3. 1-width, 3 bytes, single character i.e. o͡͡͡
pub fn from_str(s: &str, settings: &Settings) -> Grid {
let lines: Vec<&str> = s.lines().collect();
let mut rows: Vec<Vec<String>> = Vec::with_capacity(lines.len());
let mut text_elm: Vec<(usize, usize, String)> = vec![];
for (y, line) in lines.iter().enumerate() {
let (line, escaped_texts): (String, Vec<(usize, String)>) = exclude_escaped_text(line);
let mut row: Vec<String> = Vec::with_capacity(line.chars().count());
for (x, escaped) in escaped_texts {
text_elm.push((x, y, svg_escape(&escaped)));
}
for ch in line.chars() {
if let Some(1) = ch.width() {
row.push(format!("{}", ch));
} else if let Some(2) = ch.width() {
row.push(format!("{}", ch));
// HACK: push a blank to the next cell,
//in order to make this character twice as
// big and aligns the next succeeding characters on
// this row
row.push(format!("\0"));
}
// if zero width char, append it to the previous string
else if let Some(0) = ch.width() {
let prev: Option<String> = row.pop();
match prev {
Some(mut prev) => {
prev.push(ch);
row.push(prev);
}
None => (),
}
}
}
rows.push(row);
}
let g = Grid {
settings: settings.clone(),
index: rows,
text_elm: text_elm,
};
// do the pre processing here
g.pre_process()
}
pub fn rows(&self) -> usize {
self.index.len()
}
/// get the maximum row len
pub fn columns(&self) -> usize {
self.index.iter().map(|r| r.len()).max().unwrap_or(0)
}
/// get a character at this location
/// widths are computed since there are
/// characters that spans 2 columns
/// and characters that has 0 width
///
pub fn get(&self, loc: &Loc) -> Option<&String> {
match self.index.get(loc.y as usize) {
Some(row) => row.get(loc.x as usize),
None => None,
}
}
fn text(&self, loc: &Loc) -> &str {
match self.get(loc) {
Some(ref s) => s,
None => ""
}
}
/// get the focus char at this location
pub fn get_focuschar(&self, loc: &Loc) -> FocusChar {
FocusChar::new(&loc, self)
}
/// process the enhancing of circle elements
/// this should be called before other elements are extracted from the grid
fn get_enhance_circle_elements(&self) -> (Vec<Vec<Vec<Element>>>, Vec<Loc>){
let mut rows: Vec<Vec<Vec<Element>>> = Vec::with_capacity(self.index.len());
let mut all_consumed_loc: Vec<Loc> = vec![];
for (y,line) in self.index.iter().enumerate() {
let mut row: Vec<Vec<Element>> = Vec::with_capacity(line.len());
for (x,_cell) in line.iter().enumerate() {
let loc = Loc::new(x as i32,