#![feature(custom_attribute)]
#![feature(fnbox)]

use std::ops::Fn;
use std::net::UdpSocket;
use std::net::{ToSocketAddrs, SocketAddr};
use std::io::Error;
use std::mem;
use std::boxed::FnBox;

pub extern crate osaka_macros;
pub use osaka_macros::osaka;



pub enum Async<Output,Error> {
    Error(Error),
    Ready(Output),

    /// TODO this needs to hold a token for when to retry
    Again,
}

pub trait AsyncIter<Input,Output,Error> {
    fn forward(&mut self, s: &mut Input) -> Async<Output,Error>;
}


use std::marker::PhantomData;
pub struct AsyncIterFnMut<F, Input, Output,Error> (PhantomData<Input>, F) where F: FnMut(&mut Input) -> Async<Output, Error>;

impl<F,Input,Output,Error> AsyncIter<Input,Output,Error> for AsyncIterFnMut<F, Input, Output,Error>
where F: FnMut(&mut Input) -> Async<Output,Error>
{
    fn forward(&mut self, s: &mut Input) -> Async<Output,Error> {
        (self.1)(s)
    }
}


impl <F,Input,Output,Error> AsyncIter<Input,Output,Error> for &mut F
where F: AsyncIter<Input,Output,Error> {
    fn forward(self: &mut Self, s: &mut Input) -> Async<Output,Error> {
        (*self).forward(s)
    }
}


struct NetworkReceiver {
    incomming: Vec<String>
}


impl AsyncIter<(),String,String> for NetworkReceiver{
    fn forward(&mut self, _: &mut ()) -> Async<String, String> {
        // could return Async::Again here with a token

        if self.incomming.len() > 0 {
            Async::Ready(self.incomming.remove(0))
        } else {
            Async::Error("network is EOF".into())
        }
    }
}




fn main () {
    let mut incomming  = NetworkReceiver{incomming:
        vec![
            "i", "am", "kebab",
            "yes", "i", "am", "kebab",
            "sure", "this", "am", "food",
            "my", "name", "is", "willi", "am", "doenerface",
            "am", "i", "food?",
        ].into_iter().map(String::from).collect()
    };
    let mut name = get_the_name2();

    loop {
        let v = name.forward(&mut incomming);
        match v {
            Async::Error(v) => {
                eprintln!("error: {}", v);
                break;
            },
            Async::Ready(v) => println!("{}", v),
            Async::Again => (),
        }
    }
}







fn get_the_name<Input, Error>() -> impl AsyncIter<Input, String, Error>
where
    Input: AsyncIter<(), String, Error>,
    Input: 'static,
    Error: 'static,
{

    let mut __stateful_f : Box<dyn FnMut(&mut Input, *mut u8) -> Async<String, Error>>;

    __stateful_f = Box::new(|net: &mut Input, __stateful_f: *mut u8| {
        let token = match net.forward(&mut ()) {
            Async::Ready(v) => v,
            e => return e,
        };
        if token != "am" {
            return Async::Again;
        }
        let mut collect_that_name = String::new();

        let __stateful_f : &mut Option<Box<dyn FnMut(&mut Input, *mut u8) -> Async<String, Error>>>  = unsafe {
            mem::transmute(__stateful_f)
        };


        *__stateful_f = Some(Box::new(move |net: &mut Input, __stateful_f: *mut u8|{
            let token = match net.forward(&mut ()) {
                Async::Ready(v) => v,
                e => return e,
            };
            collect_that_name += &token;
            Async::Ready(collect_that_name.clone())
        }));
        Async::Again

        /*


        Box::new(move |net: &mut Input|{
            let token = match net.forward(&mut ()) {
                Async::Ready(v) => v,
                e => return Either::B(e),
            };
            collect_that_name += &token;

            Either::A(Box::new(move |net: &mut Input|{
                let token = match net.forward(&mut ()) {
                    Async::Ready(v) => v,
                    e => return Either::B(e),
                };
                collect_that_name += &token;
                Either::B(Async::Ready(collect_that_name))
            })) as Either<Box<FnBox(&mut Input) -> Either<Box<_>,_>>, _>
        }))  as Either<Box<FnBox(&mut Input) -> Either<Box<_>,_>>, _>

        */

    });



    AsyncIterFnMut(
        PhantomData::default(),
        move |net: &mut Input| -> Async<String, Error> {
            let mut nu_state : Option<Box<dyn FnMut(&mut Input, *mut u8) -> Async<String, Error>>> = None;
            let r = (__stateful_f)(net, unsafe { mem::transmute(&mut nu_state)});
            if let Some(n) = nu_state {
                __stateful_f = n;
            }
            r
        }
    )
}



#[osaka]
pub fn get_the_name2<Input, Error>() -> impl AsyncIter<Input, String, Error>
    where Input: AsyncIter<(),String, Error>,
{
    sync!(token);
    if token != "am" {
        return Async::Again;
    }

    sync!(token);
    Async::Ready(token)
}

/*

fn get_the_name<Input, Error>() -> impl AsyncIter<Input, String, Error>
    where Input: AsyncIter<(),String, Error>,
{
    let mut collect_that_name = String::new();

    let token <- net;
    if token != "am" {
        return Async::Again;
    }
    let mut collect_that_name = String::new();

    let name <- net;
    collect_that_name += &name;

    let name <- net;
    collect_that_name += &name;


    Async::Ready(collect_that_name)
}


*/
