#![feature(custom_attribute)]

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

extern crate osaka_macros;
use osaka_macros::osaka_async_fn;



pub enum Async<N,R,E> {
    Error(E),
    Ready(R),

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


    /// FIXME using this means we can't really stack different types
    /// an alternative would be that each function needs to hold its entire state internally.
    /// we can easily generate a state engine from osaka_async_fn
    /// probably matches gneerators more closely too, so we might be able to abuse them some day.
    Later(Box<Later<N,R,E>>),
}

pub trait Later<N, R,E> {
    fn forward(&mut self, s: N) -> Async<N,R,E>;
}

impl<N,F,R,E> Later<N,R,E> for F where F: FnMut(N) -> Async<N, R,E> {
    fn forward(&mut self, s: N) -> Async<N,R,E> {
        (self)(s)
    }
}


pub struct Executor<N,R,E>  {
    t: Box<Later<N,R,E>>,
}

impl<N,R,E> Executor<N,R,E> {
    pub fn complete(&mut self, n: N) -> Option<Result<R,E>>{
        match self.t.forward(n) {
            Async::Error(e) => return Some(Err(e)),
            Async::Ready(r) => return Some(Ok(r)),
            Async::Later(n) => self.t = n,
            Async::Again => (),
        }
        None
    }
}

/*

#[osaka_async_fn]
pub fn wait_for_3_3_macro(x: u32) -> Result<u32,()> {

    let v = sync!(x);
    if v != 3 {
        continue
    }

    let v = sync!(x);
    if v != 3 {
        continue
    }

    Ok(32)
}



pub fn desugar_main() -> Async<u32,u32,()> {
    Async::Later(Box::new(desugar_step1))
}

pub fn desugar_step1(v: u32) -> Async<u32,u32,()> {
    if v != 3 {
        return Async::Again
    }
    Async::Later(Box::new(desugar_step2))
}

pub fn desugar_step2(v: u32) -> Async<u32,u32,()> {
    if v != 3 {
        return Async::Again
    }
    Async::Ready(32)
}


*/




struct Network {
    incomming: Vec<String>
}


impl Network {
    fn recv(&mut self) -> 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 done".into())
        }
    }
}

/*
#[osaka_async_fn]
fn get_the_name(net: Network) -> Result<String, String> {
    let item = sync!(net.recv());
    if item == "am" {
        let name = sync!(net.recv());
        Ok(name)
    }
}
*/

fn get_the_name_desugar<'a>() -> impl Later<&'a mut Network, String, String> {
    move |net: &'a mut Network|{
        let item = match net.recv() {
            Async::Ready(v) => v,
            e => return e,
        };

        if item != "am" {
            return Async::Again;
        }

        Async::Ready(String::from("ok cool"))

        /*

        Async::Later(Box::new(move |net: &'a mut Network| {
            let name = match net.recv() {
                Async::Ready(v) => v,
                e => return e,
            };
            Async::Ready(name)
        }))

        */
    }
}

/*
fn get_the_name_desugar(mut net: Network) -> impl Later<(), String, String> {
    use std::mem::replace;

    let mut xe = Some(net);
    move |()|{
        let item = match xe.as_mut().unwrap().recv() {
            Async::Ready(v) => v,
            e => return e,
        };

        if item != "am" {
            return Async::Again;
        }

        let mut xe  = replace(&mut xe, None);
        Async::Later(Box::new(move |()| {
            let name = match xe.as_mut().unwrap().recv() {
                Async::Ready(v) => v,
                e => return e,
            };
            Async::Ready(name)
        }))
    }
}
*/



fn main () {
    let incomming  = Network{incomming: vec!["yes".into(), "i".into(), "am".into(), "kebab".into()]};
    let name = get_the_name_desugar();

    /*
    let mut e = Executor{t: Box::new(name)};

    loop {
        let v = e.complete(());
        println!("{:?}", v);
        if v.is_some() {
            break;
        }
    }
    */
}








/*




pub fn wait_for_3_3_raw_inner(x: u32) -> Result<Async<u32,u32,()>, ()> {
    if x != 3 {
        return Ok(Async::Again)
    }
    Ok(Async::Later::<u32,u32,()>(Box::new(wait_for_3_3_step2)))
}

pub fn wait_for_3_3_raw(x: u32) -> Async<u32,u32,()> {
    match wait_for_3_3_raw_inner(x) {
        Ok(v)  => v,
        Err(e) => Async::Error(e),
    }
}






pub fn wait_for_3_3_step2_inner(x: u32) -> Result<Async<u32,u32,()>, ()> {
    if x != 3 {
        return Ok(Async::Again)
    }

    Ok(Async::Ready(52))
}

pub fn wait_for_3_3_step2(x: u32) -> Async<u32,u32,()> {
    match wait_for_3_3_step2_inner(x) {
        Ok(v)  => v,
        Err(e) => Async::Error(e),
    }
}



fn main() {

    let incomming = [0,1,2,3,4,3,5];


    let mut e = Executor{t: Box::new(wait_for_3_3_raw)};

    for i in incomming.into_iter() {
        let x = e.complete(*i);
        println!("{:?}", x);
    }

}

*/
