use crate::softether_reader::{SoftEtherReader, SoftEtherError};
use csv;
use std::error::Error;
use std::io::Write;
use std::process::{Command, Stdio};

pub struct SoftEtherHubStatusReader;

impl SoftEtherHubStatusReader {
    pub fn hub_status(
        vpncmd: &str,
        server: &str,
        hub: &str,
        password: &str,
    ) -> Result<HubStatus, Box<dyn Error>> {
        let mut child = Command::new(vpncmd)
            .arg(server)
            .arg("/SERVER")
            .arg(format!("/HUB:{}", hub))
            .arg(format!("/PASSWORD:{}", password))
            .arg("/CSV")
            .arg("/CMD")
            .arg("StatusGet")
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .spawn()?;

        {
            let stdin = child.stdin.as_mut().unwrap();
            // Input Ctrl-D to interrupt password prompt
            stdin.write_all(&[4])?;
        }

        let output = child.wait_with_output()?;

        if !output.status.success() {
            let msg = String::from_utf8_lossy(output.stdout.as_slice());
            return Err(Box::new(SoftEtherError {
                msg: String::from(format!("vpncmd failed ( {} )", msg)),
            }));
        }

        SoftEtherHubStatusReader::decode_hub_status(&output.stdout)
    }

    fn decode_hub_status(src: &[u8]) -> Result<HubStatus, Box<dyn Error>> {
        let mut rdr = csv::Reader::from_reader(src);
        let mut status = HubStatus::new();

        for entry in rdr.records() {
            let entry = entry?;
            let key = entry.get(0).unwrap_or("");
            let val = entry.get(1).unwrap_or("");
            match key.as_ref() {
                "仮想 HUB 名" => status.name = String::from(val),
                "状態" => {
                    status.online = if val == "オンライン" {
                        true
                    } else {
                        false
                    }
                }
                "SecureNAT 機能" => {
                    status.secure_nat = if val == "無効" { false } else { true }
                }
                "セッション数" => status.sessions = val.parse()?,
                "セッション数 (クライアント)" => {
                    status.sessions_client = val.parse()?
                }
                "セッション数 (ブリッジ)" => status.sessions_bridge = val.parse()?,
                "アクセスリスト数" => status.access_lists = val.parse()?,
                "ユーザー数" => status.users = val.parse()?,
                "グループ数" => status.groups = val.parse()?,
                "MAC テーブル数" => status.mac_tables = val.parse()?,
                "IP テーブル数" => status.ip_tables = val.parse()?,
                "ログイン回数" => status.logins = val.parse()?,
                "送信ユニキャストパケット数" => {
                    status.outgoing_unicast_packets = SoftEtherReader::decode_packets(val)?
                }
                "送信ユニキャスト合計サイズ" => {
                    status.outgoing_unicast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "送信ブロードキャストパケット数" => {
                    status.outgoing_broadcast_packets = SoftEtherReader::decode_packets(val)?
                }
                "送信ブロードキャスト合計サイズ" => {
                    status.outgoing_broadcast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "受信ユニキャストパケット数" => {
                    status.incoming_unicast_packets = SoftEtherReader::decode_packets(val)?
                }
                "受信ユニキャスト合計サイズ" => {
                    status.incoming_unicast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "受信ブロードキャストパケット数" => {
                    status.incoming_broadcast_packets = SoftEtherReader::decode_packets(val)?
                }
                "受信ブロードキャスト合計サイズ" => {
                    status.incoming_broadcast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "Virtual Hub Name" => status.name = String::from(val),
                "Status" => status.online = if val == "Online" { true } else { false },
                "SecureNAT" => status.secure_nat = if val == "Disabled" { false } else { true },
                "Sessions" => status.sessions = val.parse()?,
                "Sessions (Client)" => status.sessions_client = val.parse()?,
                "Sessions (Bridge)" => status.sessions_bridge = val.parse()?,
                "Access Lists" => status.access_lists = val.parse()?,
                "Users" => status.users = val.parse()?,
                "Groups" => status.groups = val.parse()?,
                "MAC Tables" => status.mac_tables = val.parse()?,
                "IP Tables" => status.ip_tables = val.parse()?,
                "Num Logins" => status.logins = val.parse()?,
                "Outgoing Unicast Packets" => {
                    status.outgoing_unicast_packets = SoftEtherReader::decode_packets(val)?
                }
                "Outgoing Unicast Total Size" => {
                    status.outgoing_unicast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "Outgoing Broadcast Packets" => {
                    status.outgoing_broadcast_packets = SoftEtherReader::decode_packets(val)?
                }
                "Outgoing Broadcast Total Size" => {
                    status.outgoing_broadcast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "Incoming Unicast Packets" => {
                    status.incoming_unicast_packets = SoftEtherReader::decode_packets(val)?
                }
                "Incoming Unicast Total Size" => {
                    status.incoming_unicast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "Incoming Broadcast Packets" => {
                    status.incoming_broadcast_packets = SoftEtherReader::decode_packets(val)?
                }
                "Incoming Broadcast Total Size" => {
                    status.incoming_broadcast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "虚拟 HUB 名称" => status.name = String::from(val),
                "状态" => status.online = if val == "在线" { true } else { false },
                "SecureNAT 机能" => {
                    status.secure_nat = if val == "无效" { false } else { true }
                }
                "会话数" => status.sessions = val.parse()?,
                "会话数 (客户端)" => status.sessions_client = val.parse()?,
                "会话数 (网桥)" => status.sessions_bridge = val.parse()?,
                "访问列表" => status.access_lists = val.parse()?,
                "用户数" => status.users = val.parse()?,
                "组数" => status.groups = val.parse()?,
                "MAC 表数" => status.mac_tables = val.parse()?,
                "IP 表数" => status.ip_tables = val.parse()?,
                "登录次数" => status.logins = val.parse()?,
                "发送单播数据包" => {
                    status.outgoing_unicast_packets = SoftEtherReader::decode_packets(val)?
                }
                "发送单播总量" => {
                    status.outgoing_unicast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "发送广播数据包" => {
                    status.outgoing_broadcast_packets = SoftEtherReader::decode_packets(val)?
                }
                "发送广播总量" => {
                    status.outgoing_broadcast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "接收单播数据包" => {
                    status.incoming_unicast_packets = SoftEtherReader::decode_packets(val)?
                }
                "接收单播总量" => {
                    status.incoming_unicast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                "接收广播数据包" => {
                    status.incoming_broadcast_packets = SoftEtherReader::decode_packets(val)?
                }
                "接收广播总量" => {
                    status.incoming_broadcast_bytes = SoftEtherReader::decode_bytes(val)?
                }
                _ => (),
            }
        }
        Ok(status)
    }
}

#[derive(Debug)]
pub struct HubStatus {
    pub name: String,
    pub online: bool,
    pub secure_nat: bool,
    pub sessions: f64,
    pub sessions_client: f64,
    pub sessions_bridge: f64,
    pub access_lists: f64,
    pub users: f64,
    pub groups: f64,
    pub mac_tables: f64,
    pub ip_tables: f64,
    pub logins: f64,
    pub outgoing_unicast_packets: f64,
    pub outgoing_unicast_bytes: f64,
    pub outgoing_broadcast_packets: f64,
    pub outgoing_broadcast_bytes: f64,
    pub incoming_unicast_packets: f64,
    pub incoming_unicast_bytes: f64,
    pub incoming_broadcast_packets: f64,
    pub incoming_broadcast_bytes: f64,
}

impl HubStatus {
    pub fn new() -> HubStatus {
        HubStatus {
            name: String::from(""),
            online: false,
            secure_nat: false,
            sessions: 0.0,
            sessions_client: 0.0,
            sessions_bridge: 0.0,
            access_lists: 0.0,
            users: 0.0,
            groups: 0.0,
            mac_tables: 0.0,
            ip_tables: 0.0,
            logins: 0.0,
            outgoing_unicast_packets: 0.0,
            outgoing_unicast_bytes: 0.0,
            outgoing_broadcast_packets: 0.0,
            outgoing_broadcast_bytes: 0.0,
            incoming_unicast_packets: 0.0,
            incoming_unicast_bytes: 0.0,
            incoming_broadcast_packets: 0.0,
            incoming_broadcast_bytes: 0.0,
        }
    }
}
