// Create a virtual force feedback device, just while this is running.

use evdev::{
    uinput::VirtualDevice, AttributeSet, EventSummary, FFEffectCode, FFStatusCode, InputEvent,
    UInputCode,
};
use std::collections::BTreeSet;

fn main() -> std::io::Result<()> {
    let mut device = VirtualDevice::builder()?
        .name("Fake Force Feedback")
        .with_ff(&AttributeSet::from_iter([FFEffectCode::FF_RUMBLE]))?
        .with_ff_effects_max(16)
        .build()?;

    for path in device.enumerate_dev_nodes_blocking()? {
        let path = path?;
        println!("Available as {}", path.display());
    }

    let mut ids: BTreeSet<u16> = (0..16).collect();

    println!("Waiting for Ctrl-C...");
    loop {
        let events: Vec<InputEvent> = device.fetch_events()?.collect();

        const STOPPED: i32 = FFStatusCode::FF_STATUS_STOPPED.0 as i32;
        const PLAYING: i32 = FFStatusCode::FF_STATUS_PLAYING.0 as i32;

        for event in events {
            match event.destructure() {
                EventSummary::UInput(event, UInputCode::UI_FF_UPLOAD, ..) => {
                    let mut event = device.process_ff_upload(event)?;
                    let id = ids.iter().next().copied();
                    match id {
                        Some(id) => {
                            ids.remove(&id);
                            event.set_effect_id(id as i16);
                            event.set_retval(0);
                        }
                        None => {
                            event.set_retval(-1);
                        }
                    }
                    println!("upload effect {:?}", event.effect());
                }
                EventSummary::UInput(event, UInputCode::UI_FF_ERASE, ..) => {
                    let event = device.process_ff_erase(event)?;
                    ids.insert(event.effect_id() as u16);
                    println!("erase effect ID = {}", event.effect_id());
                }
                EventSummary::ForceFeedback(.., effect_id, STOPPED) => {
                    println!("stopped effect ID = {}", effect_id.0);
                }
                EventSummary::ForceFeedback(.., effect_id, PLAYING) => {
                    println!("playing effect ID = {}", effect_id.0);
                }
                _ => {
                    println!("event = {:?}", event);
                }
            };
        }
    }
}
