use pad::PadStr;
use std::usize;

use crate::configotron::conf::{UserConfigData, UserConfigItem};

#[derive(Clone, PartialEq, Debug)]
pub enum DocGridCellType {
    Boarder,
    Empty,
    SubMenu { text: Vec<String> },
    Item { text: Vec<String> },
    ItemJoin,
}

impl DocGridCellType {
    fn to_debug_string(&self) -> String {
        match self {
            DocGridCellType::Empty => "E".to_string(),
            DocGridCellType::Item { .. } => "I".to_string(),
            DocGridCellType::ItemJoin => "i".to_string(),
            DocGridCellType::SubMenu { .. } => "S".to_string(),
            DocGridCellType::Boarder => "B".to_string(),
        }
    }
}

pub enum ResultingGridCell {
    Grid(DocGrid),
    Cell(DocGridCellType),
}

fn split_string(s: &String) -> Vec<String> {
    s.split('\n')
        .map(|s| s.to_string())
        .collect::<Vec<String>>()
}

fn user_config_item_to_grid_cells(item: &UserConfigItem) -> ResultingGridCell {
    match item {
        UserConfigItem::String { name, max_length } => {
            ResultingGridCell::Cell(DocGridCellType::Item {
                text: vec![name.to_string(), format!("[length: 0..{}]", max_length)],
            })
        }
        UserConfigItem::IPv4 { name } => ResultingGridCell::Cell(DocGridCellType::Item {
            text: vec![name.to_string(), "[Address IPv4]".to_string()],
        }),
        UserConfigItem::Boolean { name } => ResultingGridCell::Cell(DocGridCellType::Item {
            text: vec![name.to_string(), "[Yes/No]".to_string()],
        }),
        UserConfigItem::Number { name, max, min } => {
            ResultingGridCell::Cell(DocGridCellType::Item {
                text: vec![
                    name.to_string(),
                    match (min, max) {
                        (None, None) => "[Integers]".to_string(),
                        (None, Some(h)) => format!("[Integers: ..{}]", h),
                        (Some(l), None) => format!("[Integers: {}..]", l),
                        (Some(l), Some(h)) => format!("[Integers: {}..{}]", l, h),
                    },
                ],
            })
        }
        UserConfigItem::Submenu(user_config_data) => {
            ResultingGridCell::Grid(DocGrid::from(user_config_data))
        }
    }
}

#[derive(Clone)]
pub struct DocGrid {
    rows: usize,
    cols: usize,
    array_cells: Vec<DocGridCellType>,
}

