use std::ops::{Add, Sub};

#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub struct Pair<T> {
    pub x: T,
    pub y: T,
}
pub type Coord = Pair<u16>;

impl Pair<f32> {
    pub fn to_discrete(&self, size: f32) -> Coord {
        Pair {
            x: (self.x / size).floor() as u16,
            y: (self.y / size).floor() as u16,
        }
    }
}

impl<T> Pair<T> {
    pub fn new(x: T, y: T) -> Pair<T> {
        Pair { x, y }
    }
}

impl<T: Add<T, Output=T> + Sub<T, Output=T> + From<u8>> Pair<T> {
    pub fn zero() -> Pair<T> {
        Pair {
            x: T::from(0u8),
            y: T::from(0u8),
        }
    }

    pub fn left(self) -> Pair<T> {
        Pair { x: self.x - T::from(1u8), y: self.y }
    }

    pub fn right(self) -> Pair<T> {
        Pair { x: self.x + T::from(1u8), y: self.y }
    }
}

impl<O, T: Add<T, Output=O>> Add<Pair<T>> for Pair<T> {
    type Output = Pair<O>;

    fn add(self, other: Pair<T>) -> Pair<O> {
        Pair {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

impl<O, T: Add<T, Output=O> + Clone> Add<T> for Pair<T> {
    type Output = Pair<O>;

    fn add(self, r: T) -> Pair<O> {
        Pair {
            x: self.x + r.clone(),
            y: self.y + r,
        }
    }
}
