use crate::{
buffer::{
cell_buffer::{Contacts, Endorse},
fragment_buffer::FragmentSpan,
FragmentBuffer, Property, PropertyBuffer, StringBuffer,
},
fragment,
fragment::Circle,
map::{circle_map, UNICODE_FRAGMENTS},
Cell, Fragment, Merge, Point, Settings,
};
use itertools::Itertools;
use std::{
fmt,
ops::{Deref, DerefMut},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Span(pub Vec<(Cell, char)>);
impl Deref for Span {
type Target = Vec<(Cell, char)>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub struct Bounds {
top_left: Cell,
bottom_right: Cell,
}
impl DerefMut for Span {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<Vec<(Cell, char)>> for Span {
fn from(cell_chars: Vec<(Cell, char)>) -> Self {
Span(cell_chars)
}
}
impl Span {
pub(crate) fn new(cell: Cell, ch: char) -> Self {
Span(vec![(cell, ch)])
}
pub(super) fn is_adjacent(&self, cell: &Cell) -> bool {
self.iter()
.rev()
.any(|(ex_cell, _)| ex_cell.is_adjacent(cell))
}
pub(super) fn can_merge(&self, other: &Self) -> bool {
self.iter().rev().any(|(cell, _)| {
other
.iter()
.any(|(other_cell, _)| cell.is_adjacent(other_cell))
})
}
pub fn paste_at(&self, loc: Cell, other: &Self) -> Self {
let mut this = self.clone();
for (cell, ch) in other.deref() {
this.push((*cell + loc, *ch));
}
this.sort();
this.dedup();
this
}
fn top_left(&self) -> Cell {
let bounds = self.bounds().expect("must have bounds");
bounds.0
}
pub fn localize_point(&self, point: Point) -> Point {
self.top_left().localize_point(point)
}
pub(crate) fn bounds(&self) -> Option<(Cell, Cell)> {
if let Some((min_y, max_y)) =
self.iter().map(|(cell, _)| cell.y).minmax().into_option()
{
if let Some((min_x, max_x)) =
self.iter().map(|(cell, _)| cell.x).minmax().into_option()
{
Some((Cell::new(min_x, min_y), Cell::new(max_x, max_y)))
} else {
None
}
} else {
None
}
}
pub fn cell_bounds(&self) -> Option<Bounds> {
if let Some((top_left, top_right)) = self.bounds() {
Some(Bounds::new(top_left, top_right))
} else {
None
}
}
pub(crate) fn localize(self) -> Self {
if let Some((tl, _br)) = self.bounds() {
let mut new_self = Span(vec![]);
for (cell, ch) in self.iter() {
let local_cell = tl.localize_cell(*cell);
new_self.push((local_cell, *ch));
}
new_self
} else {
self
}
}
pub(crate) fn endorse(self) -> Endorse<FragmentSpan, Span> {
let (mut accepted, un_endorsed_span): (Vec<FragmentSpan>, Span) =
self.endorse_to_arcs_and_circles();
let un_endorsed_contacts: Vec<Contacts> = un_endorsed_span.into();
let rect_endorsed: Endorse<FragmentSpan, Contacts> =
Contacts::endorse_rects(un_endorsed_contacts);
accepted.extend(rect_endorsed.accepted);
let re_endorsed = Self::re_endorse(rect_endorsed.rejects);
let mut endorsed = Endorse {
accepted,
rejects: vec![],
};
endorsed.extend(re_endorsed);
endorsed
}
fn re_endorse(rect_rejects: Vec<Contacts>) -> Endorse<FragmentSpan, Span> {
let span_rejects: Vec<Span> = rect_rejects
.into_iter()
.map(|contact| contact.span())
.collect();
let span_rejects: Vec<Span> = Span::merge_recursive(span_rejects);
let (accepted, rejects): (Vec<Vec<FragmentSpan>>, Vec<Span>) =
span_rejects
.into_iter()
.map(|span| span.endorse_to_arcs_and_circles())
.unzip();
Endorse {
accepted: accepted.into_iter().flatten().collect(),
rejects,
}
}
fn endorse_to_arcs_and_circles(self) -> (Vec<FragmentSpan>, Span) {
let mut accepted = vec![];
let (top_left, _) = self.bounds().expect("must have bounds");
let un_endorsed_span: Span = if let Some((circle, un_endorsed_span)) =
circle_map::endorse_circle_span(&self)
{
let circle = circle.absolute_position(top_left);
let circle_frag_span =
FragmentSpan::new(self.clone(), circle.into());
accepted.push(circle_frag_span);
un_endorsed_span
} else if let Some((three_quarters_arc, un_endorsed_span)) =
circle_map::endorse_three_quarters_arc_span(&self)
{
let three_quarters_arc =
three_quarters_arc.absolute_position(top_left);
let three_quarters_arc_frag_span =
FragmentSpan::new(self.clone(), three_quarters_arc.into());
accepted.push(three_quarters_arc_frag_span);
un_endorsed_span
} else if let Some((half_arc, un_endorsed_span)) =
circle_map::endorse_half_arc_span(&self)
{
let half_arc = half_arc.absolute_position(top_left);
let half_arc_frag_span =
FragmentSpan::new(self.clone(), half_arc.into());
accepted.push(half_arc_frag_span);
un_endorsed_span
} else if let Some((arc, un_endorsed_span)) =
circle_map::endorse_quarter_arc_span(&self)
{
let arc = arc.absolute_position(top_left);
let arc_frag_span = FragmentSpan::new(self.clone(), arc.into());
accepted.push(arc_frag_span);
un_endorsed_span
} else {
self
};
(accepted, un_endorsed_span)
}
pub(crate) fn extract(&self, bound1: Cell, bound2: Cell) -> Self {
Span(
self.iter()
.map(|(cell, ch)| (*cell, *ch))
.filter(|(cell, _ch)| cell.is_bounded(bound1, bound2))
.collect(),
)
}
pub fn is_bounded(&self, bound1: Cell, bound2: Cell) -> bool {
self.iter()
.all(|(cell, ch)| cell.is_bounded(bound1, bound2))
}
pub fn hit_cell(&self, needle: Cell) -> bool {
self.iter().any(|(cell, ch)| *cell == needle)
}
pub fn merge_no_check(&self, other: &Self) -> Self {
let mut cells = self.0.clone();
cells.extend(&other.0);
Span(cells)
}
}
impl Merge for Span {
fn merge(&self, other: &Self) -> Option<Self> {
if self.can_merge(other) {
Some(self.merge_no_check(other))
} else {
None
}
}
}
impl Bounds {
pub fn new(cell1: Cell, cell2: Cell) -> Self {
let (top_left, bottom_right) = Cell::rearrange_bound(cell1, cell2);
Self {
top_left,
bottom_right,
}
}
pub fn top_left(&self) -> Cell {
self.top_left
}
pub fn bottom_right(&self) -> Cell {
self.bottom_right
}
pub fn top_right(&self) -> Cell {
Cell::new(self.bottom_right.x, self.top_left.y)
}
pub fn bottom_left(&self) -> Cell {
Cell::new(self.top_left.x, self.bottom_right.y)
}
}
impl<'p> From<Span> for PropertyBuffer<'p> {
fn from(span: Span) -> Self {
let mut pb = PropertyBuffer::new();
for (cell, ch) in span.iter() {
if let Some(property) = Property::from_char(*ch) {
pb.as_mut().insert(*cell, property);
}
}
pb
}
}
impl From<Span> for Vec<Contacts> {
fn from(span: Span) -> Vec<Contacts> {
let fb = FragmentBuffer::from(span);
let merged_fragments: Vec<FragmentSpan> = fb.merge_fragment_spans();
let contacts: Vec<Contacts> = merged_fragments
.into_iter()
.map(|frag| Contacts::new(frag))
.collect();
Contacts::merge_recursive(contacts)
}
}
impl From<Span> for FragmentBuffer {
fn from(span: Span) -> FragmentBuffer {
let pb = PropertyBuffer::from(span.clone());
let mut fb = FragmentBuffer::from(pb.clone());
for (cell, ch) in span.iter() {
if pb.as_ref().get(cell).is_none() {
if let Some(fragments) = UNICODE_FRAGMENTS.get(ch) {
fb.add_fragments_to_cell(*cell, *ch, fragments.clone());
} else {
fb.add_fragment_to_cell(
*cell,
*ch,
fragment::cell_text(*ch),
);
}
}
}
fb
}
}
impl fmt::Display for Span {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut buffer = StringBuffer::new();
if let Some((tl, _br)) = self.bounds() {
for (cell, ch) in self.iter() {
if *ch != '\0' && !ch.is_whitespace() {
let local = tl.localize_cell(*cell);
buffer.add_char(local.x, local.y, *ch);
}
}
}
write!(f, "{}", buffer.to_string())
}
}
#[cfg(test)]
mod test_span;