impl DocGrid {
    pub fn new() -> Self {
        Self {
            rows: 0,
            cols: 2,
            array_cells: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.cols * self.rows
    }

    pub fn get_row(&self) -> usize {
        self.rows
    }

    pub fn set_title(&mut self, cell: DocGridCellType) {
        self.array_cells
            .resize(self.len() + self.cols, DocGridCellType::Empty);
        self.array_cells[0] = cell;
    }

    pub fn append_item(&mut self, item: ResultingGridCell) {
        match item {
            ResultingGridCell::Cell(cell_type) => {
                self.array_cells
                    .resize(self.len() + self.cols, DocGridCellType::Empty);
                self.array_cells[self.rows * self.cols + 1] = cell_type;

                self.rows += 1;
            }
            ResultingGridCell::Grid(grid) => {
                let new_col_size = std::cmp::max(self.cols, grid.cols + 1);
                let new_row_size = self.rows + grid.rows;
                self.array_cells
                    .resize(new_col_size * new_row_size, DocGridCellType::Empty);

                let row_offset = self.rows;
                let old_cols = self.cols;
                self.cols = new_col_size;
                self.rows = new_row_size;

                for row_index in (0..new_row_size).rev() {
                    for col_index in (0..new_col_size).rev() {
                        let new_index = row_index * new_col_size + col_index;
                        if col_index < old_cols && row_index < self.rows {
                            // Reshuffel Stuff Old Stuff
                            let old_index = row_index * old_cols + col_index;
                            self.array_cells[new_index] = self.array_cells[old_index].clone();
                        } else {
                            // Make Cells left to inset empty
                            self.array_cells[new_index] = DocGridCellType::Empty;
                        }
                    }
                }

                // Copy in new stuff
                for row_index in 0..grid.rows {
                    for col_index in 0..grid.cols {
                        let (target_row_index, target_col_index) =
                            (row_index + row_offset, col_index + 1);

                        let target_index = target_col_index + target_row_index * self.cols;
                        let src_index = row_index * grid.cols + col_index;

                        self.array_cells[target_index] = grid.array_cells[src_index].clone();
                    }
                }
            }
        };
    }

    pub fn to_debug_string(&self) -> String {
        let mut s = String::new();

        for row_index in 0..self.rows {
            s.push_str("| ");
            for col_index in 0..self.cols {
                s.push_str(&format!(
                    "{} ",
                    self.array_cells[row_index * self.cols + col_index].to_debug_string()
                ));
            }
            s.push_str("|\n")
        }

        s
    }

    fn row_size_max(&self, c: usize) -> usize {
        let max = (0..self.rows)
            .map(|r| match &self.array_cells[r * self.cols + c] {
                DocGridCellType::Boarder => 1,
                DocGridCellType::Empty => 1,
                DocGridCellType::SubMenu { text: name } => {
                    name.iter().map(|s| s.len()).max().unwrap_or(0)
                }
                DocGridCellType::Item { text: name } => {
                    name.iter().map(|s| s.len()).max().unwrap_or(0)
                }
                DocGridCellType::ItemJoin => 1,
            })
            .max()
            .unwrap_or(1);

        max
    }

    pub fn row_sizes(&self) -> Vec<usize> {
        let mut res = Vec::with_capacity(self.cols);
        for c in 0..self.cols {
            res.push(self.row_size_max(c));
        }
        res
    }

    fn col_size_max(&self, r: usize) -> usize {
        let max = (0..self.cols)
            .map(|c| match &self.array_cells[r * self.cols + c] {
                DocGridCellType::Boarder => 1,
                DocGridCellType::Empty => 1,
                DocGridCellType::SubMenu { text: name } => name.len(),
                DocGridCellType::Item { text: name } => name.len(),
                DocGridCellType::ItemJoin => 1,
            })
            .max()
            .unwrap_or(1);

        max
    }

    pub fn col_sizes(&self) -> Vec<usize> {
        let mut res = Vec::with_capacity(self.rows);
        for r in 0..self.rows {
            res.push(self.col_size_max(r));
        }
        res
    }
}

impl From<&UserConfigData> for DocGrid {
    fn from(value: &UserConfigData) -> Self {
        let mut res = DocGrid::new();
        res.set_title(DocGridCellType::SubMenu {
            text: split_string(&value.name),
        });
        value.config_items.iter().for_each(|i| {
            res.append_item(user_config_item_to_grid_cells(i));
        });

        // Add ItemJoins
        for row_index in 0..res.rows {
            for col_index in 2..res.cols {
                let index = col_index + row_index * res.cols;
                match res.array_cells[col_index - 1 + row_index * res.cols] {
                    DocGridCellType::Item { .. } => {
                        res.array_cells[index] = DocGridCellType::ItemJoin;
                    }
                    DocGridCellType::ItemJoin => {
                        res.array_cells[index] = DocGridCellType::ItemJoin;
                    }
                    _ => {}
                }
            }
        }
        res
    }
}

#[derive(Clone)]
pub enum DocGridLineType {
    NONE,
    VERTICAL,
    HORIZONTAL,
}

#[derive(Clone)]
pub enum DocGridLineCrossType {
    NONE,
    FULL,
    VERTICAL,
    HORIZONTAL,
}

pub struct DocGridLayout {
    grid: DocGrid,
    lines_hort: Vec<DocGridLineType>,
    lines_vert: Vec<DocGridLineType>,
    lines_cross: Vec<DocGridLineCrossType>,
}

impl DocGridLayout {
    fn map_line_to_char(l: &DocGridLineType) -> String {
        match l {
            DocGridLineType::HORIZONTAL => "-".to_string(),
            DocGridLineType::NONE => " ".to_string(),
            DocGridLineType::VERTICAL => "|".to_string(),
        }
    }

    fn map_cross_to_chr(c: &DocGridLineCrossType) -> String {
        match c {
            DocGridLineCrossType::NONE => " ".to_string(),
            DocGridLineCrossType::FULL => "+".to_string(),
            DocGridLineCrossType::VERTICAL => "|".to_string(),
            DocGridLineCrossType::HORIZONTAL => "-".to_string(),
        }
    }

