use super::Editor;

use crate::{feature_types::SearchId, text_content::TextCursor};

use single_whitespace_text_editing::single_whitespace_string_edit;
use text_editing::TextLine;

impl Editor {
    /// Input text.
    pub fn text_input(&mut self, character: char, skip: bool) {
        if character == '#' {
            return;
        }
        let edit_string = if let Some(edit_string) = single_whitespace_string_edit(character, skip)
        {
            edit_string
        } else {
            return;
        };

        if let Some(string_searcher) = &mut self.string_searcher {
            if !edit_string(
                &mut string_searcher.name,
                &mut string_searcher.name_cursor,
                character,
            ) {
                return;
            }
            let subtext = &string_searcher.name;
            if subtext.is_empty() {
                string_searcher.list.pids.clear();
                string_searcher.list.tids.clear();
                string_searcher.index = None;
            } else {
                string_searcher.list.pids = self
                    .nodes
                    .iter_places()
                    .filter_map(|(&pid, node)| {
                        let node_name = node.name.as_str();
                        let subtext = subtext.as_str();
                        if node_name.contains(&subtext) {
                            return Some(pid);
                        }
                        None
                    })
                    .collect();
                string_searcher.list.tids = self
                    .nodes
                    .transitions
                    .nodes
                    .iter()
                    .filter_map(|(&tid, node)| {
                        let node_name = node.name.as_str();
                        let subtext = subtext.as_str();
                        if node_name.contains(&subtext) {
                            return Some(tid);
                        }

                        None
                    })
                    .collect();
                match (
                    string_searcher.list.pids.is_empty(),
                    string_searcher.list.tids.is_empty(),
                ) {
                    (true, true) => string_searcher.index = None,
                    (true, false) => string_searcher.index = Some(SearchId::Transition(0)),
                    (false, true) => string_searcher.index = Some(SearchId::Place(0)),
                    (false, false) => {
                        if let Some(index) = &mut string_searcher.index {
                            use SearchId::*;
                            *index = match index {
                                Place(_) => Place(0),
                                Transition(_) => Transition(0),
                            };
                        } else {
                            string_searcher.index = Some(SearchId::Transition(0));
                        }
                    }
                }
            }
        } else if self.text_content_shown && self.selected.tids.len() == 1 {
            self.changes = true;
            let content = &mut self
                .nodes
                .transitions
                .node_mut(*self.selected.tids.iter().next().unwrap())
                .content;
            if content.cursor.column == 0 && character == '\x08' && content.cursor.row > 0 {
                let line = content.lines.remove(content.cursor.row);
                content.cursor.row -= 1;
                if content.offset > 0 {
                    content.offset -= 1;
                }
                content.cursor.column = content.lines[content.cursor.row].len();
                content.lines[content.cursor.row].join(line);
            } else if content.cursor.column == content.lines[content.cursor.row].len()
                && character == '\x7F'
                && content.cursor.row < content.lines.len() - 1
            {
                let line = content.lines.remove(content.cursor.row + 1);
                content.lines[content.cursor.row].join(line);
            } else {
                edit_string(
                    &mut content.lines[content.cursor.row],
                    &mut content.cursor.column,
                    character,
                );
            }
        } else {
            self.changes = true;
            for &tid in &self.selected.tids {
                let node = self.nodes.transitions.node_mut(tid);
                edit_string(&mut node.name, &mut node.name_cursor, character);
            }
            for &pid in self.selected.pids.keys() {
                let node = self.nodes.place_mut(pid);
                edit_string(&mut node.name, &mut node.name_cursor, character);
            }
        }
    }

    /// Finish the current action.
    /// Basically the user presses the enter key.
    pub fn finish(&mut self, clear_old: bool, skip: bool) {
        if self.text_content_shown && self.selected.tids.len() == 1 {
            self.changes = true;
            let line_count = self.line_count();
            let content = &mut self
                .nodes
                .transitions
                .node_mut(*self.selected.tids.iter().next().unwrap())
                .content;
            let line = content.lines[content.cursor.row].split(content.cursor.column);
            content.cursor.row += 1;
            if content.cursor.row >= content.offset + line_count {
                content.offset = content.cursor.row - line_count;
            }
            content.cursor.column = 0;
            content.lines.insert(content.cursor.row, line);
        } else if let Some(string_searcher) = &mut self.string_searcher {
            if clear_old {
                self.selected.clear();
            }
            if skip {
                for &pid in &string_searcher.list.pids {
                    if !self.selected.pids.contains_key(&pid) {
                        self.selected.pids.insert(pid, 0);
                    }
                }
                for &tid in &string_searcher.list.tids {
                    if !self.selected.tids.contains(&tid) {
                        self.selected.tids.insert(tid);
                    }
                }
            } else {
                if let Some(index) = &string_searcher.index {
                    use SearchId::*;
                    match index {
                        &Place(pindex) => {
                            let pid = *string_searcher.list.pids.iter().nth(pindex).unwrap();
                            if !self.selected.pids.contains_key(&pid) {
                                self.selected.pids.insert(pid, 0);
                            }
                        }
                        &Transition(tindex) => {
                            let tid = *string_searcher.list.tids.iter().nth(tindex).unwrap();
                            if !self.selected.tids.contains(&tid) {
                                self.selected.tids.insert(tid);
                            }
                        }
                    }
                }
            }

            self.string_searcher = None;
        }
    }

