use impl_ops::*;
use std::{ops, ops::AddAssign};

pub const ALL_DIRECTIONS: [Direction; 4] = [Direction::Up, Direction::Down, Direction::Left, Direction::Right];

#[derive(Clone, Copy, Debug)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

impl AddAssign<i8> for Direction {
    fn add_assign(&mut self, rhs: i8) {
        *self = *self + rhs;
    }
}

impl_op!(+ |a: Direction, b: i8| -> Direction {
        match b {
            -1 | 3 => match a {
                Direction::Up => Direction::Left,
                Direction::Right => Direction::Up,
                Direction::Down => Direction::Right,
                Direction::Left => Direction::Down,
            },
            1 | -3 => match a {
                Direction::Up => Direction::Right,
                Direction::Right => Direction::Down,
                Direction::Down => Direction::Left,
                Direction::Left => Direction::Up,
            },
            0 | 4 | -4 => a,
            2 | -2 => match a {
                Direction::Up => Direction::Down,
                Direction::Right => Direction::Left,
                Direction::Down => Direction::Up,
                Direction::Left => Direction::Right,
            },
            n => unreachable!(format!("Illegal turn value: {}", n)),
        }
});

impl Direction {
    pub fn turn(&mut self, turn_value: i64) {
        *self += turn_value as i8;
    }
}
