use boostvoronoi::prelude as BV;
use boostvoronoi::prelude::*;

mod common;
use common::to_segments;

type I = i32;

fn retrieve_point<T: InputType>(
    point_data_: &[Point<T>],
    segment_data_: &[Line<T>],
    source: (BV::SourceIndex, SourceCategory),
) -> Point<T> {
    let source_index = source.0.usize();
    match source.1 {
        SourceCategory::SinglePoint => point_data_[source_index],
        SourceCategory::SegmentStart => segment_data_[source_index - point_data_.len()].start,
        SourceCategory::Segment | SourceCategory::SegmentEnd => {
            segment_data_[source_index - point_data_.len()].end
        }
    }
}

#[test]
fn segment_4_1() -> Result<(), BvError> {
    let _output = {
        let segments = to_segments(&[
            [200, 200, 200, 400],
            [200, 400, 400, 400],
            [400, 400, 400, 200],
            [400, 200, 200, 200],
            [529, 242, 367, 107],
            [94, 628, 512, 632],
            [680, 608, 669, 291],
            [572, 96, 363, 51],
            [147, 103, 96, 170],
        ]);

        Builder::<I>::default()
            .with_segments(segments.iter())?
            .build()?
    };
    for v in _output.vertices().iter() {
        assert!(!v.x().is_nan());
        assert!(!v.y().is_nan());
    }
    Ok(())
}

