Documentation
use std::any::Any;
use std::collections::VecDeque;
use std::sync::Arc;
use crate::{Event, EventSchedule};
use crate::event::EventOnce;

#[derive(Debug,Default)]
pub struct Context{
    input: Option<Box<dyn Any + Send + Sync + 'static>>,
    events:VecDeque<Arc<dyn Event+Send+'static>>,
    once_events:VecDeque<Box<dyn EventOnce+Send+'static>>,
    is_abort:bool,
}

impl Context {
    pub async fn new<T>(input:T,trigger:&[u8],schedule:&EventSchedule)->Self
        where
            T:Send+Sync+'static,
    {
        let mut this = Self{
            input:Some(Box::new(input)),
            events:VecDeque::new(),
            once_events:VecDeque::new(),
            is_abort:false,
        };
        this.init(trigger,schedule).await;
        this
    }
    pub fn is_empty_input(&self) -> bool {
        self.input.is_none()
    }
    pub fn set_input<T:Send+Sync+'static>(&mut self,input:T){
        self.input = Some(Box::new(input));
    }
    pub async fn init(&mut self,trigger:&[u8],schedule:&EventSchedule){
        self.events = schedule.raw_load_events(trigger).await.into();
        self.once_events = schedule.raw_load_once_events(trigger).into();
    }
    pub fn try_into_inner<T:'static>(&mut self)->Option<T>
    {
        let input = if let Some(ref input) = self.input{
            if input.downcast_ref::<T>().is_some() {
                self.input.take().unwrap()
            }else{
                return None
            }
        }else{
            return None
        };
        Some(*input.downcast::<T>().unwrap())
    }

    // 向下调度
    pub async fn raw_next(&mut self)->anyhow::Result<()>{
        loop {
            if self.is_abort {
                return Ok(())
            }
            if let Some(event) = self.events.pop_front() {
                event.call(self).await?;
            }else if let Some(event) = self.once_events.pop_front() {
                event.call(self).await?;
            }else{
                break;
            }
        }
        Ok(())
    }
    // 扩展
    pub async fn next<T:Send+Sync+'static>(&mut self,input:T)->anyhow::Result<()>{
        self.set_input(input);
        self.raw_next().await
    }

    pub fn deref_fn<T:Any,Out>(&self,handle:impl FnOnce(Option<&T>)->Out)->Out{
        if let Some(ref input) = self.input{
            if let Some(input) = input.downcast_ref::<T>() {
                return handle(Some(input))
            }
        }
        handle(None)
    }
    pub fn deref_fn_mut<T:Any,Out>(&mut self,handle:impl FnOnce(Option<&mut T>)->Out)->Out{
        if let Some(ref mut input) = self.input{
            if let Some(input) = input.downcast_mut::<T>() {
                return handle(Some(input))
            }
        }
        handle(None)
    }
    pub fn abort(&mut self){
        self.is_abort = true;
    }
}