    fn get_vert_line(&self, r: i32, c: i32) -> &DocGridLineType {
        if r < 0 || r >= (self.grid.rows as i32) || c < 0 || c > (self.grid.cols as i32) {
            &DocGridLineType::NONE
        } else {
            &self.lines_vert[r as usize * (self.grid.cols + 1) + c as usize]
        }
    }

    fn set_vert_line(&mut self, r: usize, c: usize, v: DocGridLineType) {
        self.lines_vert[r as usize * (self.grid.cols + 1) + c as usize] = v;
    }

    fn get_hort_line(&self, r: i32, c: i32) -> &DocGridLineType {
        if r < 0 || r > (self.grid.rows as i32) || c < 0 || c >= (self.grid.cols as i32) {
            &DocGridLineType::NONE
        } else {
            &self.lines_hort[(r as usize) * self.grid.cols + (c as usize)]
        }
    }

    fn set_hort_line(&mut self, r: usize, c: usize, v: DocGridLineType) {
        self.lines_hort[r as usize * (self.grid.cols) + c as usize] = v;
    }

    fn get_cross(&self, r: i32, c: i32) -> &DocGridLineCrossType {
        if r < 0 || r > (self.grid.rows as i32) || c < 0 || c > (self.grid.cols as i32) {
            &DocGridLineCrossType::NONE
        } else {
            &self.lines_cross[(r as usize) * (self.grid.cols + 1) + (c as usize)]
        }
    }

    fn set_cross(&mut self, r: usize, c: usize, v: DocGridLineCrossType) {
        self.lines_cross[r * (self.grid.cols + 1) + c] = v;
    }

    pub fn new<FLineV, FLineH, FCross>(
        grid: &DocGrid,
        vertical_mapper: FLineV,
        horizontal_mapper: FLineH,
        cross_mapper: FCross,
    ) -> DocGridLayout
    where
        FLineV: Fn(&DocGridCellType, &DocGridCellType) -> DocGridLineType,
        FLineH: Fn(&DocGridCellType, &DocGridCellType) -> DocGridLineType,
        FCross: Fn(
            &DocGridLineType,
            &DocGridLineType,
            &DocGridLineType,
            &DocGridLineType,
        ) -> DocGridLineCrossType,
    {
        let mut lines_hort = Vec::new();
        let mut lines_vert = Vec::new();
        let mut crosses = Vec::new();

        lines_hort.resize(grid.cols * (1 + grid.rows), DocGridLineType::NONE);
        lines_vert.resize((grid.cols + 1) * grid.rows, DocGridLineType::NONE);
        crosses.resize(
            (grid.rows + 1) * (grid.cols + 1),
            DocGridLineCrossType::NONE,
        );

        let mut res: DocGridLayout = DocGridLayout {
            grid: grid.clone(),
            lines_cross: crosses,
            lines_hort: lines_hort,
            lines_vert: lines_vert,
        };

        let get_cell = |r: i32, c: i32| -> &DocGridCellType {
            if r < 0 || (r as usize) >= grid.rows || c < 0 || (c as usize) >= grid.cols {
                &DocGridCellType::Boarder
            } else {
                &grid.array_cells[r as usize * grid.cols + c as usize]
            }
        };

        // Calculating Lines Horizontal lines
        for row in 0..(grid.rows + 1) {
            for col in 0..grid.cols {
                let top = get_cell(row as i32 - 1, col as i32);
                let bottom = get_cell(row as i32, col as i32);
                res.set_hort_line(row, col, horizontal_mapper(top, bottom));
            }
        }

        // Calculating Lines Vertical lines
        for row in 0..grid.get_row() {
            for col in 0..(grid.cols + 1) {
                let left = get_cell(row as i32, col as i32 - 1);
                let right = get_cell(row as i32, col as i32);
                res.set_vert_line(row, col, vertical_mapper(left, right));
            }
        }
        // Calculating Crossings

        for row in 0..(grid.rows + 1) {
            for col in 0..(grid.cols + 1) {
                let north = res.get_vert_line((row as i32) - 1, col as i32);
                let south = res.get_vert_line(row as i32, col as i32);

                let east = res.get_hort_line(row as i32, col as i32);
                let west = res.get_hort_line(row as i32, (col as i32) - 1);

                res.set_cross(row, col, cross_mapper(north, east, south, west));
            }
        }

        res
    }

