use super::Editor;

use crate::{
    edit_list::NodeInstanceId,
    feature_types::{Grab, ViewMode},
    vector::Vector,
};

impl Editor {
    fn action_position_info(&self, click_pos: Vector) -> Option<NodeInstanceId> {
        for (&tid, node) in self.nodes.transitions.nodes.iter().rev() {
            let pos = node.position;
            if pos.x - self.node_settings.width / 2.0 < click_pos.x
                && click_pos.x < pos.x + self.node_settings.width / 2.0
                && pos.y - self.node_settings.height / 2.0 < click_pos.y
                && click_pos.y < pos.y + self.node_settings.height / 2.0
            {
                return Some(NodeInstanceId::Transition(tid));
            }
        }

        None
    }

    fn state_position_info(&self, click_pos: Vector) -> Option<NodeInstanceId> {
        for (&pid, node) in self.nodes.iter_places().rev() {
            for (subindex, pos) in node.positions.iter().enumerate() {
                if (pos - click_pos).norm() < self.node_settings.radius {
                    return Some(NodeInstanceId::Place(pid, subindex));
                }
            }
        }

        None
    }

    pub(super) fn click_info(&self, click_pos: Vector) -> Option<NodeInstanceId> {
        if self.view_mode != ViewMode::State {
            if let Some(id) = self.action_position_info(click_pos) {
                return Some(id);
            }
        }

        if self.view_mode != ViewMode::Actions {
            if let Some(id) = self.state_position_info(click_pos) {
                return Some(id);
            }
        }

        None
    }

    fn add_action_box_info(
        &self,
        left: f32,
        right: f32,
        top: f32,
        bottom: f32,
        result: &mut Vec<NodeInstanceId>,
    ) {
        for (&tid, node) in self.nodes.transitions.nodes.iter().rev() {
            let pos = node.position;
            if pos.x - self.node_settings.width / 2.0 < right
                && left < pos.x + self.node_settings.width / 2.0
                && pos.y - self.node_settings.height / 2.0 < top
                && bottom < pos.y + self.node_settings.height / 2.0
            {
                result.push(NodeInstanceId::Transition(tid));
            }
        }
    }

    fn add_state_box_info(
        &self,
        left: f32,
        right: f32,
        top: f32,
        bottom: f32,
        result: &mut Vec<NodeInstanceId>,
    ) {
        for (&pid, node) in self.nodes.iter_places().rev() {
            for (subindex, pos) in node.positions.iter().enumerate() {
                if pos.x - self.node_settings.radius < right
                    && left < pos.x + self.node_settings.radius
                    && pos.y - self.node_settings.radius < top
                    && bottom < pos.y + self.node_settings.radius
                {
                    result.push(NodeInstanceId::Place(pid, subindex));
                }
            }
        }
    }

    pub(super) fn box_info(&self) -> Vec<NodeInstanceId> {
        let mut result = Vec::new();

        if let Some(Grab { pos: grab_pos, .. }) = self.grab {
            let pos1 = grab_pos;
            let pos2 = self.relative_mouse_pos();

            let left = pos1.x.min(pos2.x);
            let right = pos1.x.max(pos2.x);
            let top = pos1.y.max(pos2.y);
            let bottom = pos1.y.min(pos2.y);

            if self.view_mode != ViewMode::State {
                self.add_action_box_info(left, right, top, bottom, &mut result)
            }

            if self.view_mode != ViewMode::Actions {
                self.add_state_box_info(left, right, top, bottom, &mut result)
            }
        }

        result
    }
}
