use std::collections::BTreeMap;
use ordered_float::OrderedFloat;

pub fn closest_key<V>(map: &BTreeMap<OrderedFloat<f64>, V>, val: f64) -> Option<(OrderedFloat<f64>, f64)> {
    let mut r1 = map.range(OrderedFloat(val)..);
    let r2 = map.range(..=OrderedFloat(val));
    let o1 = r1.next();
    let o2 = r2.last();
    match (o1, o2) {
        (None, None) => {
            None
        },
        (Some(i), None) => {
            Some((*i.0, (*i.0 - val).abs()))
        },
        (None, Some(i)) => {
            Some((*i.0, (*i.0 - val).abs()))
        },
        (Some(i1), Some(i2)) => {
            // abs(f - i)
            let i1_dist = (i1.0 - val).abs();
            let i2_dist = (i2.0 - val).abs();
            Some(if i1_dist < i2_dist {
                (*i1.0, i1_dist)
            } else {
                (*i2.0, i2_dist)
            })
        }
    }
}

pub fn lookup<V>(map: &BTreeMap<OrderedFloat<f64>, V>, val: f64) -> Option<&V> {
    let mut r1 = map.range(OrderedFloat(val)..);
    let mut r2 = map.range(..OrderedFloat(val));
    let o1 = r1.next();
    let o2 = r2.next();
    match (o1, o2) {
        (None, None) => None,
        (Some(i), None) => Some(i.1),
        (None, Some(i)) => Some(i.1),
        (Some(i1), Some(i2)) => {
            // abs(f - i)
            let i1_dist = (i1.0 - val).abs();
            let i2_dist = (i2.0 - val).abs();
            Some(if i1_dist < i2_dist {
                i1.1
            } else {
                i2.1
            })
        }
    }
}


pub type LookupTable2D = BTreeMap<OrderedFloat<f64>, BTreeMap<OrderedFloat<f64>, f64>>;
