Framework for embedding localizations into Rust types
//! Implementations of `Localize` for various list types

use crate::macros::impl_serialize;
use crate::{Context, Localize};

use writeable::Writeable;

pub trait Length {
    fn len(&self) -> usize;
}

#[derive(Clone, Copy, Debug)]
pub enum ListType {
    And,
    Or,
    Unit,
}

macro_rules! list_impl {
    ($list_name:ident, $list_type:path) => {
        #[derive(Debug, Clone)]
        pub struct $list_name<L: Localize> {
            messages: Vec<L>,
        }

        impl<L: Localize> $list_name<L> {
            pub const fn new(messages: Vec<L>) -> Self {
                Self { messages }
            }
        }

        impl<L: Localize> Length for $list_name<L> {
            fn len(&self) -> usize {
                self.messages.len()
            }
        }

        impl<L: Localize> Localize for $list_name<L> {
            fn localize(&self, context: &Context, buffer: &mut String) {
                let list_formatter = context.list_formatter($list_type);

                let localized_messages = self.messages.iter().map(|message| {
                    let mut buffer = String::new();
                    message.localize(context, &mut buffer);

                    buffer
                });

                let formatted_list = list_formatter.format(localized_messages);
                formatted_list.write_to(buffer).unwrap();
            }
        }
    };
}

list_impl!(AndList, ListType::And);
list_impl!(OrList, ListType::Or);
list_impl!(UnitList, ListType::Unit);

impl_serialize!(AndList, messages);
impl_serialize!(OrList, messages);
impl_serialize!(UnitList, messages);