1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use super::HtmlNode;
use crate::html_prefab::BasicHtmlPrefab;
use crate::HtmlRenderer;
use crate::{Html, HtmlPrefab, VNode};
use kagura::component::{Render, Update};
use kagura::node::{
    BasicComponentState, BasicNodeMsg, FutureMsg, Msg, RenderNode, SubHandler, UpdateNode,
};
use std::collections::VecDeque;
use std::pin::Pin;

pub struct BasicHtmlNode<This: Render<Html> + Update + 'static> {
    state: BasicComponentState<This>,
    html_renderer: HtmlRenderer<This>,
    index_id: Option<String>,
}

impl<This: Render<Html> + Update> BasicHtmlNode<This> {
    pub fn new(
        index_id: Option<String>,
        sub_handler: Option<SubHandler<This>>,
        state: Pin<Box<This>>,
        children: This::Children,
    ) -> Self {
        let mut html_renderer = HtmlRenderer::new();
        html_renderer.set_children(children);
        Self {
            state: BasicComponentState::new(state, sub_handler),
            html_renderer,
            index_id,
        }
    }
}

impl<This: Render<Html> + Update> UpdateNode for BasicHtmlNode<This> {
    fn update(&mut self, mut msg: Msg) -> VecDeque<FutureMsg> {
        if msg.target() == self.state.target_id() {
            if let Some(msg) = msg
                .take()
                .and_then(|msg| msg.downcast::<BasicNodeMsg<This>>().ok())
            {
                self.state.update(*msg)
            } else {
                VecDeque::new()
            }
        } else {
            self.html_renderer.update(msg)
        }
    }
}

impl<This: Render<Html> + Update> RenderNode<(VecDeque<VNode>, VecDeque<FutureMsg>)>
    for BasicHtmlNode<This>
{
    fn render(&mut self) -> (VecDeque<VNode>, VecDeque<FutureMsg>) {
        self.html_renderer.render(&self.state)
    }
}

impl<This: Render<Html> + Update> HtmlNode for BasicHtmlNode<This> {
    fn is(&self, prefab: &dyn HtmlPrefab) -> bool {
        compare_node_and_prefab::<This>(
            &self.index_id,
            prefab.component_type_id(),
            prefab.index_id(),
        )
    }

    fn on_assemble(&mut self) -> VecDeque<FutureMsg> {
        self.state.on_assemble()
    }

    fn update_by_prefab(&mut self, prefab: Box<dyn HtmlPrefab>) -> VecDeque<FutureMsg> {
        if self.is(prefab.as_ref()) {
            if let Ok(prefab) = prefab.into_any().downcast::<BasicHtmlPrefab<This>>() {
                let (props, index_id, sub_handler, children) = prefab.into_data();
                self.index_id = index_id;
                self.html_renderer.set_children(children);
                self.state.set_sub_handler(sub_handler);
                return self.state.on_load(props);
            }
        }
        VecDeque::new()
    }
}

pub fn compare_node_and_prefab<This: Update + Render<Html> + 'static>(
    this_index_id: &Option<String>,
    component_type_id: std::any::TypeId,
    index_id: &Option<String>,
) -> bool {
    if std::any::TypeId::of::<This>() == component_type_id {
        return *this_index_id == *index_id;
    } else {
        false
    }
}