    /// Escapes from submenus.
    pub fn escape(&mut self) {
        self.string_searcher = None;
        self.text_content_shown = false;
    }

    /// Move the text cursor in line.
    pub fn move_text_cursor(&mut self, forward: bool, skip: bool) {
        let call = TextLine::cursor_movement(forward, skip);

        if self.text_content_shown && self.selected.tids.len() == 1 {
            let content = &mut self
                .nodes
                .transitions
                .node_mut(*self.selected.tids.iter().next().unwrap())
                .content;
            let lines = &content.lines;
            let cursor = &mut content.cursor;
            let cursor_call = TextCursor::line_changer(forward);

            if skip {
                while !call(&lines[cursor.row], &mut cursor.column) {
                    if !cursor_call(cursor, lines) {
                        break;
                    }
                }
            } else {
                if !call(&lines[cursor.row], &mut cursor.column) {
                    cursor_call(cursor, lines);
                }
            }
        } else if let Some(string_searcher) = &mut self.string_searcher {
            call(&string_searcher.name, &mut string_searcher.name_cursor);
        } else {
            for &pid in self.selected.pids.keys() {
                let node = self.nodes.place_mut(pid);
                call(&node.name, &mut node.name_cursor);
            }
            for &tid in &self.selected.tids {
                let node = self.nodes.transitions.node_mut(tid);
                call(&node.name, &mut node.name_cursor);
            }
        }
    }

    /// Move the text cursor by a line.
    pub fn move_line(&mut self, down: bool) {
        if self.text_content_shown && self.selected.tids.len() == 1 {
            let line_count = self.line_count();
            let content = &mut self
                .nodes
                .transitions
                .node_mut(*self.selected.tids.iter().next().unwrap())
                .content;
            if down {
                if content.cursor.row < content.lines.len() - 1 {
                    content.cursor.row += 1;
                    if content.cursor.column > content.lines[content.cursor.row].len() {
                        content.cursor.column = content.lines[content.cursor.row].len();
                    }
                    if content.cursor.row >= content.offset + line_count {
                        content.offset = content.cursor.row - line_count;
                    }
                } else {
                    content.cursor.column = content.lines[content.cursor.row].len();
                }
            } else {
                if content.cursor.row > 0 {
                    content.cursor.row -= 1;
                    if content.cursor.column > content.lines[content.cursor.row].len() {
                        content.cursor.column = content.lines[content.cursor.row].len();
                    }
                    if content.cursor.row < content.offset {
                        content.offset = content.cursor.row;
                    }
                } else {
                    content.cursor.column = 0;
                }
            }
        }
    }

    /// Move the text by a page.
    pub fn move_page(&mut self, down: bool) {
        if self.text_content_shown && self.selected.tids.len() == 1 {
            let line_count = self.line_count();
            let content = &mut self
                .nodes
                .transitions
                .node_mut(*self.selected.tids.iter().next().unwrap())
                .content;
            if down {
                if content.offset + line_count * 2 < content.lines.len() - 1 {
                    content.offset += line_count;
                } else if content.offset + line_count < content.lines.len() - 1 {
                    content.offset = content.lines.len() - 1 - line_count;
                }

                if content.cursor.row + line_count < content.lines.len() - 1 {
                    content.cursor.row += line_count;
                } else {
                    content.cursor.row = content.lines.len() - 1;
                    content.cursor.column = content.lines[content.cursor.row].len();
                }
            } else {
                if content.offset > line_count {
                    content.offset -= line_count;
                } else {
                    content.offset = 0;
                }
                if content.cursor.row > line_count {
                    content.cursor.row -= line_count;
                } else {
                    content.cursor.row = 0;
                    content.cursor.column = 0;
                }
            }
            if content.lines[content.cursor.row].len() < content.cursor.column {
                content.cursor.column = content.lines[content.cursor.row].len();
            }
        }
    }

    /// Move the text to the start or end of line or file.
    pub fn move_text_cursor_border(&mut self, end: bool, all_lines: bool) {
        if self.text_content_shown && self.selected.tids.len() == 1 {
            let line_count = self.line_count();
            let content = &mut self
                .nodes
                .transitions
                .node_mut(*self.selected.tids.iter().next().unwrap())
                .content;

            if end {
                if all_lines {
                    if content.lines.len() > line_count {
                        content.offset = content.lines.len() - 1 - line_count;
                    }
                    content.cursor.row = content.lines.len() - 1;
                }
                content.cursor.column = content.lines[content.cursor.row].len();
            } else {
                if all_lines {
                    content.offset = 0;
                    content.cursor.row = 0;
                }
                content.cursor.column = 0;
            }
        } else if let Some(string_searcher) = &mut self.string_searcher {
            if end {
                string_searcher.name_cursor = string_searcher.name.len();
            } else {
                string_searcher.name_cursor = 0;
            }
        } else {
            if end {
                for &pid in self.selected.pids.keys() {
                    let node = self.nodes.place_mut(pid);
                    node.name_cursor = node.name.len();
                }
                for &tid in &self.selected.tids {
                    let node = self.nodes.transitions.node_mut(tid);
                    node.name_cursor = node.name.len();
                }
            } else {
                for &pid in self.selected.pids.keys() {
                    self.nodes.place_mut(pid).name_cursor = 0;
                }
                for &tid in &self.selected.tids {
                    self.nodes.transitions.node_mut(tid).name_cursor = 0;
                }
            }
        }
    }
}
