use {
    crate::{
        core::{Observer, OuterViewPort},
        vec::{VecBuffer, VecDiff},
    },
    async_std::{
        io::{Read, ReadExt},
        stream::StreamExt,
    },
    serde::{de::DeserializeOwned, Serialize},
    std::sync::RwLock,
    std::{io::Write, sync::Arc},
};

//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>

pub struct VecJsonWriter<T, W>
where
    T: Clone + Send + Sync + 'static,
    W: Write + Send + Sync,
{
    data: Option<Arc<RwLock<Vec<T>>>>,
    out: RwLock<W>,
}

impl<T> OuterViewPort<RwLock<Vec<T>>>
where
    T: Clone + Serialize + Send + Sync + 'static,
{
    pub fn serialize_json<W: Write + Send + Sync + 'static>(
        &self,
        out: W,
    ) -> Arc<RwLock<VecJsonWriter<T, W>>> {
        let writer = Arc::new(RwLock::new(VecJsonWriter {
            data: None,
            out: RwLock::new(out),
        }));
        self.add_observer(writer.clone());
        writer
    }
}

impl<T, W> Observer<RwLock<Vec<T>>> for VecJsonWriter<T, W>
where
    T: Clone + Serialize + Send + Sync + 'static,
    W: Write + Send + Sync,
{
    fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
        self.data = view;

        self.out
            .write()
            .unwrap()
            .write(
                &serde_json::to_string(&VecDiff::<T>::Clear)
                    .unwrap()
                    .as_bytes(),
            )
            .expect("");
        self.out.write().unwrap().write(b"\n").expect("");

        if let Some(data) = self.data.as_ref() {
            for x in data.read().unwrap().iter() {
                self.out
                    .write()
                    .unwrap()
                    .write(&serde_json::to_string(&VecDiff::Push(x)).unwrap().as_bytes())
                    .expect("");
                self.out.write().unwrap().write(b"\n").expect("");
            }
        }

        self.out.write().unwrap().flush().expect("");
    }

    fn notify(&mut self, diff: &VecDiff<T>) {
        self.out
            .write()
            .unwrap()
            .write(serde_json::to_string(diff).unwrap().as_bytes())
            .expect("");
        self.out.write().unwrap().write(b"\n").expect("");
        self.out.write().unwrap().flush().expect("");
    }
}

impl<T> VecBuffer<T>
where
    T: DeserializeOwned + Clone + Send + Sync + 'static,
{
    pub async fn from_json<R: Read + async_std::io::Read + Unpin>(&mut self, read: R) {
        let mut bytes = read.bytes();
        let mut s = String::new();
        while let Some(Ok(b)) = bytes.next().await {
            match b {
                b'\n' => {
                    if s.len() > 0 {
                        let diff =
                            serde_json::from_str::<VecDiff<T>>(&s).expect("error parsing json");
                        self.apply_diff(diff);
                        s.clear();
                    }
                }
                c => {
                    s.push(c as char);
                }
            }
        }
    }
}