Documentation
use crate::processor::{Context, ContextKey, Process, ProcessDecision, Result, Titles};
use std::collections::HashSet;

pub struct Uniqueness {
    known_lines: HashSet<ContextKey>,
    next: Box<dyn Process>,
}

impl Uniqueness {
    pub fn create_process(next: Box<dyn Process>) -> Box<dyn Process> {
        Box::new(Uniqueness {
            known_lines: HashSet::new(),
            next,
        })
    }
}

impl Process for Uniqueness {
    fn complete(&mut self) -> Result<()> {
        self.known_lines.clear();
        self.next.complete()
    }
    fn start(&mut self, titles_so_far: Titles) -> Result<()> {
        self.next.start(titles_so_far)
    }
    fn process(&mut self, context: Context) -> Result<ProcessDecision> {
        if self.known_lines.insert(context.key()) {
            self.next.process(context)
        } else {
            Ok(ProcessDecision::Continue)
        }
    }
}

#[cfg(test)]
mod tests {
    use std::cell::RefCell;
    use std::ops::Deref;
    use std::rc::Rc;

    use super::*;
    use crate::json_value::JsonValue;

    #[test]
    fn duplicate_lines_follow_only_once() -> Result<()> {
        struct Next(Rc<RefCell<Vec<JsonValue>>>);
        let data = Rc::new(RefCell::new(Vec::new()));
        impl Process for Next {
            fn complete(&mut self) -> Result<()> {
                Ok(())
            }
            fn process(&mut self, context: Context) -> Result<ProcessDecision> {
                let value = context.input().deref().clone();
                let mut vec = self.0.borrow_mut();
                vec.push(value);
                Ok(ProcessDecision::Continue)
            }
            fn start(&mut self, _: Titles) -> Result<()> {
                Ok(())
            }
        }
        {
            let next = Box::new(Next(data.clone()));
            let mut uniqueness = Uniqueness::create_process(next);

            let context = Context::new_with_no_context("text".into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context("text".into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context((100).into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context("text2".into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context((200).into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context((100).into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context((200).into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context("text2".into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context("text".into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context((100).into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context((200).into());
            uniqueness.process(context)?;
            let context = Context::new_with_no_context("text2".into());
            uniqueness.process(context)?;
        }

        assert_eq!(
            *data.deref().borrow(),
            vec!["text".into(), (100).into(), "text2".into(), (200).into()]
        );

        Ok(())
    }

    #[test]
    fn start_will_keep_the_title() -> Result<()> {
        struct Next(Rc<RefCell<bool>>);
        let data = Rc::new(RefCell::new(false));
        let one = Rc::new("one".into());
        let two = Rc::new("two".into());
        let titles = Titles::default().with_title(&one).with_title(&two);
        impl Process for Next {
            fn complete(&mut self) -> Result<()> {
                Ok(())
            }
            fn process(&mut self, _: Context) -> Result<ProcessDecision> {
                Ok(ProcessDecision::Continue)
            }
            fn start(&mut self, titles: Titles) -> Result<()> {
                assert_eq!(titles.len(), 2);
                *self.0.borrow_mut() = true;
                Ok(())
            }
        }
        {
            let next = Box::new(Next(data.clone()));
            let mut uniqueness = Uniqueness::create_process(next);

            uniqueness.start(titles)?;
        }

        let binding = data.borrow();
        let data = &*binding;
        assert_eq!(data, &true);

        Ok(())
    }

    #[test]
    fn complete_will_complete() -> Result<()> {
        struct Next(Rc<RefCell<bool>>);
        let data = Rc::new(RefCell::new(false));
        impl Process for Next {
            fn complete(&mut self) -> Result<()> {
                *self.0.borrow_mut() = true;
                Ok(())
            }
            fn process(&mut self, _: Context) -> Result<ProcessDecision> {
                Ok(ProcessDecision::Continue)
            }
            fn start(&mut self, _: Titles) -> Result<()> {
                Ok(())
            }
        }
        {
            let next = Box::new(Next(data.clone()));
            let mut uniqueness = Uniqueness::create_process(next);

            uniqueness.complete()?;
        }

        let binding = data.borrow();
        let data = &*binding;
        assert_eq!(data, &true);

        Ok(())
    }
}