mod input_field;

use self::input_field::InputField;
use proc_macro2::Span;
use std::ops::Deref;
use syn::{Token, parse::Parse, punctuated::Punctuated};

pub struct DialectInput {
    name: String,
    files: Vec<String>,
    directories: Vec<String>,
    directory_env_vars: Vec<(String, Span)>,
}

impl DialectInput {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn files(&self) -> impl Iterator<Item = &str> {
        self.files.iter().map(Deref::deref)
    }

    pub fn directories(&self) -> impl Iterator<Item = &str> {
        self.directories.iter().map(Deref::deref)
    }

    pub fn directory_env_vars(&self) -> impl Iterator<Item = (&str, &Span)> {
        self.directory_env_vars
            .iter()
            .map(|(value, span)| (value.deref(), span))
    }
}

impl Parse for DialectInput {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let mut name = None;
        let mut files = vec![];
        let mut directories = vec![];
        let mut directory_env_vars = vec![];

        for item in Punctuated::<InputField, Token![,]>::parse_terminated(input)? {
            match item {
                InputField::Name(field) => name = Some(field.value()),
                InputField::Files(field) => {
                    files = field.into_iter().map(|literal| literal.value()).collect()
                }
                InputField::Directories(field) => {
                    directories = field.into_iter().map(|literal| literal.value()).collect()
                }
                InputField::DirectoryEnvVars(field) => {
                    directory_env_vars = field
                        .into_iter()
                        .map(|literal| (literal.value(), literal.span()))
                        .collect()
                }
            }
        }

        Ok(Self {
            name: name.ok_or_else(|| input.error("dialect name required"))?,
            files,
            directories,
            directory_env_vars,
        })
    }
}
