orinfar 0.0.1

A Text Editor For Witches
use crate::{
    commands::Command, mode::Mode, motion::Motion, operator::Operator, register::RegisterHandler,
    undo::UndoTree, utility::last_char, view::View, view_command::ViewCommand,
};

#[allow(clippy::too_many_arguments)]
pub fn match_action<'a>(
    chained: &mut Vec<char>,
    next_operation: &mut Option<&'a Operator<'a>>,
    count: &mut u16,

    last_chained: &mut Vec<char>,
    last_count: &mut u16,

    register_handler: &mut RegisterHandler,
    undo_tree: &mut UndoTree,
    view: &mut View,
    mode: &mut Mode,

    commands: &[Command],
    operators: &'a [Operator<'a>],
    motions: &[Motion],
    view_commands: &[ViewCommand],
) {
    let last = *match chained.last() {
        Some(c) => c,
        None => return,
    };
    let buffer = view.get_buffer_mut();

    if let Some(command) = commands
        .iter()
        .find(|motion| last_char(motion.name) == last)
    {
        (0..*count).for_each(|_| {
            command.execute(buffer, register_handler, mode, undo_tree);
        });

        reset(chained, count, next_operation, last_chained, last_count);
    } else if let Some(view_command) = view_commands
        .iter()
        .find(|command| command.name == chained.iter().collect::<String>())
    {
        (0..*count).for_each(|_| {
            view_command.execute(view);
        });

        reset(chained, count, next_operation, last_chained, last_count);
    } else if let Some(operation) = next_operation {
        if let Some(motion) = motions.iter().find(|motion| last_char(motion.name) == last) {
            (0..*count).for_each(|_| {
                operation.execute(motion, buffer, register_handler, mode, undo_tree);
            });

            reset(chained, count, next_operation, last_chained, last_count);
        } else if last_char(operation.name) == last {
            (0..*count).for_each(|_| {
                operation.entire_line(buffer, register_handler, mode, undo_tree);
            });

            reset(chained, count, next_operation, last_chained, last_count);
        }
    } else if chained.len() == 1
        && let Some(motion) = motions
            .iter()
            .find(|motion| motion.name.chars().last().unwrap() == last)
    {
        (0..*count).for_each(|_| {
            motion.apply(buffer);
        });

        reset(chained, count, next_operation, last_chained, last_count);
    }
    if let Some(operator) = operators
        .iter()
        .find(|operator| last_char(operator.name) == last)
    {
        *next_operation = Some(operator);
    }
}

pub fn reset<'a>(
    chained: &mut Vec<char>,
    count: &mut u16,
    next_operation: &mut Option<&'a Operator<'a>>,
    last_chained: &mut Vec<char>,
    last_count: &mut u16,
) {
    last_chained.clone_from(chained);
    *last_count = *count;

    chained.clear();
    *count = 1;
    *next_operation = None;
}

pub fn enumerate_normal_chars(
    commands: &[Command],
    operators: &[Operator],
    motions: &[Motion],
    view_commands: &[ViewCommand],
) -> Vec<char> {
    let command_chars = commands.iter().flat_map(|cmd| cmd.name.chars());
    let operator_chars = operators.iter().flat_map(|cmd| cmd.name.chars());
    let motion_chars = motions.iter().flat_map(|cmd| cmd.name.chars());
    let view_command_chars = view_commands.iter().flat_map(|cmd| cmd.name.chars());

    command_chars
        .chain(operator_chars)
        .chain(motion_chars)
        .chain(view_command_chars)
        .collect()
}