/*-
 * syslog-rs - a syslog client translated from libc to rust
 * 
 * Copyright 2025 Aleksandr Morozov
 * 
 * The syslog-rs crate can be redistributed and/or modified
 * under the terms of either of the following licenses:
 *
 *   1. the Mozilla Public License Version 2.0 (the “MPL”) OR
 *
 *   2. The MIT License (MIT)
 *                     
 *   3. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
 */

/// A container which holds the formatted message and a range of slices 
/// which are suitable for the stderror output or syscons output. 
/// Normally, the `stderr_range` is a message without `PRI` and other headers
/// 
/// For example for the message type <34> Mon 12 ... the stderr_tange can be 1.. 
/// which will exclude the <34>.
#[derive(Debug)]
pub struct SyslogFormatted
{
    /// A header
    msg_header: Option<String>,

    /// A msg which is sent to stderr if needed. Usually this is a message without PRI
    msg_payload: String,

    /// A cache in case if it will be reqired to obtain a full message which consists
    /// from header and payload.
    full_msg: Option<String>,
}

impl SyslogFormatted
{
    /// Constructs new container.
    pub 
    fn new(msg_header: Option<String>, msg_payload: String) -> Self
    {
        return Self{ msg_header: msg_header, msg_payload: msg_payload, full_msg: None };
    }

    /// Returns the payload without header.
    pub(crate) 
    fn get_stderr_output(&self) -> &str
    {
        return &self.msg_payload;
    }

    /// Returns the concatinated message (headr+payload) or just a payload
    /// if header does not present.
    pub(crate) 
    fn get_full_msg(&mut self) -> &str
    {
        if self.full_msg.is_some() == true
        {
            return self.full_msg.as_ref().unwrap();
        }
        else
        {
            let header= 
                if self.msg_header.is_some() == true
                {
                    let msg = [self.msg_header.as_ref().unwrap().as_str(), self.msg_payload.as_str()].concat();

                    self.full_msg.replace(msg);

                    self.full_msg.as_ref().unwrap().as_str()
                }
                else
                {
                    self.msg_payload.as_ref()
                };

            return header;
        }
    }
}

/// A trait for the custom syslog formatter.
pub trait SyslogFormatter: std::fmt::Debug + Send + Clone + From<String> + From<&'static str> + 'static
{
    /// Formats the message for the syslog server with specific protocol or
    /// RFC.
    /// 
    /// # Arguments
    /// 
    /// * `max_msg_size` - a max msg size in bytes.
    /// 
    /// * `prifac` - a [SyslogMsgPriFac] a prepared PRI header value.
    /// 
    /// * `progname` - a ref to program name or identifier which is set during init.
    /// 
    /// * `pid` - an [Option] value where inner constains a PID number already converted 
    ///     into `string` form. If [Option::None] is provided, a [crate::LogStat::LOG_PID] was
    ///     not set during init. The formatter must exclude the `PID` from the report.
    /// 
    /// # Returns
    /// 
    /// A [SyslogFormatted] should be returned.
    fn vsyslog1_format(&self, max_msg_size: usize, prifac: SyslogMsgPriFac, progname: &str, pid: Option<&str>) -> SyslogFormatted;
}

/// A windows specific formatter (which is not bounded to any standart). 
/// Used for Windows Event Log and not appliciable to the rest logging.
#[cfg(target_os = "windows")]
pub mod windows_10;

/// RFC3146 based formatter.
pub mod syslog_3146;

/// RFC5424 based formatter.
pub mod syslog_5424;

/// Formatter for local file (which is not bounded to any standart).
pub mod syslog_file;

pub use syslog_3146::FormatRfc3146;
pub use syslog_5424::FormatRfc5424;
pub use syslog_file::FormatFile;

#[cfg(target_os = "windows")]
pub use windows_10::FormatWindows;

use crate::{SyslogMsgPriFac};

/// A default syslog formatter. For GNU/Linux it is RFC3146
#[cfg(target_os = "linux")]
pub type DefaultSyslogFormatter = FormatRfc3146;

/// A default syslog formatter. For xBSD it is RFC5424
#[cfg(any(
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "openbsd",
    target_os = "netbsd",
    target_os = "macos"
))]
pub type DefaultSyslogFormatter = FormatRfc5424;

/// If the crate is compiled on the Windows OS, the value is set to 
/// the one which is for the Local Windows Event Log because by default
/// the default syslog instance is `local`. You must override the value
/// if working with remote or local syslog.
#[cfg(target_os = "windows")]
pub type DefaultSyslogFormatter = FormatWindows;

/// A default syslog message formatter for local files.
pub type DefaultSyslogFormatterFile = FormatFile;
