Documentation
/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--

Dia-Args

Copyright (C) 2018-2019, 2021-2025  Anonymous

There are several releases over multiple years,
they are listed as ranges, such as: "2018-2019".

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/

//! # Option

use {
    core::{
        fmt::{self, Display},
        option::Option as RustOption,
    },
    std::borrow::Cow,
    super::{Cfg, I18n},
};

/// # Option
///
/// ## Examples
///
/// ```
/// use std::borrow::Cow;
/// use dia_args::docs::{self, Option};
///
/// // All these constants are convenient while working with Args.
/// // And you can also use them for Option.
///
/// const OPTION_PORT: &[&str] = &["-p", "--port"];
/// const OPTION_PORT_VALUES: &[u16] = &[0, 64009];
/// const OPTION_PORT_DEFAULT: u16 = OPTION_PORT_VALUES[1];
/// const OPTION_PORT_DOCS: Cow<str> = Cow::Borrowed("Port for server.");
///
/// let _option = Option::new(
///     OPTION_PORT, false,
///     OPTION_PORT_VALUES,
///     Some(OPTION_PORT_DEFAULT),
///     OPTION_PORT_DOCS,
/// );
/// // Here you can pass this option to Docs::new(...)
/// ```
#[derive(Clone)]
pub struct Option<'a> {
    names: &'a [&'a str],
    required: bool,
    values: Vec<String>,
    default: RustOption<String>,
    docs: Cow<'a, str>,
}

impl<'a> Option<'a> {

    /// # Makes new instance
    pub fn new<T>(names: &'a [&'a str], required: bool, values: &[T], default: RustOption<T>, docs: Cow<'a, str>) -> Self where T: Display {
        Self {
            names,
            required,
            values: values.iter().map(|v| v.to_string()).collect(),
            default: default.map(|v| v.to_string()),
            docs,
        }
    }

    /// # Formats self
    pub fn format(&self, cfg: &Cfg, i18n: &I18n, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let tab = cfg.tab_len().saturating_mul(cfg.tab_level().into());
        f.write_str(&super::format(&format!("{:?}", self.names), tab, cfg.columns()))?;

        let tab = cfg.tab_len().saturating_mul(cfg.tab_level().saturating_add(1).into());
        f.write_str(&super::format(&format!("{}: {}", i18n.required, self.required), tab, cfg.columns()))?;
        if self.values.is_empty() == false {
            let mut tmp = String::new();
            for (i, v) in self.values.iter().enumerate() {
                if i > 0 {
                    tmp.push_str(", ");
                }
                tmp.push_str(&v);
            }
            f.write_str(&super::format(&format!("{}: {}", i18n.values, tmp), tab, cfg.columns()))?;
        }
        if let Some(default) = &self.default {
            f.write_str(&super::format(&format!("{}: {}", i18n.default, default), tab, cfg.columns()))?;
        }
        f.write_str(super::LINE_BREAK)?;
        f.write_str(&super::format(&self.docs, tab, cfg.columns()))?;
        f.write_str(super::LINE_BREAK)?;

        Ok(())
    }

}

impl<'a> From<Option<'a>> for Cow<'a, Option<'a>> {

    fn from(option: Option<'a>) -> Self {
        Cow::Owned(option)
    }

}

impl<'a> From<&'a Option<'a>> for Cow<'a, Option<'a>> {

    fn from(option: &'a Option<'a>) -> Self {
        Cow::Borrowed(option)
    }

}