use std::sync::Arc;
use std::time::Duration;
use async_trait::async_trait;
use either::Either;
use eyre::Result;
use makeup_console::Keypress;
use tokio::sync::mpsc::UnboundedSender;
use tokio::sync::Mutex;
use crate::post_office::PostOffice;
use crate::{Coordinates, Dimensions, DrawCommand};
pub type Key = u64;
pub type DrawCommandBatch = (Key, Vec<DrawCommand>);
pub type RawComponentMessage<M> = Either<M, MakeupMessage>;
pub type ExtractMessageFromComponent<C> = <C as Component>::Message;
pub type ComponentMessage<C> = RawComponentMessage<ExtractMessageFromComponent<C>>;
pub type Mailbox<C> = Vec<ComponentMessage<C>>;
pub type ContextTx<M> = Arc<Mutex<UnboundedSender<(Key, M)>>>;
#[derive(Debug)]
pub struct UpdateContext<'a, M: std::fmt::Debug + Send + Sync + Clone + 'a> {
pub post_office: &'a mut PostOffice<M>,
pub tx: ContextTx<RawComponentMessage<M>>,
pub focus: Key,
}
#[derive(Debug, Clone)]
pub struct RenderContext {
pub last_frame_time: Option<Duration>,
pub frame_counter: u128,
pub fps: f64,
pub effective_fps: f64,
pub cursor: Coordinates,
pub dimensions: Dimensions,
pub focus: Key,
}
#[derive(Debug, Clone)]
pub enum MakeupMessage {
TimerTick(Duration),
TextUpdate(String),
Keypress(Keypress),
}
#[async_trait]
pub trait Component: std::fmt::Debug + Send + Sync {
type Message: std::fmt::Debug + Send + Sync + Clone;
fn children(&self) -> Option<Vec<&dyn Component<Message = Self::Message>>>;
async fn update(
&mut self,
ctx: &mut UpdateContext<ExtractMessageFromComponent<Self>>,
) -> Result<()>;
async fn render(&self, ctx: &RenderContext) -> Result<DrawCommandBatch>;
async fn update_pass(
&mut self,
ctx: &mut UpdateContext<ExtractMessageFromComponent<Self>>,
) -> Result<()>;
async fn render_pass(&self, ctx: &RenderContext) -> Result<Vec<DrawCommandBatch>>;
fn key(&self) -> Key;
}
pub fn generate_key() -> Key {
rand::random::<Key>()
}