pub mod command;
pub mod cpu_time;
pub mod empty;
pub mod gid;
pub mod group;
pub mod maj_flt;
pub mod pid;
pub mod ppid;
pub mod priority;
pub mod read_bytes;
pub mod separator;
pub mod slot;
pub mod start_time;
pub mod threads;
pub mod tree;
pub mod uid;
pub mod usage_cpu;
pub mod usage_mem;
pub mod user;
pub mod vm_hwm;
pub mod vm_peak;
pub mod vm_pin;
pub mod vm_rss;
pub mod vm_size;
pub mod vm_swap;
pub mod write_bytes;

pub use self::command::Command;
pub use self::cpu_time::CpuTime;
pub use self::empty::Empty;
pub use self::gid::Gid;
pub use self::group::Group;
pub use self::maj_flt::MajFlt;
pub use self::pid::Pid;
pub use self::ppid::Ppid;
pub use self::priority::Priority;
pub use self::read_bytes::ReadBytes;
pub use self::separator::Separator;
pub use self::slot::Slot;
pub use self::start_time::StartTime;
pub use self::threads::Threads;
pub use self::tree::Tree;
pub use self::uid::Uid;
pub use self::usage_cpu::UsageCpu;
pub use self::usage_mem::UsageMem;
pub use self::user::User;
pub use self::vm_hwm::VmHwm;
pub use self::vm_peak::VmPeak;
pub use self::vm_pin::VmPin;
pub use self::vm_rss::VmRss;
pub use self::vm_size::VmSize;
pub use self::vm_swap::VmSwap;
pub use self::write_bytes::WriteBytes;

use crate::column::Column;
use lazy_static::lazy_static;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;

// ---------------------------------------------------------------------------------------------------------------------
// ConfigColumnKind
// ---------------------------------------------------------------------------------------------------------------------

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum ConfigColumnKind {
    Command,
    CpuTime,
    Empty,
    Gid,
    Group,
    MajFlt,
    Pid,
    Ppid,
    Priority,
    ReadBytes,
    Separator,
    Slot,
    StartTime,
    Threads,
    Tree,
    Uid,
    UsageCpu,
    UsageMem,
    User,
    VmHwm,
    VmPeak,
    VmPin,
    VmRss,
    VmSize,
    VmSwap,
    WriteBytes,
}

// ---------------------------------------------------------------------------------------------------------------------
// gen_column
// ---------------------------------------------------------------------------------------------------------------------

pub fn gen_column(
    kind: &ConfigColumnKind,
    header: Option<String>,
    _docker_path: &str,
    separator: &str,
    abbr_sid: bool,
    tree_symbols: &[String; 5],
) -> Box<dyn Column> {
    match kind {
        ConfigColumnKind::Command => Box::new(Command::new(header)),
        ConfigColumnKind::CpuTime => Box::new(CpuTime::new(header)),
        ConfigColumnKind::Empty => Box::new(Empty::new()),
        ConfigColumnKind::Gid => Box::new(Gid::new(header, abbr_sid)),
        ConfigColumnKind::Group => Box::new(Group::new(header, abbr_sid)),
        ConfigColumnKind::MajFlt => Box::new(MajFlt::new(header)),
        ConfigColumnKind::Pid => Box::new(Pid::new(header)),
        ConfigColumnKind::Ppid => Box::new(Ppid::new(header)),
        ConfigColumnKind::Priority => Box::new(Priority::new(header)),
        ConfigColumnKind::ReadBytes => Box::new(ReadBytes::new(header)),
        ConfigColumnKind::Separator => Box::new(Separator::new(separator)),
        ConfigColumnKind::Slot => Box::new(Slot::new()),
        ConfigColumnKind::StartTime => Box::new(StartTime::new(header)),
        ConfigColumnKind::Threads => Box::new(Threads::new(header)),
        ConfigColumnKind::Tree => Box::new(Tree::new(tree_symbols)),
        ConfigColumnKind::Uid => Box::new(Uid::new(header, abbr_sid)),
        ConfigColumnKind::UsageCpu => Box::new(UsageCpu::new(header)),
        ConfigColumnKind::UsageMem => Box::new(UsageMem::new(header)),
        ConfigColumnKind::User => Box::new(User::new(header, abbr_sid)),
        ConfigColumnKind::VmHwm => Box::new(VmHwm::new(header)),
        ConfigColumnKind::VmPeak => Box::new(VmPeak::new(header)),
        ConfigColumnKind::VmPin => Box::new(VmPin::new(header)),
        ConfigColumnKind::VmRss => Box::new(VmRss::new(header)),
        ConfigColumnKind::VmSize => Box::new(VmSize::new(header)),
        ConfigColumnKind::VmSwap => Box::new(VmSwap::new(header)),
        ConfigColumnKind::WriteBytes => Box::new(WriteBytes::new(header)),
    }
}

// ---------------------------------------------------------------------------------------------------------------------
// KIND_LIST
// ---------------------------------------------------------------------------------------------------------------------

