use super::Editor;

use crate::feature_types::{Grab, GrabKind, MoveType, SearchId};

use gapp::Update;

impl Update for Editor {
    fn update(&mut self, _timestep: f32) {
        if let Some(Grab {
            kind, moved: true, ..
        }) = self.grab
        {
            if let GrabKind::Move(MoveType::Nodes) | GrabKind::Connect | GrabKind::Select = kind {
                const WS: f32 = 6.0;
                let movefac = self.zoom * 0x400 as f32;
                let window_left = (self.mouse_pos.x - self.window_size.x / WS) / self.window_size.x;
                if window_left < 0.0 {
                    self.view_offset.x -= window_left.powf(2.0) * movefac;
                }
                let window_right = (1.0 - self.mouse_pos.x + self.window_size.x * (WS - 1.0) / WS)
                    / self.window_size.x;
                if window_right < 0.0 {
                    self.view_offset.x += window_right.powf(2.0) * movefac;
                }
                let window_up = (self.mouse_pos.y - self.window_size.y / WS) / self.window_size.y;
                if window_up < 0.0 {
                    self.view_offset.y -= window_up.powf(2.0) * movefac;
                }
                let window_down = (1.0 - self.mouse_pos.y + self.window_size.y * (WS - 1.0) / WS)
                    / self.window_size.y;
                if window_down < 0.0 {
                    self.view_offset.y += window_down.powf(2.0) * movefac;
                }
            }
        }

        let relative_mouse_pos = self.relative_mouse_pos();
        if let Some(Grab {
            pos: grab_pos,
            kind: GrabKind::Move(move_type),
            ..
        }) = &mut self.grab
        {
            let movevec = relative_mouse_pos - *grab_pos;

            match move_type {
                MoveType::Nodes => {
                    for (&pid, subindices) in self.selected.pids.iter() {
                        let positions = &mut self.nodes.place_mut(pid).positions;
                        for &subindex in subindices {
                            positions[subindex] += movevec;
                        }
                    }
                    for &tid in self.selected.tids.iter() {
                        self.nodes.transitions.node_mut(tid).position += movevec;
                    }
                    *grab_pos += movevec;
                }
                MoveType::View => self.view_offset -= movevec,
            }
        }

        if let Some(string_searcher) = &self.string_searcher {
            if let Some(index) = &string_searcher.index {
                use SearchId::*;
                if let Some(goal_pos) = match index {
                    &Place(pindex) => {
                        let pid = *string_searcher.list.pids.iter().nth(pindex).unwrap();
                        let node = &self.nodes.place(pid);
                        node.positions.iter().fold(None, |result, pos| {
                            let new_distance = (pos - self.view_offset).norm_squared();
                            if let Some((position, distance)) = result {
                                if new_distance >= distance {
                                    return Some((position, distance));
                                }
                            }
                            Some((pos, new_distance))
                        })
                    }
                    &Transition(tindex) => {
                        let tid = *string_searcher.list.tids.iter().nth(tindex).unwrap();
                        Some((&self.nodes.transitions.node(tid).position, 0.0))
                    }
                } {
                    self.view_offset += (goal_pos.0 - self.view_offset) / 4.0;
                }
            }
        }
    }
}
