//! Blinks an LED
//!
//! This assumes that a LED is connected to GPIO4.
//! Depending on your target and the board you are using you should change the pin.
//! If your board doesn't have on-board LEDs don't forget to add an appropriate resistor.
//!

#![no_std]
#![no_main]


use esp32c3_hal::{
    clock::ClockControl,
    pac::Peripherals,
    gpio_types::*,
    gpio::*,
    prelude::*,
    spi,
    timer::TimerGroup,
    Rtc,
    IO,
    Delay,
};
/* Display and graphics */
use ili9341::{DisplaySize240x320, Ili9341, Orientation};

use display_interface_spi::SPIInterfaceNoCS;
use embedded_graphics::mono_font::MonoTextStyle;
use embedded_graphics::pixelcolor::*;
use embedded_graphics::prelude::*;
use embedded_graphics::primitives::*;
use embedded_graphics::text::*;
use embedded_graphics::image::Image;
use embedded_graphics::geometry::*;
use embedded_graphics::draw_target::DrawTarget;
use embedded_hal;

use riscv_rt;
use riscv_rt::entry;

use esp_println::println;
use esp_backtrace as _;

pub enum KalugaOrientation {
    Portrait,
    PortraitFlipped,
    Landscape,
    LandscapeVericallyFlipped,
    LandscapeFlipped,
}

impl ili9341::Mode for KalugaOrientation {
    fn mode(&self) -> u8 {
        match self {
            Self::Portrait => 0,
            Self::LandscapeVericallyFlipped => 0x20,
            Self::Landscape => 0x20 | 0x40,
            Self::PortraitFlipped => 0x80 | 0x40,
            Self::LandscapeFlipped => 0x80 | 0x20 | 0x08,
        }
    }

    fn is_landscape(&self) -> bool {
        matches!(self, Self::Landscape | Self::LandscapeFlipped | Self::LandscapeVericallyFlipped)
    }
}

#[derive(Copy, Clone, PartialEq)]
pub enum Event {
    Pressed,
    Released,
    Nothing,
}
#[derive(Copy, Clone, PartialEq)]
enum State {
    High(u8),
    Low(u8),
}
pub struct Button<T> {
    button: T,
    state: State,
}
impl<T: ::embedded_hal::digital::v2::InputPin<Error = core::convert::Infallible>> Button<T> {
    pub fn new(button: T) -> Self {
        Button {
            button,
            state: State::High(0),
        }
    }
    pub fn poll(&mut self) -> Event {
        use self::State::*;
        let value = self.button.is_high().unwrap();
        match &mut self.state {
            High(cnt) => {
                if value {
                    *cnt = 0
                } else {
                    *cnt += 1
                }
            }
            Low(cnt) => {
                if value {
                    *cnt += 1
                } else {
                    *cnt = 0
                }
            }
        }
        match self.state {
            High(cnt) if cnt >= 200 => {
                self.state = Low(0);
                Event::Pressed
            }
            Low(cnt) if cnt >= 200 => {
                self.state = High(0);
                Event::Released
            }
            _ => Event::Nothing,
        }
    }
}


#[entry]
fn main() -> ! {

    let peripherals = Peripherals::take().unwrap();
    let mut system = peripherals.SYSTEM.split();

     let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();

    // Disable the RTC and TIMG watchdog timers
    let mut rtc = Rtc::new(peripherals.RTC_CNTL);
    let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
    let mut wdt0 = timer_group0.wdt;
    let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
    let mut wdt1 = timer_group1.wdt;
    
    rtc.rwdt.disable();
    wdt0.disable();
    wdt1.disable();


    println!("About to initialize the SPI LED driver ILI9341");
    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
    
    println!("Hello, world!");

    let mosi = io.pins.gpio7;
    let cs = io.pins.gpio2;
    let rst = io.pins.gpio10;
    let dc = io.pins.gpio3;
    let sck = io.pins.gpio6;
    let miso = io.pins.gpio5;
    let backlight = io.pins.gpio4;

    /* Then set backlight (set_low() - display lights up when signal is in 0, set_high() - opposite case(for example.)) */
    let mut backlight = backlight.into_push_pull_output();
    //backlight.set_low().unwrap();


    /* Configure SPI */
    let spi = spi::Spi::new(
        peripherals.SPI2,
        sck,
        mosi,
        miso,
        cs,
        400u32.MHz(),
        spi::SpiMode::Mode0,
        &mut system.peripheral_clock_control,
        &mut clocks,
    );

    let di = SPIInterfaceNoCS::new(spi, dc.into_push_pull_output());
    let reset = rst.into_push_pull_output();
    let mut delay = Delay::new(&clocks);
   
    // let mut display = Ili9341::new(
    //     di,
    //     reset, 
    //     &mut delay, 
    //     KalugaOrientation::LandscapeFlipped, 
    //     DisplaySize240x320)
    // .unwrap();

    // println!("Display initialised");


    let mut button_green = Button::new(io.pins.gpio0.into_pull_up_input());
    let mut green_cnt = 0;

    loop {
        if let Event::Pressed = button_green.poll()
        {
            println!("KAWABUNGA");
        }
    }
}