use std::cell::RefCell;
use std::fmt;
use std::fmt::Display;
pub const SPACE: char = '\u{0020}';
pub const LIGHT_HORIZONTAL: char = '\u{2500}';
pub const LIGHT_VERTICAL: char = '\u{2502}';
pub const LIGHT_DOWN_AND_RIGHT: char = '\u{250C}';
pub const LIGHT_DOWN_AND_LEFT: char = '\u{2510}';
pub const LIGHT_UP_AND_RIGHT: char = '\u{2514}';
pub const LIGHT_UP_AND_LEFT: char = '\u{2518}';
pub const LIGHT_VERTICAL_AND_RIGHT: char = '\u{251C}';
pub const LIGHT_VERTICAL_AND_LEFT: char = '\u{2524}';
pub const LIGHT_DOWN_AND_HORIZONTAL: char = '\u{252C}';
pub const LIGHT_UP_AND_HORIZONTAL: char = '\u{2534}';
pub const LIGHT_VERTICAL_AND_HORIZONTAL: char = '\u{253C}';
pub const DOUBLE_HORIZONTAL: char = '\u{2550}';
pub const DOUBLE_VERTICAL: char = '\u{2551}';
pub const VERTICAL_SINGLE_AND_RIGHT_DOUBLE: char = '\u{255E}';
pub const VERTICAL_DOUBLE_AND_RIGHT_SINGLE: char = '\u{255F}';
pub const VERTICAL_SINGLE_AND_LEFT_DOUBLE: char = '\u{2561}';
pub const VERTICAL_DOUBLE_AND_LEFT_SINGLE: char = '\u{2562}';
pub const DOWN_SINGLE_AND_HORIZONTAL_DOUBLE: char = '\u{2564}';
pub const DOWN_DOUBLE_AND_HORIZONTAL_SINGLE: char = '\u{2565}';
pub const UP_SINGLE_AND_HORIZONTAL_DOUBLE: char = '\u{2567}';
pub const UP_DOUBLE_AND_HORIZONTAL_SINGLE: char = '\u{2568}';
pub const VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE: char = '\u{256A}';
pub const VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE: char = '\u{256B}';
pub const DOUBLE_VERTICAL_AND_HORIZONTAL: char = '\u{256C}';
pub const ATTRIBUTE_CLEAR: u8 = 0x0;
pub const ATTRIBUTE_JOIN: u8 = 0x01;
pub const ATTRIBUTE_FULL_JOIN: u8 = 0x02;
#[derive(Debug, Clone)]
pub struct Char {
ch: RefCell<char>,
attributes: RefCell<u8>,
}
impl Display for Char {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.ch.borrow())
}
}
impl PartialEq for Char {
fn eq(&self, other: &Self) -> bool {
self.ch == other.ch
}
}
impl From<char> for Char {
fn from(ch: char) -> Self {
Self {
ch: RefCell::new(ch),
attributes: RefCell::new(ATTRIBUTE_CLEAR),
}
}
}
impl Char {
pub fn new(ch: char, attributes: u8) -> Self {
Self {
ch: RefCell::new(ch),
attributes: RefCell::new(attributes),
}
}
pub fn char(&self) -> char {
*self.ch.borrow()
}
pub fn attributes(&self) -> u8 {
*self.attributes.borrow()
}
pub fn set_char(&self, ch: char) {
*self.ch.borrow_mut() = ch;
}
pub fn horz_fill(&self) -> Self {
if self.is_single_vert_line_crossing_left() {
Char::new(LIGHT_HORIZONTAL, self.attributes())
} else if self.is_double_vert_line_crossing_left() {
Char::new(DOUBLE_HORIZONTAL, self.attributes())
} else {
Char::new(SPACE, self.attributes())
}
}
pub fn is_join(&self) -> bool {
*self.attributes.borrow() & ATTRIBUTE_JOIN == ATTRIBUTE_JOIN
}
pub fn set_join(&self) {
*self.attributes.borrow_mut() |= ATTRIBUTE_JOIN;
*self.attributes.borrow_mut() &= !ATTRIBUTE_FULL_JOIN;
}
pub fn clear_join(&self) {
*self.attributes.borrow_mut() &= !ATTRIBUTE_JOIN;
}
pub fn is_full_join(&self) -> bool {
*self.attributes.borrow() & ATTRIBUTE_FULL_JOIN == ATTRIBUTE_FULL_JOIN
}
pub fn set_full_join(&self) {
*self.attributes.borrow_mut() |= ATTRIBUTE_FULL_JOIN;
*self.attributes.borrow_mut() &= !ATTRIBUTE_JOIN;
}
pub fn clear_full_join(&self) {
*self.attributes.borrow_mut() &= !ATTRIBUTE_FULL_JOIN;
}
pub fn is_frame(&self) -> bool {
matches!(
*self.ch.borrow(),
LIGHT_HORIZONTAL
| LIGHT_VERTICAL
| LIGHT_DOWN_AND_RIGHT
| LIGHT_DOWN_AND_LEFT
| LIGHT_UP_AND_RIGHT
| LIGHT_UP_AND_LEFT
| LIGHT_VERTICAL_AND_RIGHT
| LIGHT_VERTICAL_AND_LEFT
| LIGHT_DOWN_AND_HORIZONTAL
| LIGHT_UP_AND_HORIZONTAL
| LIGHT_VERTICAL_AND_HORIZONTAL
| DOUBLE_HORIZONTAL
| DOUBLE_VERTICAL
| VERTICAL_SINGLE_AND_RIGHT_DOUBLE
| VERTICAL_DOUBLE_AND_RIGHT_SINGLE
| VERTICAL_SINGLE_AND_LEFT_DOUBLE
| VERTICAL_DOUBLE_AND_LEFT_SINGLE
| DOWN_SINGLE_AND_HORIZONTAL_DOUBLE
| DOWN_DOUBLE_AND_HORIZONTAL_SINGLE
| UP_SINGLE_AND_HORIZONTAL_DOUBLE
| UP_DOUBLE_AND_HORIZONTAL_SINGLE
| VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE
| VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE
| DOUBLE_VERTICAL_AND_HORIZONTAL
)
}
pub fn is_crossing(&self) -> bool {
matches!(
*self.ch.borrow(),
LIGHT_DOWN_AND_RIGHT
| LIGHT_DOWN_AND_LEFT
| LIGHT_UP_AND_RIGHT
| LIGHT_UP_AND_LEFT
| LIGHT_VERTICAL_AND_RIGHT
| LIGHT_VERTICAL_AND_LEFT
| LIGHT_DOWN_AND_HORIZONTAL
| LIGHT_UP_AND_HORIZONTAL
| LIGHT_VERTICAL_AND_HORIZONTAL
| VERTICAL_SINGLE_AND_RIGHT_DOUBLE
| VERTICAL_DOUBLE_AND_RIGHT_SINGLE
| VERTICAL_SINGLE_AND_LEFT_DOUBLE
| VERTICAL_DOUBLE_AND_LEFT_SINGLE
| DOWN_SINGLE_AND_HORIZONTAL_DOUBLE
| DOWN_DOUBLE_AND_HORIZONTAL_SINGLE
| UP_SINGLE_AND_HORIZONTAL_DOUBLE
| UP_DOUBLE_AND_HORIZONTAL_SINGLE
| VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE
| VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE
| DOUBLE_VERTICAL_AND_HORIZONTAL
)
}
pub fn is_vert_line(&self) -> bool {
matches!(*self.ch.borrow(), LIGHT_VERTICAL | DOUBLE_VERTICAL)
}
pub fn is_vert_line_or_crossing(&self) -> bool {
self.is_vert_line() || self.is_crossing()
}
pub fn is_single_vert_line(&self) -> bool {
matches!(*self.ch.borrow(), LIGHT_VERTICAL)
}
pub fn is_double_vert_line(&self) -> bool {
matches!(*self.ch.borrow(), DOUBLE_VERTICAL)
}
pub fn is_single_vert_line_crossing_left(&self) -> bool {
matches!(
*self.ch.borrow(),
LIGHT_VERTICAL_AND_HORIZONTAL
| LIGHT_DOWN_AND_HORIZONTAL
| LIGHT_UP_AND_HORIZONTAL
| LIGHT_DOWN_AND_LEFT
| LIGHT_UP_AND_LEFT
| LIGHT_VERTICAL_AND_LEFT
| DOWN_DOUBLE_AND_HORIZONTAL_SINGLE
| UP_DOUBLE_AND_HORIZONTAL_SINGLE
| VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE
| VERTICAL_DOUBLE_AND_LEFT_SINGLE
)
}
pub fn is_double_vert_line_crossing_left(&self) -> bool {
matches!(
*self.ch.borrow(),
VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE
| DOUBLE_VERTICAL_AND_HORIZONTAL
| VERTICAL_SINGLE_AND_LEFT_DOUBLE
| DOWN_SINGLE_AND_HORIZONTAL_DOUBLE
| UP_SINGLE_AND_HORIZONTAL_DOUBLE
)
}
pub fn is_vert_line_crossing_left(&self) -> bool {
self.is_single_vert_line_crossing_left() || self.is_double_vert_line_crossing_left()
}
pub fn is_vert_line_left(&self) -> bool {
matches!(
*self.ch.borrow(),
LIGHT_VERTICAL | LIGHT_VERTICAL_AND_RIGHT | DOUBLE_VERTICAL | VERTICAL_DOUBLE_AND_RIGHT_SINGLE
)
}
pub fn is_vert_line_right(&self) -> bool {
matches!(
*self.ch.borrow(),
LIGHT_VERTICAL | LIGHT_VERTICAL_AND_LEFT | DOUBLE_VERTICAL | VERTICAL_DOUBLE_AND_LEFT_SINGLE
)
}
pub fn is_horz_line(&self) -> bool {
matches!(*self.ch.borrow(), LIGHT_HORIZONTAL | DOUBLE_HORIZONTAL)
}
pub fn is_horz_line_or_crossing(&self) -> bool {
self.is_horz_line() || self.is_crossing()
}
pub fn is_space(&self) -> bool {
matches!(*self.ch.borrow(), SPACE)
}
}