use std::iter::Peekable;
use cotis::element_configuring::{ConfigureElements, ConfiguredParentElement, OpenElement};
use cotis::layout::LayoutFrameManager;
use cotis::layout::{LayoutManager, LayoutManagerCompatible};
use crate::serialize_targets::leaf_serialization::LeafConfigListCompatible;
use crate::serialize_targets::{
LeafedInterfaceDeclaration, LeafedInterfaceInstructions, SerializableInterfaceInstructions,
};
pub struct LayoutModuleReplay<Module, ConfigType, List: Copy> {
internal: Module,
declaration: LeafedInterfaceDeclaration<ConfigType, List>,
}
impl<Module, ConfigType, List: Copy> LayoutModuleReplay<Module, ConfigType, List> {
pub fn new(
internal: Module,
declaration: LeafedInterfaceDeclaration<ConfigType, List>,
) -> Self {
Self {
internal,
declaration,
}
}
pub fn replay<'frame, RenderCommandType, Renderer>(
&mut self,
renderer: &mut Renderer,
) -> Vec<RenderCommandType>
where
ConfigType: 'frame + Clone,
RenderCommandType: 'frame,
Module: LayoutManager<'frame, ConfigType, RenderCommandType>
+ LayoutManagerCompatible<Renderer>,
for<'layout> List: LeafConfigListCompatible<Module::ElementConfigurer<'layout>, ConfigType>,
{
self.internal.init(renderer);
self.internal.prepare(renderer);
let mut frame = self.internal.begin_frame();
let mut root = frame.begin();
let mut iter = self.declaration.iter_over();
replay_instructions(&mut iter, &mut root);
root.close_element();
frame.end().collect()
}
}
pub(crate) fn replay_instructions<'a, ConfigType, Configurer, List>(
inst_iter: &mut impl Iterator<
Item = LeafedInterfaceInstructions<&'a SerializableInterfaceInstructions<ConfigType>, List>,
>,
layout: &mut ConfiguredParentElement<'_, Configurer, ConfigType>,
) where
ConfigType: Clone + 'a,
Configurer: ConfigureElements<ConfigType>,
List: Copy + LeafConfigListCompatible<Configurer, ConfigType>,
{
replay_instructions_recursive_parent(&mut inst_iter.peekable(), layout);
}
fn replay_instructions_recursive_parent<'a, ConfigType, Configurer, List>(
inst_iter: &mut Peekable<
impl Iterator<
Item = LeafedInterfaceInstructions<
&'a SerializableInterfaceInstructions<ConfigType>,
List,
>,
>,
>,
layout: &mut ConfiguredParentElement<'_, Configurer, ConfigType>,
) where
ConfigType: Clone + 'a,
Configurer: ConfigureElements<ConfigType>,
List: Copy + LeafConfigListCompatible<Configurer, ConfigType>,
{
while let Some(leafed) = inst_iter.next() {
match leafed.instruction {
SerializableInterfaceInstructions::Open => {
let element = layout.new_element();
replay_instructions_recursive_open(inst_iter, element);
}
SerializableInterfaceInstructions::Close => {
break;
}
SerializableInterfaceInstructions::Configure(_) => {
panic!("Bad replay: cannot configure ConfiguredParentElement");
}
SerializableInterfaceInstructions::LeafConfig(_) => {
panic!("Bad replay: cannot configure ConfiguredParentElement with leaf config");
}
_ => {}
}
}
}
fn replay_instructions_recursive_open<'a, ConfigType, Configurer, List>(
inst_iter: &mut Peekable<
impl Iterator<
Item = LeafedInterfaceInstructions<
&'a SerializableInterfaceInstructions<ConfigType>,
List,
>,
>,
>,
layout: OpenElement<'_, Configurer, ConfigType>,
) where
ConfigType: Clone + 'a,
Configurer: ConfigureElements<ConfigType>,
List: Copy + LeafConfigListCompatible<Configurer, ConfigType>,
{
let mut layout_opt = Some(layout);
let mut parent_opt: Option<ConfiguredParentElement<'_, Configurer, ConfigType>> = None;
while let Some(leafed) = inst_iter.next() {
match leafed.instruction {
SerializableInterfaceInstructions::Configure(c) => {
if let Some(ref mut open) = layout_opt {
open.set_config(c.clone());
}
}
SerializableInterfaceInstructions::LeafConfig(data) => {
if let Some(open) = layout_opt.take() {
List::configure_open(data, open);
}
}
SerializableInterfaceInstructions::Open => {
if parent_opt.is_none()
&& let Some(open) = layout_opt.take()
{
parent_opt = Some(open.make_parent());
}
if let Some(ref mut parent) = parent_opt {
let child_element = parent.new_element();
replay_instructions_recursive_open(inst_iter, child_element);
}
}
SerializableInterfaceInstructions::Close => {
if let Some(parent) = parent_opt.take() {
parent.close_element();
} else if let Some(open) = layout_opt.take() {
open.close_element();
}
break;
}
_ => {}
}
}
}