    pub fn to_debug_string(&self) -> String {
        let mut s = String::new();

        for r in 0..self.grid.rows {
            for c in 0..self.grid.cols {
                s.push_str(&format!(
                    "{}{}",
                    &Self::map_cross_to_chr(self.get_cross(r as i32, c as i32)),
                    &Self::map_line_to_char(self.get_hort_line(r as i32, c as i32))
                ));
            }
            s.push_str(&format!(
                "{}\n",
                &Self::map_cross_to_chr(self.get_cross(r as i32, self.grid.cols as i32))
            ));
            for c in 0..self.grid.cols {
                s.push_str(&format!(
                    "{}{}",
                    &Self::map_line_to_char(self.get_vert_line(r as i32, c as i32)),
                    &self.grid.array_cells[self.grid.cols * r + c].to_debug_string()
                ));
            }
            s.push_str(&format!(
                "{}\n",
                &Self::map_line_to_char(self.get_vert_line(r as i32, self.grid.cols as i32))
            ));
        }

        for c in 0..self.grid.cols {
            s.push_str(&format!(
                "{}{}",
                &Self::map_cross_to_chr(self.get_cross(self.grid.rows as i32, c as i32)),
                &Self::map_line_to_char(self.get_hort_line(self.grid.rows as i32, c as i32))
            ));
        }

        s.push_str(&format!(
            "{}\n",
            &Self::map_cross_to_chr(self.get_cross(self.grid.rows as i32, self.grid.cols as i32))
        ));

        s
    }

    pub fn to_ascii_doc_string(&self) -> String {
        let col_sizes = self.grid.col_sizes();
        let row_sizes = self.grid.row_sizes();
        let mut s = String::new();

        let empty_string = "".to_string();

        let map_cell = |cell: &DocGridCellType, sub_c: &usize| -> String {
            match cell {
                DocGridCellType::Boarder => empty_string.clone(),
                DocGridCellType::Empty => empty_string.clone(),
                DocGridCellType::SubMenu { text } => {
                    text.get(*sub_c).cloned().unwrap_or(empty_string.clone())
                }
                DocGridCellType::Item { text } => {
                    text.get(*sub_c).cloned().unwrap_or(empty_string.clone())
                }
                DocGridCellType::ItemJoin => empty_string.clone(),
            }
        };

        for r in 0..self.grid.rows {
            for c in 0..self.grid.cols {
                s.push_str(&format!(
                    "{}{}",
                    &Self::map_cross_to_chr(self.get_cross(r as i32, c as i32)),
                    &Self::map_line_to_char(self.get_hort_line(r as i32, c as i32))
                        .repeat(row_sizes[c] + 2)
                ));
            }
            s.push_str(&format!(
                "{}\n",
                &Self::map_cross_to_chr(self.get_cross(r as i32, self.grid.cols as i32))
            ));

            for sub_c in 0..col_sizes[r] {
                for c in 0..self.grid.cols {
                    s.push_str(&format!(
                        "{} {} ",
                        &Self::map_line_to_char(self.get_vert_line(r as i32, c as i32)),
                        &map_cell(&self.grid.array_cells[self.grid.cols * r + c], &sub_c)
                            .pad_to_width(row_sizes[c])
                    ));
                }
                s.push_str(&format!(
                    "{}\n",
                    &Self::map_line_to_char(self.get_vert_line(r as i32, self.grid.cols as i32))
                ));
            }
        }

        for c in 0..self.grid.cols {
            s.push_str(&format!(
                "{}{}",
                &Self::map_cross_to_chr(self.get_cross(self.grid.rows as i32, c as i32)),
                &Self::map_line_to_char(self.get_hort_line(self.grid.rows as i32, c as i32))
                    .repeat(row_sizes[c] + 2)
            ));
        }

        s.push_str(&format!(
            "{}\n",
            &Self::map_cross_to_chr(self.get_cross(self.grid.rows as i32, self.grid.cols as i32))
        ));

        s
    }
}

mod doc_grid_layout_mappers {
    use super::{DocGridCellType, DocGridLineCrossType, DocGridLineType};

