// SPDX-License-Identifier: MIT OR Apache-2.0
// Copyright 2024 René Ladan <rene0+codeberg@freedom.nl>

use radio_datetime_utils::{
    DST_ANNOUNCED, DST_PROCESSED, DST_SUMMER, LEAP_ANNOUNCED, LEAP_MISSING, LEAP_PROCESSED,
};

use dcf77_utils::DCF77Utils;

// quick and dirty parsing function
fn parse_dst(dst: Option<u8>) -> String {
    if dst.is_none() {
        return String::from("*");
    }
    let mut res = String::from("");
    let s_dst = dst.unwrap();
    if s_dst & DST_ANNOUNCED != 0 {
        res += "announced ";
    }
    if s_dst & DST_PROCESSED != 0 {
        res += "processed ";
    }
    if s_dst & DST_SUMMER != 0 {
        res += "summer";
    } else {
        res += "winter";
    }
    res
}

fn str_weekday(day: Option<u8>) -> String {
    String::from(match day {
        Some(0) => "?",
        Some(1) => "Monday",
        Some(2) => "Tuesday",
        Some(3) => "Wednesday",
        Some(4) => "Thursday",
        Some(5) => "Friday",
        Some(6) => "Saturday",
        Some(7) => "Sunday",
        None => "None",
        _ => "<panic>",
    })
}

fn parse_leapsecond(ls: Option<u8>, is_one: Option<bool>) -> String {
    if ls.is_none() {
        return String::from("*");
    }
    let mut res = String::from("");
    let s_ls = ls.unwrap();
    if s_ls & LEAP_ANNOUNCED != 0 {
        res += "announced ";
    }
    if s_ls & LEAP_PROCESSED != 0 {
        res += "processed ";
        res += match is_one {
            Some(true) => " 1-instead-of-0 ",
            Some(false) => "",
            None => "*",
        }
    }
    if s_ls & LEAP_MISSING != 0 {
        res += "missing";
    }

    res
}

fn main() {
    // Pretend to do live decoding, e.g. by detecting the time differences in microseconds from
    // edges read from a GPIO pin. Samples need to be in absolute time since some point, not in
    // relative time to each other. Format is (time-in-us-since-some-point, edge-becomes-high).
    // The boolean value is the inverse of the radio signal (see
    //   https://en.wikipedia.org/wiki/DCF77#/media/File:DCF77_code.svg )
    const SAMPLES: [(u32, bool); 122] = [
        (419878222, true),
        (419994127, false),
        (421879420, true),
        (421993909, false),
        (422878486, true),
        (423096680, false),
        (423878635, true),
        (423996148, false),
        (424879214, true),
        (424995340, false),
        (425879677, true),
        (426096537, false),
        (426879389, true),
        (427098425, false),
        (427879069, true),
        (428098592, false),
        (428878142, true),
        (429097255, false),
        (429880457, true),
        (430094647, false),
        (430878441, true),
        (431101211, false),
        (431879863, true),
        (431995444, false),
        (432880438, true),
        (433094660, false),
        (433880659, true),
        (434097586, false),
        (434878947, true),
        (434994297, false),
        (435879906, true),
        (436095402, false),
        (436879753, true),
        (436993732, false),
        (437879570, true),
        (437993803, false),
        (438879730, true),
        (438993954, false),
        (439879587, true),
        (440097608, false),
        (440879385, true),
        (440996300, false),
        (441879265, true),
        (442098812, false),
        (442879414, true),
        (443097163, false),
        (443879871, true),
        (444098379, false),
        (444879431, true),
        (445096020, false),
        (445879087, true),
        (445995405, false),
        (446879690, true),
        (447093251, false),
        (447879256, true),
        (447995003, false),
        (448878561, true),
        (449095092, false),
        (449879350, true),
        (450099078, false),
        (450879372, true),
        (450993982, false),
        (451879342, true),
        (452098213, false),
        (452878519, true),
        (452995944, false),
        (453878657, true),
        (453993212, false),
        (454879919, true),
        (455097547, false),
        (455879782, true),
        (455996723, false),
        (456879091, true),
        (456995262, false),
        (457879629, true),
        (458096555, false),
        (458880213, true),
        (458996974, false),
        (459879878, true),
        (460099002, false),
        (460878999, true),
        (460996136, false),
        (461878396, true),
        (461994434, false),
        (462880614, true),
        (462993996, false),
        (463879321, true),
        (463994609, false),
        (464879642, true),
        (465097262, false),
        (465878747, true),
        (466099624, false),
        (466879199, true),
        (467097612, false),
        (467879093, true),
        (467995798, false),
        (468879484, true),
        (468994767, false),
        (469879145, true),
        (469997752, false),
        (470879522, true),
        (471100802, false),
        (471878503, true),
        (471994937, false),
        (472878993, true),
        (473099100, false),
        (473878453, true),
        (473995742, false),
        (474879545, true),
        (474994621, false),
        (475878401, true),
        (475994585, false),
        (476879857, true),
        (477098616, false),
        (477879080, true),
        (477997045, false),
        (478881025, true),
        (478994588, false),
        (479878796, true),
        (479994936, false),
        (481878510, true),
        (481995485, false),
    ];
    let mut dcf77 = DCF77Utils::default();
    for s in SAMPLES {
        dcf77.handle_new_edge(s.1, s.0);
        if s.1 {
            println!("{} {:?}", dcf77.get_second(), dcf77.get_current_bit());
            if !dcf77.increase_second() {
                println!("Bad increase_second at second {}", dcf77.get_old_second());
            }
        }
        if s.0 == 479994936 {
            // Remember, there is no bit at second 59. However, we still need to call
            // increase_second() here (halfway the minute marker) to let get_second()
            // show the correct value and to pass checks in decode_time()
            println!("* {} {:?}", dcf77.get_second(), dcf77.get_current_bit());
            if !dcf77.increase_second() {
                println!("Bad increase_second at second {}", dcf77.get_old_second());
            }
        }
        if s.1 && dcf77.is_new_minute() {
            println!("New minute! Time to decode!");
            dcf77.decode_time(true, true);
            println!("Bit 0={:?}", dcf77.get_bit_0());
            println!(
                "Third party bits (hex)={:x?}",
                dcf77.get_third_party_buffer()
            );
            println!("Call bit={:?}", dcf77.get_call_bit());
            println!("Bit 20={:?}", dcf77.get_bit_20());
            println!(
                "Parities={:?} {:?} {:?}",
                dcf77.get_parity_1(),
                dcf77.get_parity_2(),
                dcf77.get_parity_3()
            );
            let rdt = dcf77.get_radio_datetime();
            println!(
                "Date/time={:?}-{:?}-{:?} {:?}:{:?} {} {} {}",
                rdt.get_year(),
                rdt.get_month(),
                rdt.get_day(),
                rdt.get_hour(),
                rdt.get_minute(),
                str_weekday(rdt.get_weekday()),
                parse_dst(rdt.get_dst()),
                parse_leapsecond(rdt.get_leap_second(), dcf77.leap_second_is_one())
            );
        }
    }
}
