#![deny(clippy::mem_forget)]

use fenir::cwe::CweRecord;
use fenir::database::{
    check_database, find_columns, find_cwe_by_id, initialize_tables, refresh_mitre_database,
    searching, MitreDefinition,
};
use fenir::facilities::configure_terminal;
use fenir::network::check_mitre_data;
use fenir::os::parse_id;
use fenir::package::errors::write_error_message_and_exit;
use fenir::{no_argument_and_exit, show_version};
use get_cwe::{CweDisplayType::{
    Attacks, Consequences, Description, Detections, Extended, Mitigations,
}, {build_tree_schema, inject_csv_into_cwe_table, run_search, CweDisplayType, GetCweCommand}};
use std::env;
use std::process::exit;

fn main() {
    configure_terminal();

    let args: Vec<String> = env::args().collect();
    if args.iter().any(|a| a == "help" || a == "h") {
        help();
        exit(0);
    }

    if args.iter().any(|a| a == "check" || a == "c") {
        let check_option = args.iter().position(|x| x == "--db" || x == "-d");
        if check_option.is_some() {
            let result = check_database("cwe");
            if result.0 {
                println!("Mitre table 'cwe'... Ok ({})", result.1);
            } else {
                eprintln!("Database does not exist!");
            }
        } else {
            let data = CweRecord::define();
            check_mitre_data(data);
        }
    } else if args.iter().any(|a| a.to_ascii_lowercase().contains("cwe-")) {
        let cwe_id = parse_id(args[1].as_str(), "cwe");
        if let Some(cwe_id) = cwe_id {
            if let Some(cwe) = find_cwe_by_id(cwe_id) {
                if args.iter().any(|a| a == "--schema" || a == "-S") {
                    let schema = build_tree_schema(&cwe);
                    println!("{}", schema.render_to_string());
                    exit(0);
                }

                println!("{}", cwe);

                let mut counter = 0;

                if args.iter().any(|a| a == "--desc" || a == "-t") {
                    Description.show(&cwe);
                    counter += 1;
                }

                if args.iter().any(|a| a == "--ext" || a == "-x") {
                    Extended.show(&cwe);
                    counter += 1;
                }

                if args.iter().any(|a| a == "--cons" || a == "-c") {
                    Consequences.show(&cwe);
                    counter += 1;
                }

                if args.iter().any(|a| a == "--detect" || a == "-e") {
                    Detections.show(&cwe);
                    counter += 1;
                }

                if args.iter().any(|a| a == "--mitigations" || a == "-m") {
                    Mitigations.show(&cwe);
                    counter += 1;
                }

                if args.iter().any(|a| a == "--capec" || a == "-A") {
                    Attacks.show(&cwe);
                    counter += 1;
                }

                if counter == 0 {
                    CweDisplayType::All.show(&cwe);
                }
            } else {
                write_error_message_and_exit("CWE not found", None);
            }
        } else {
            write_error_message_and_exit("Invalid cwe id", None);
        }
    } else if args.iter().any(|x| x == "refresh" || x == "r") {
        initialize_tables(GetCweCommand);
        refresh_mitre_database(CweRecord::define(), inject_csv_into_cwe_table);
    } else if args.iter().any(|x| x == "version" || x == "v") {
        show_version(env!("CARGO_PKG_VERSION"));
    } else if args.iter().any(|a| a == "search" || a == "s") {
        searching(&args, &find_columns("cwe"), run_search);
    } else {
        no_argument_and_exit!();
    }
}

fn help() {
    println!("
Gets information data about the given CWE identification.

Usage:
    get-cwe [options]

Options:
    h or help: shows this help.
    c or check [-d|--db]: test the validity of the connection to the Mitre. With '-d' or '--db' option check if local database is available.
    <cwe-id>: shows the name of the <cwe-id> id. The <cwe-id> is the form of: CWE-<id>. With this option,
the complementary options are the following:
        -A or --capec: shows associated capec attacks if defined,
        -c or --cons: shows the associated consequences,
        -t or --desc: shows the associated description,
        -e or --detect: shows the associated detections,
        -x or --ext: shows the associated extended description,
        -m or --mitigation: shows the associated mitigations,
        -S or --schema: shows the cwe schema for this cwe.
    r or refresh: refresh the CWE database content with the last mitre publications,
    s or search <domain>=<arguments>,  where <domain>
        <domain>: is the following reserved keywords:
            name = <arguments>

        <arguments> is the following forms: <value1> <operator> <value2>...<valueN-1> <operator> <valueN>
            <value>: os a searched value,
            <operator>:
                or: or operator,
                and: and operator,
                not: not operator

        Eg: search name = XML or XPath

    The domain list is the following:
        - consequences,
        - description,
        - detections,
        - extended,
        - mitigations,
        - name,
        - all: means search criteria will be applied to all domain list above (eg: all = <value>),

    v or version: shows the current version.");
}