    pub fn vert_line_ascii(left: &DocGridCellType, right: &DocGridCellType) -> DocGridLineType {
        use DocGridCellType::{Item, ItemJoin};
        match (left, right) {
            (ItemJoin, Item { .. }) => DocGridLineType::NONE,
            (Item { .. }, ItemJoin) => DocGridLineType::NONE,

            (_, _) => DocGridLineType::VERTICAL,
        }
    }

    pub fn hort_line_ascii(top: &DocGridCellType, bottom: &DocGridCellType) -> DocGridLineType {
        use DocGridCellType::{Boarder, Empty, Item, ItemJoin, SubMenu};
        match (top, bottom) {
            (Empty, Empty) => DocGridLineType::NONE,

            // Sub Menu "Joins"
            (Empty, SubMenu { .. }) => DocGridLineType::HORIZONTAL,
            (SubMenu { .. }, Empty) => DocGridLineType::NONE,
            (SubMenu { .. }, SubMenu { .. }) => DocGridLineType::HORIZONTAL,

            // Horizontal Rules
            (Boarder, _) => DocGridLineType::HORIZONTAL,
            (_, Boarder) => DocGridLineType::HORIZONTAL,

            (Item { .. }, _) => DocGridLineType::HORIZONTAL,
            (_, Item { .. }) => DocGridLineType::HORIZONTAL,

            (ItemJoin, _) => DocGridLineType::HORIZONTAL,
            (_, ItemJoin) => DocGridLineType::HORIZONTAL,
        }
    }

    pub fn cross_ascii(
        n: &DocGridLineType,
        e: &DocGridLineType,
        s: &DocGridLineType,
        w: &DocGridLineType,
    ) -> DocGridLineCrossType {
        use DocGridLineType::{HORIZONTAL, NONE, VERTICAL};
        match (n, e, s, w) {
            (VERTICAL, NONE, VERTICAL, NONE) => DocGridLineCrossType::VERTICAL,
            (NONE, HORIZONTAL, NONE, HORIZONTAL) => DocGridLineCrossType::HORIZONTAL,
            (_, _, _, _) => DocGridLineCrossType::FULL,
        }
    }
}

pub fn create_ascii_debug_string(grid: &DocGrid) -> String {
    let layout = DocGridLayout::new(
        grid,
        doc_grid_layout_mappers::vert_line_ascii,
        doc_grid_layout_mappers::hort_line_ascii,
        doc_grid_layout_mappers::cross_ascii,
    );

    return layout.to_debug_string();
}

pub fn create_ascii_doc_string(grid: &DocGrid) -> String {
    let layout = DocGridLayout::new(
        grid,
        doc_grid_layout_mappers::vert_line_ascii,
        doc_grid_layout_mappers::hort_line_ascii,
        doc_grid_layout_mappers::cross_ascii,
    );

    return layout.to_ascii_doc_string();
}

#[cfg(test)]
mod tests {
    use super::{DocGrid, DocGridCellType, ResultingGridCell};
    use crate::configotron::conf::{UserConfigData, UserConfigItem};

    // Helper functino for creating elements for testing
    fn create_item() -> UserConfigItem {
        UserConfigItem::Boolean {
            name: "Test".to_string(),
        }
    }

    fn create_submenu(v: Vec<UserConfigItem>) -> UserConfigItem {
        UserConfigItem::Submenu(UserConfigData {
            name: "SubMenu".to_string(),
            config_items: v,
        })
    }

    fn create_menu(v: Vec<UserConfigItem>) -> UserConfigData {
        UserConfigData {
            name: "TestMenu".to_string(),
            config_items: v,
        }
    }

    // Actuall Test
    #[test]
    fn grid_extend() {
        let mut grid = DocGrid::new();

        grid.set_title(DocGridCellType::SubMenu {
            text: vec!["name".to_string()],
        });
        grid.append_item(ResultingGridCell::Cell(DocGridCellType::Item {
            text: vec!["name".to_string()],
        }));
        grid.append_item(ResultingGridCell::Cell(DocGridCellType::ItemJoin));
        grid.append_item(ResultingGridCell::Cell(DocGridCellType::Item {
            text: vec!["name".to_string()],
        }));
        grid.append_item(ResultingGridCell::Cell(DocGridCellType::Item {
            text: vec!["name".to_string()],
        }));
        grid.append_item(ResultingGridCell::Cell(DocGridCellType::ItemJoin));
        grid.append_item(ResultingGridCell::Cell(DocGridCellType::SubMenu {
            text: vec!["name".to_string()],
        }));

        assert_eq!(
            grid.to_debug_string(),
            r#"| S I |
| E i |
| E I |
| E I |
| E i |
| E S |
"#
        );
    }