lazy_static! {
    pub static ref KIND_LIST: HashMap<ConfigColumnKind, (&'static str, &'static str)> = [
        (
            ConfigColumnKind::Command,
            ("Command", "Command with all arguments")
        ),
        (
            ConfigColumnKind::CpuTime,
            ("CpuTime", "Cumulative CPU time")
        ),
        (ConfigColumnKind::Empty, ("Empty", "Empty")),
        (ConfigColumnKind::Gid, ("Gid", "Group ID")),
        (ConfigColumnKind::Group, ("Group", "Group name")),
        (
            ConfigColumnKind::MajFlt,
            ("MajFlt", "Major page fault count")
        ),
        (ConfigColumnKind::Pid, ("Pid", "Process ID")),
        (ConfigColumnKind::Ppid, ("Ppid", "Parent process ID")),
        (ConfigColumnKind::Priority, ("Priority", "Priority")),
        (
            ConfigColumnKind::ReadBytes,
            ("ReadBytes", "Read bytes from storage")
        ),
        (
            ConfigColumnKind::Separator,
            ("Separator", "Show | for column separation")
        ),
        (
            ConfigColumnKind::Slot,
            ("Slot", "Slot for `--insert` option")
        ),
        (ConfigColumnKind::StartTime, ("StartTime", "Starting time")),
        (ConfigColumnKind::Threads, ("Threads", "Thread count")),
        (ConfigColumnKind::Uid, ("Uid", "User ID")),
        (ConfigColumnKind::UsageCpu, ("UsageCpu", "CPU utilization")),
        (
            ConfigColumnKind::UsageMem,
            ("UsageMem", "Memory utilization")
        ),
        (ConfigColumnKind::User, ("User", "User name")),
        (ConfigColumnKind::VmHwm, ("VmHwm", "Peak resident set size")),
        (
            ConfigColumnKind::VmPeak,
            ("VmPeak", "Peak virtual memory size")
        ),
        (ConfigColumnKind::VmPin, ("VmPin", "Pinned memory size")),
        (ConfigColumnKind::VmRss, ("VmRss", "Resident set size")),
        (ConfigColumnKind::VmSize, ("VmSize", "Physical page size")),
        (
            ConfigColumnKind::VmSwap,
            ("VmSwap", "Swapped-out virtual memory size")
        ),
        (
            ConfigColumnKind::WriteBytes,
            ("WriteBytes", "Write bytes to storage")
        ),
    ]
    .iter()
    .cloned()
    .collect();
}

// ---------------------------------------------------------------------------------------------------------------------
// CONFIG_DEFAULT
// ---------------------------------------------------------------------------------------------------------------------

pub static CONFIG_DEFAULT: &str = r#"
[[columns]]
kind = "Pid"
style = "BrightYellow|Yellow"
numeric_search = true
nonnumeric_search = false
[[columns]]
kind = "User"
style = "BrightGreen|Green"
numeric_search = false
nonnumeric_search = true
[[columns]]
kind = "Separator"
style = "White|BrightBlack"
numeric_search = false
nonnumeric_search = false
[[columns]]
kind = "UsageCpu"
style = "ByPercentage"
numeric_search = false
nonnumeric_search = false
align = "Right"
[[columns]]
kind = "UsageMem"
style = "ByPercentage"
numeric_search = false
nonnumeric_search = false
align = "Right"
[[columns]]
kind = "CpuTime"
style = "BrightCyan|Cyan"
numeric_search = false
nonnumeric_search = false
[[columns]]
kind = "Separator"
style = "White|BrightBlack"
numeric_search = false
nonnumeric_search = false
[[columns]]
kind = "Command"
style = "BrightWhite|Black"
numeric_search = false
nonnumeric_search = true
"#;

// ---------------------------------------------------------------------------------------------------------------------
// CONFIG_ALL
// ---------------------------------------------------------------------------------------------------------------------

#[cfg(test)]
pub static CONFIG_ALL: &str = r#"
[[columns]]
kind = "Command"
style = "BrightRed"
align = "Left"
[[columns]]
kind = "CpuTime"
style = "BrightGreen"
align = "Center"
[[columns]]
kind = "Empty"
style = "BrightYellow"
[[columns]]
kind = "Gid"
style = "White"
[[columns]]
kind = "Group"
style = "White"
[[columns]]
kind = "MajFlt"
style = "BrightCyan"
[[columns]]
kind = "Pid"
style = "Green"
[[columns]]
kind = "Ppid"
style = "Yellow"
[[columns]]
kind = "Priority"
style = "Blue"
[[columns]]
kind = "ReadBytes"
style = "Cyan"
[[columns]]
kind = "Separator"
style = "White"
[[columns]]
kind = "StartTime"
style = "White"
[[columns]]
kind = "Threads"
style = "White"
[[columns]]
kind = "Uid"
style = "White"
[[columns]]
kind = "UsageCpu"
style = "White"
[[columns]]
kind = "UsageMem"
style = "White"
[[columns]]
kind = "User"
style = "White"
[[columns]]
kind = "VmHwm"
style = "ByUnit"
[[columns]]
kind = "VmPeak"
style = "ByUnit"
[[columns]]
kind = "VmPin"
style = "ByUnit"
[[columns]]
kind = "VmRss"
style = "ByUnit"
[[columns]]
kind = "VmSize"
style = "ByUnit"
[[columns]]
kind = "VmSwap"
style = "ByUnit"
[[columns]]
kind = "WriteBytes"
style = "White"
"#;
