use crate::formatter::Formatter;
use crate::logger::Dispatch;
use log::{LevelFilter, Record};
use std::io::{stdout, Stdout, Write};

pub struct Socket<F: Formatter, W: Write + Send + Sync> {
    level_filter: LevelFilter,
    uid: u64,
    socket: W,
    formatter: F
}

impl<F: Formatter, W: Write + Send + Sync> Socket<F, W> {
    pub fn new(uid: impl Into<u64>, level_filter: LevelFilter, socket: W, formatter: F) -> Self {
        Self {
            level_filter,
            uid: uid.into(),
            socket,
            formatter,
        }
    }

    pub fn stdout(uid: impl Into<u64>, level_filter: LevelFilter, formatter: F) -> Socket<F, Stdout> {
        Socket::<F, Stdout> {
            level_filter,
            uid: uid.into(),
            socket: stdout(),
            formatter,
        }
    }
}

impl<F: Formatter, W: Write + Send + Sync> Dispatch for Socket<F, W> {
    fn max_level(&self) -> LevelFilter {
        self.level_filter
    }

    fn uid(&self) -> u64 {
        self.uid
    }

    fn log(&mut self, record: &Record) {
        self.formatter.format_log(record, &mut self.socket).expect("failed to format log");
    }

    fn flush(&mut self) {
        self.socket.flush().expect("failed to flush socket");
    }
}