use enum_dispatch::enum_dispatch;
use std::sync::Arc;
use uuid::Uuid;
use crate::config::{DEFAULT_DIM, DEFAULT_FPS, DEFAULT_SRC_LEN};
use super::attrs::Attrs;
use super::frame::Frame;
use super::keys::{
A_FPS, A_FRAME, A_HEIGHT, A_IN, A_OUT, A_SRC_LEN, A_TRIM_IN, A_TRIM_OUT, A_WIDTH,
};
use super::traits::{FrameCache, WorkerPool};
pub struct ComputeContext<'a> {
pub cache: &'a dyn FrameCache,
pub cache_arc: Option<Arc<dyn FrameCache + Send + Sync>>,
pub media: &'a std::collections::HashMap<Uuid, Arc<super::node_kind::NodeKind>>,
pub media_arc: Option<std::sync::Arc<std::sync::RwLock<std::collections::HashMap<Uuid, Arc<super::node_kind::NodeKind>>>>>,
pub workers: Option<&'a dyn WorkerPool>,
pub epoch: u64,
}
#[enum_dispatch]
pub trait Node: Send + Sync {
fn uuid(&self) -> Uuid;
fn name(&self) -> &str;
fn node_type(&self) -> &'static str;
fn attrs(&self) -> &Attrs;
fn attrs_mut(&mut self) -> &mut Attrs;
fn inputs(&self) -> Vec<Uuid>;
fn compute(&self, frame: i32, ctx: &ComputeContext) -> Option<Frame>;
fn is_dirty(&self, ctx: Option<&ComputeContext>) -> bool;
fn mark_dirty(&self);
fn clear_dirty(&self);
fn preload(&self, _center: i32, _radius: i32, _ctx: &ComputeContext) {
}
fn get_attr(&self, key: &str) -> Option<&super::attrs::AttrValue> {
self.attrs().get(key)
}
fn set_attr(&mut self, key: &str, value: super::attrs::AttrValue) {
self.attrs_mut().set(key, value);
}
fn get_i32(&self, key: &str) -> Option<i32> {
self.attrs().get_i32(key)
}
fn get_float(&self, key: &str) -> Option<f32> {
self.attrs().get_float(key)
}
fn get_str(&self, key: &str) -> Option<&str> {
self.attrs().get_str(key)
}
fn get_uuid_attr(&self, key: &str) -> Option<Uuid> {
self.attrs().get_uuid(key)
}
fn play_range(&self, _use_work_area: bool) -> (i32, i32) {
(self.attrs().layer_start(), self.attrs().layer_end())
}
fn bounds(&self, use_trim: bool, _selection_only: bool, _media: &std::collections::HashMap<Uuid, Arc<super::node_kind::NodeKind>>) -> (i32, i32) {
self.play_range(use_trim)
}
fn _in(&self) -> i32 {
self.attrs().get_i32(A_IN).unwrap_or(0)
}
fn _out(&self) -> i32 {
self.attrs().get_i32(A_OUT).unwrap_or_else(|| {
self.attrs().get_i32(A_SRC_LEN).unwrap_or(DEFAULT_SRC_LEN)
})
}
fn fps(&self) -> f32 {
self.attrs().get_float(A_FPS).unwrap_or(DEFAULT_FPS)
}
fn frame(&self) -> i32 {
self.attrs().get_i32(A_FRAME).unwrap_or_else(|| self._in())
}
fn work_area(&self) -> (i32, i32) {
let trim_in = self.attrs().get_i32(A_TRIM_IN).unwrap_or(0);
let trim_out = self.attrs().get_i32(A_TRIM_OUT).unwrap_or(0);
(self._in() + trim_in, self._out() - trim_out)
}
fn frame_count(&self) -> i32 {
(self._out() - self._in() + 1).max(0)
}
fn play_frame_count(&self) -> i32 {
let (start, end) = self.work_area();
(end - start + 1).max(0)
}
fn dim(&self) -> (usize, usize) {
let w = self.attrs().get_u32(A_WIDTH).unwrap_or(DEFAULT_DIM.0 as u32) as usize;
let h = self.attrs().get_u32(A_HEIGHT).unwrap_or(DEFAULT_DIM.1 as u32) as usize;
(w.max(1), h.max(1))
}
fn placeholder_frame(&self) -> Frame {
let (w, h) = self.dim();
Frame::placeholder(w, h)
}
}