    #[test]
    fn grid_assembly_from_data() {
        let data = create_menu(vec![
            create_item(),
            create_item(),
            create_submenu(vec![create_item(), create_item(), create_item()]),
            create_item(),
            create_item(),
            create_item(),
        ]);

        let grid = DocGrid::from(&data);

        assert_eq!(
            grid.to_debug_string(),
            r#"| S I i |
| E I i |
| E S I |
| E E I |
| E E I |
| E I i |
| E I i |
| E I i |
"#
        );
    }

    #[test]
    fn grid_deep_assembly_from_data() {
        let data = create_menu(vec![create_submenu(vec![create_submenu(vec![
            create_submenu(vec![create_item()]),
        ])])]);

        let grid = DocGrid::from(&data);

        assert_eq!(
            grid.to_debug_string(),
            r#"| S S S S I |
"#
        );
    }

    #[test]
    fn grid_complex_assembly_from_data() {
        let data = create_menu(vec![
            create_item(),
            create_item(),
            create_submenu(vec![
                create_item(),
                create_item(),
                create_submenu(vec![
                    create_item(),
                    create_item(),
                    create_submenu(vec![create_item(), create_item()]),
                    create_item(),
                ]),
                create_item(),
                create_submenu(vec![create_item(), create_item()]),
                create_item(),
                create_item(),
            ]),
            create_item(),
            create_item(),
        ]);

        let grid = DocGrid::from(&data);

        println!("{}", grid.to_debug_string());

        assert_eq!(
            grid.to_debug_string(),
            r#"| S I i i i |
| E I i i i |
| E S I i i |
| E E I i i |
| E E S I i |
| E E E I i |
| E E E S I |
| E E E E I |
| E E E I i |
| E E I i i |
| E E S I i |
| E E E I i |
| E E I i i |
| E E I i i |
| E I i i i |
| E I i i i |
"#
        );
    }

    mod ascii_docs {
        use super::{create_item, create_menu, create_submenu, DocGrid};
        use crate::configotron::{
            doc::grid::create_ascii_debug_string, doc::grid::create_ascii_doc_string,
        };

        #[test]
        fn ascii_docs_debug() {
            let data = create_menu(vec![
                create_item(),
                create_item(),
                create_submenu(vec![create_item(), create_item(), create_item()]),
                create_item(),
                create_item(),
                create_item(),
            ]);

            let grid = DocGrid::from(&data);

            println!("{}", grid.to_debug_string());

            let s = create_ascii_debug_string(&grid);

            println!("{}", s);

            assert_eq!(
                s,
                r#"+-+---+
|S|I i|
| +---+
|E|I i|
| +-+-+
|E|S|I|
| | +-+
|E|E|I|
| | +-+
|E|E|I|
| +-+-+
|E|I i|
| +---+
|E|I i|
| +---+
|E|I i|
+-+---+
"#
            );
        }

        #[test]
        fn ascii_docs_real() {
            let data = create_menu(vec![
                create_item(),
                create_item(),
                create_submenu(vec![create_item(), create_item(), create_item()]),
                create_item(),
                create_item(),
                create_item(),
            ]);

            let grid = DocGrid::from(&data);

            println!("{}", grid.to_debug_string());

            let s = create_ascii_doc_string(&grid);

            println!("{}", s);

            assert_eq!(
                s,
                r#"+----------+---------------------+
| TestMenu | Test                |
|          | [Yes/No]            |
|          +---------------------+
|          | Test                |
|          | [Yes/No]            |
|          +----------+----------+
|          | SubMenu  | Test     |
|          |          | [Yes/No] |
|          |          +----------+
|          |          | Test     |
|          |          | [Yes/No] |
|          |          +----------+
|          |          | Test     |
|          |          | [Yes/No] |
|          +----------+----------+
|          | Test                |
|          | [Yes/No]            |
|          +---------------------+
|          | Test                |
|          | [Yes/No]            |
|          +---------------------+
|          | Test                |
|          | [Yes/No]            |
+----------+---------------------+
"#
            );
        }
    }
}
