use std::cmp::min;
use anyhow::{anyhow, Result};
use chrono::NaiveTime;
use itertools::Itertools;
use ordered_float::NotNan;
use super::time::time_to_day_fraction;
use crate::wallpaper::properties::TimeItem;
pub fn current_image_index_h24(time_items: &[TimeItem], time: NaiveTime) -> Result<usize> {
Ok(current_item_h24(time_items, time)?.index)
}
fn current_item_h24(time_items: &[TimeItem], time: NaiveTime) -> Result<&TimeItem> {
let current_time_fraction = not_nan!(time_to_day_fraction(time));
time_items
.iter()
.min_by_key(|item| times_distance(item.time, current_time_fraction))
.ok_or_else(|| anyhow!("no time items to choose from"))
}
fn times_distance(a: NotNan<f64>, b: NotNan<f64>) -> NotNan<f64> {
let first_distance = not_nan!((a - b).abs());
let second_distance = not_nan!(1.0) - first_distance;
min(first_distance, second_distance)
}
pub fn get_image_index_order_h24(time_items: &[TimeItem]) -> Vec<usize> {
sort_time_items(time_items)
.iter()
.map(|item| item.index)
.collect_vec()
}
pub fn sort_time_items(time_items: &[TimeItem]) -> Vec<&TimeItem> {
time_items
.iter()
.sorted_by_key(|item| item.time)
.collect_vec()
}
#[cfg(test)]
mod tests {
use rstest::*;
use super::*;
const HOUR_VALUE: f64 = 1.0 / 24.0;
#[fixture]
#[rustfmt::skip]
fn time_items_1() -> Vec<TimeItem> {
vec![
TimeItem { index: 2, time: not_nan!(05.0 * HOUR_VALUE) },
TimeItem { index: 0, time: not_nan!(01.0 * HOUR_VALUE) },
TimeItem { index: 1, time: not_nan!(04.0 * HOUR_VALUE) },
TimeItem { index: 4, time: not_nan!(22.0 * HOUR_VALUE) },
TimeItem { index: 3, time: not_nan!(12.0 * HOUR_VALUE) },
]
}
#[fixture]
#[rustfmt::skip]
fn time_items_2() -> Vec<TimeItem> {
vec![
TimeItem { index: 0, time: not_nan!(06.0 * HOUR_VALUE) },
TimeItem { index: 1, time: not_nan!(23.0 * HOUR_VALUE) },
]
}
#[rstest]
#[case("00:00:00", 0)]
#[case("00:20:00", 0)]
#[case("03:30:00", 1)]
#[case("04:00:00", 1)]
#[case("04:29:00", 1)]
#[case("04:31:00", 2)]
#[case("05:00:00", 2)]
#[case("05:30:00", 2)]
#[case("05:30:00", 2)]
#[case("20:00:00", 4)]
#[case("23:00:00", 4)]
#[case("23:59:00", 0)] fn test_current_image_index_h24_1(
time_items_1: Vec<TimeItem>,
#[case] time: NaiveTime,
#[case] expected_index: usize,
) {
let result = current_image_index_h24(&time_items_1, time);
assert_eq!(result.unwrap(), expected_index);
}
#[rstest]
#[case("01:00:00", 1)] #[case("03:00:00", 0)]
#[case("12:00:00", 0)]
fn test_current_image_index_h24_2(
time_items_2: Vec<TimeItem>,
#[case] time: NaiveTime,
#[case] expected_index: usize,
) {
let result = current_image_index_h24(&time_items_2, time);
assert_eq!(result.unwrap(), expected_index);
}
#[rstest]
fn test_get_image_index_order_h24(time_items_1: Vec<TimeItem>) {
let result = get_image_index_order_h24(&time_items_1);
assert_eq!(result, &[0, 1, 2, 3, 4]);
}
}