#[test]
fn vertical_segment_1() -> Result<(), BvError> {
    let v = Vec::<Point<I>>::default();
    let s = to_segments::<I>(&[
        [200, 200, 200, 400],
        [94, 628, 512, 632],
        [147, 103, 96, 170],
    ]);

    let output = Builder::<I>::default()
        .with_vertices(v.iter())?
        .with_segments(s.iter())?
        .build()?;

    for v in output.vertices().iter() {
        assert!(!v.x().is_nan());
        assert!(!v.y().is_nan());
    }

    assert_eq!(output.cells().len(), 9);
    let cell = output.cells()[0];
    assert_eq!(cell.id(), 0);
    let (source_index, cat) = cell.source_index_2();
    let p = retrieve_point(&v, &s, (source_index, cat));
    assert_eq!(p, Point { x: 94, y: 628 });
    assert!(!cell.is_degenerate());
    assert!(cell.contains_point());
    assert!(!cell.contains_segment());
    let cell = output.cells()[1];
    assert_eq!(cell.id(), 1);
    let (source_index, cat) = cell.source_index_2();
    assert_eq!(cat, SourceCategory::Segment);
    let p = retrieve_point(&v, &s, (source_index, cat));
    assert_eq!(p, Point { x: 512, y: 632 });
    assert!(!cell.is_degenerate());
    assert!(!cell.contains_point());
    assert!(cell.contains_segment());
    let cell = output.cells()[2];
    assert_eq!(cell.id(), 2);
    let (source_index, cat) = cell.source_index_2();
    let p = retrieve_point(&v, &s, (source_index, cat));
    assert_eq!(p, Point { x: 96, y: 170 });
    assert!(!cell.is_degenerate());
    assert!(cell.contains_point());
    assert!(!cell.contains_segment());
    let cell = output.cells()[3];
    assert_eq!(cell.id(), 3);
    let (source_index, cat) = cell.source_index_2();
    assert_eq!(cat, SourceCategory::Segment);
    let p = retrieve_point(&v, &s, (source_index, cat));
    assert_eq!(p, Point { x: 96, y: 170 });
    assert!(!cell.is_degenerate());
    assert!(!cell.contains_point());
    assert!(cell.contains_segment());
    let cell = output.cells()[4];
    assert_eq!(cell.id(), 4);
    let (source_index, cat) = cell.source_index_2();
    let p = retrieve_point(&v, &s, (source_index, cat));
    assert_eq!(p, Point { x: 147, y: 103 });
    assert!(!cell.is_degenerate());
    assert!(cell.contains_point());
    assert!(!cell.contains_segment());
    let cell = output.cells()[5];
    assert_eq!(cell.id(), 5);
    let (source_index, cat) = cell.source_index_2();
    let p = retrieve_point(&v, &s, (source_index, cat));
    assert_eq!(p, Point { x: 200, y: 200 });
    assert!(!cell.is_degenerate());
    assert!(cell.contains_point());
    assert!(!cell.contains_segment());
    let cell = output.cells()[6];
    assert_eq!(cell.id(), 6);
    let (source_index, cat) = cell.source_index_2();
    assert_eq!(cat, SourceCategory::Segment);
    let p = retrieve_point(&v, &s, (source_index, cat));
    assert_eq!(p, Point { x: 200, y: 400 });
    assert!(!cell.is_degenerate());
    assert!(!cell.contains_point());
    assert!(cell.contains_segment());
    let cell = output.cells()[7];
    assert_eq!(cell.id(), 7);
    let (source_index, cat) = cell.source_index_2();
    let p = retrieve_point(&v, &s, (source_index, cat));
    assert_eq!(p, Point { x: 200, y: 400 });
    assert!(!cell.is_degenerate());
    assert!(cell.contains_point());
    assert!(!cell.contains_segment());
    let cell = output.cells()[8];
    assert_eq!(cell.id(), 8);
    let (source_index, cat) = cell.source_index_2();
    let p = retrieve_point(&v, &s, (source_index, cat));
    assert_eq!(p, Point { x: 512, y: 632 });
    assert!(!cell.is_degenerate());
    assert!(cell.contains_point());
    assert!(!cell.contains_segment());
    assert_eq!(output.vertices().len(), 10);
    assert_eq!(output.edges().len(), 36);
    /*let v = output.vertices()[0].get();
    assert!(almost_equal(v.x(), 143.7970909, v.y(), 200.0000000));
    assert_eq!(v.get_incident_edge().unwrap(),13);
    let v = output.vertices()[1].get();
    assert!(almost_equal(v.x(), 142.0840045, v.y(), 205.0788691));
    assert_eq!(v.get_incident_edge().unwrap(),15);
    let v = output.vertices()[2].get();
    assert!(almost_equal(v.x(), -102.2273417, v.y(), 398.1387452));
    assert_eq!(v.get_incident_edge().unwrap(),17);
    let v = output.vertices()[3].get();
    assert!(almost_equal(v.x(), -98.2075472, v.y(), 400.0000000));
    assert_eq!(v.get_incident_edge().unwrap(),21);
    let v = output.vertices()[4].get();
    assert!(almost_equal(v.x(), 95.3208257, v.y(), 489.9737172));
    assert_eq!(v.get_incident_edge().unwrap(),23);
    let v = output.vertices()[5].get();
    assert!(almost_equal(v.x(), 195.1646270, v.y(), 139.6626265));
    assert_eq!(v.get_incident_edge().unwrap(),25);
    let v = output.vertices()[6].get();
    assert!(almost_equal(v.x(), 431.2163645, v.y(), 400.0000000));
    assert_eq!(v.get_incident_edge().unwrap(),29);
    let v = output.vertices()[7].get();
    assert!(almost_equal(v.x(), 515.0143534, v.y(), 317.0000690));
    assert_eq!(v.get_incident_edge().unwrap(),31);
    let v = output.vertices()[8].get();
    assert!(almost_equal(v.x(), 655.0769231, v.y(), 200.0000000));
    assert_eq!(v.get_incident_edge().unwrap(),33);
    let v = output.vertices()[9].get();
    assert!(almost_equal(v.x(), 2427.4071661, v.y(), -1080.0162866));
    assert_eq!(v.get_incident_edge().unwrap(),35);*/
    Ok(())
}

#[test]
/// This used to give NaN coordinates in some vertexes
fn segment_4_2() -> Result<(), BvError> {
    let _output = {
        let segments: [[I; 4]; 7] = [
            [-19546, 47259, -45936, 36666],
            [-45936, 36666, -59968, -21417],
            [-59968, -21417, -125257, -19781],
            [-125257, -19781, -148480, -47150],
            [-148480, -47150, 148480, -57522],
            [148480, -57522, 105345, 58720],
            [105345, 58720, -19546, 47259],
        ];

        Builder::<I>::default()
            .with_segments(segments.iter())?
            .build()?
    };
    for v in _output.vertices().iter() {
        assert!(!v.x().is_nan());
        assert!(!v.y().is_nan());
    }
    Ok(())
}
