use crate::geometry::point::Point;
pub struct Line<T>(pub Point<T>, pub Point<T>);
pub trait LineAPI<T> {
    fn distance(&self, p: Point<T>) -> f64;
    fn contains_point(&self, p: Point<T>) -> bool;
}
impl LineAPI<i64> for Line<i64> {
    fn distance(&self, p: Point<i64>) -> f64 {
        let v1 = self.1 - self.0;
        let v2 = p - self.0;
        let l1 = ((v1.0 * v1.0 + v1.1 * v1.1) as f64).sqrt();
        let det = v1.det(v2) as f64;
        det / l1
    }
    fn contains_point(&self, p: Point<i64>) -> bool {
        let d = self.1 - self.0;
        let e = p - self.0;
        d.1 * e.0 == d.0 * e.1
    }
}
impl LineAPI<f64> for Line<f64> {
    fn distance(&self, p: Point<f64>) -> f64 {
        let v1 = self.1 - self.0;
        let v2 = p - self.0;
        let l1 = (v1.0 * v1.0 + v1.1 * v1.1).sqrt();
        let det = v1.det(v2);
        det / l1
    }
    fn contains_point(&self, p: Point<f64>) -> bool {
        let d = self.1 - self.0;
        let e = p - self.0;
        d.1 * e.0 == d.0 * e.1
    }
}
#[cfg(test)]
mod test_plane {
    use crate::geometry::line::Line;
    use crate::geometry::line::LineAPI;
    use crate::geometry::line::Point;
    #[test]
    fn it_works_line_f64() {
        let x = Point(0.0, 0.0);
        let y = Point(2.0, 3.0);
        let line = Line(x, y);
        let z = Point(0.0, 3.0);
        let d = line.distance(z);
        let d_truth = 1.664_100_588_675_687_4;
        let result = (d * 1_000_000_000.0) as i64;
        let expected = (d_truth * 1_000_000_000.0) as i64;
        assert_eq!(result, expected);
    }
    #[test]
    fn it_works_line_i64() {
        let x = Point(0, 0);
        let y = Point(2, 3);
        let line = Line(x, y);
        let z = Point(0, 3);
        let d = line.distance(z);
        let d_truth = 1.664_100_588_675_687_4;
        let result = (d * 1_000_000_000.0) as i64;
        let expected = (d_truth * 1_000_000_000.0) as i64;
        assert_eq!(result, expected);
        assert!(line.contains_point(Point(4, 6)));
        assert!(line.contains_point(Point(-2, -3)));
        assert!(!line.contains_point(Point(1, 1)));
    }
}