//
// Syd: rock-solid application kernel
// src/syd-net.rs: Aggregate IP networks
//
// Copyright (c) 2024, 2025 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0

use std::{
    fs::File,
    io::{stdin, BufReader},
};

use syd::{err::SydResult, sandbox::Sandbox};

fn main() -> SydResult<()> {
    use lexopt::prelude::*;

    syd::set_sigpipe_dfl()?;

    // Parse CLI options.
    //
    // Note, option parsing is POSIXly correct:
    // POSIX recommends that no more options are parsed after the first
    // positional argument. The other arguments are then all treated as
    // positional arguments.
    // See: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02
    let mut paths = Vec::new();
    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('h') => {
                help();
                return Ok(());
            }
            Value(val) => {
                paths.push(val);
                paths.extend(parser.raw_args()?);
            }
            _ => return Err(arg.unexpected().into()),
        }
    }

    let mut sin = true; // read standard input.
    let mut syd = Sandbox::new();
    for path in paths {
        sin = false;

        #[allow(clippy::disallowed_methods)]
        let file = File::open(path)?;
        syd.parse_netset(BufReader::new(file))?;
    }

    if sin {
        let file = stdin();
        syd.parse_netset(BufReader::new(file))?;
    }

    syd.rule_agg_block("")?;
    for addr in syd.block4() {
        println!("{addr}");
    }
    for addr in syd.block6() {
        println!("{addr}");
    }

    Ok(())
}

fn help() {
    println!("Usage: syd-net [-h] <path>...");
    println!("Tool to aggregate IP networks.");
    println!("Reads IP networks from the given list of paths.");
    println!("Given no arguments, reads from standard input.");
}
