/*
    Copyright: 2020 Rasmus Thomsen <oss@cogitri.dev>
    SPDX-License-Identifier: GPL-3.0-or-later
*/

#![deny(clippy::all)]
#![warn(clippy::pedantic)]
#![allow(clippy::must_use_candidate)]

use crate::dbus_server::DBusServer;
use gettextrs::{TextDomain, TextDomainError};
use log::{debug, error, info, trace, warn, LevelFilter};
use std::convert::{TryFrom, TryInto};
use std::error::Error;
use zbus::fdo;

mod apk_package_owned;
mod dbus_server;

fn setup_logger() -> Result<(), fern::InitError> {
    let syslog_formatter = syslog::Formatter3164 {
        facility: syslog::Facility::LOG_DAEMON,
        hostname: None,
        process: "apk-polkit-server".into(),
        pid: i32::try_from(std::process::id()).unwrap_or(0),
    };

    let fern_builder = fern::Dispatch::new().chain(
        // console config
        fern::Dispatch::new()
            .format(move |out, message, record| {
                out.finish(format_args!("[{}] {}", record.level(), message))
            })
            .chain(std::io::stdout()),
    );

    match syslog::unix::<syslog::Formatter3164>(syslog_formatter) {
        Ok(syslogger) => {
            fern_builder
                .chain(
                    // syslog config
                    fern::Dispatch::new()
                        .level(LevelFilter::Info)
                        .chain(syslogger),
                )
                .apply()?;
        }
        Err(e) => {
            fern_builder.apply()?;
            error!("Failed to connect to syslog due to error {}!", e);
        }
    }
    Ok(())
}

fn setup_gettext() {
    match TextDomain::new("apk-polkit-rs").init() {
        Ok(locale) => debug!(
            "Found translation; enabling localisation with locale {:?}",
            locale
        ),
        Err(TextDomainError::InvalidLocale(e)) => {
            warn!("Couldn't enable localisation, invalid locale {}", e)
        }
        Err(TextDomainError::TranslationNotFound(e)) => warn!(
            "Couldn't enable localisation, no translation found for locale {}",
            e
        ),
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    setup_logger()?;
    setup_gettext();
    info!("Starting server...");

    let connection = zbus::Connection::new_system()?;
    fdo::DBusProxy::new(&connection)
        .unwrap()
        .request_name(
            "dev.Cogitri.apkPolkit1",
            fdo::RequestNameFlags::ReplaceExisting.into(),
        )
        .unwrap();

    let mut object_server = zbus::ObjectServer::new(&connection);
    object_server
        .at(
            &"/dev/Cogitri/apkPolkit1".try_into().unwrap(),
            DBusServer::default(),
        )
        .unwrap();
    info!("...Done! Starting event loop.");
    loop {
        trace!("Trying to process event...");
        if let Err(err) = object_server.try_handle_next() {
            error!(
                "Something went wrong while processing a DBus event: {}",
                err
            );
        }
    }
}
