extern crate buffer;
extern crate clap;
extern crate gamenet;
extern crate logger;
#[macro_use]
extern crate teehistorian;
extern crate warn;
extern crate chrono;

use std::io;
use std::path::Path;
use std::process;
use teehistorian::Buffer;
use teehistorian::Error;
use teehistorian::Item;
use teehistorian::Reader;
use chrono::DateTime;
use chrono::Duration;

fn process(path: &Path) -> Result<(), Error> {
    let mut buffer = Buffer::new();
    let mut reader;
    let basetime;
    {
        let (hdr, th) = Reader::open(path, &mut buffer)?;
        reader = th;
        basetime = hdr.timestamp;
    }

    let mut tick = None;

    let mut clients: Vec<String> = vec![String::new(); 64];

    print!("[");
    let mut first = true;
    while let Some(item) = reader.read(&mut buffer)? {
        match item {
            Item::TickStart(t) => {
                assert!(tick.is_none());
                tick = Some(t);
            },
            Item::TickEnd(t) => {
                assert_eq!(tick, Some(t));
                tick = None;
            },
            Item::AuthInit(t) => {
                clients[t.cid as usize] = String::from_utf8_lossy(t.identity).to_string();
            },
            Item::AuthLogin(t) => {
                clients[t.cid as usize] = String::from_utf8_lossy(t.identity).to_string();
            },
            Item::AuthLogout(t) => {
                clients[t.cid as usize] = String::new();
            },
            Item::Drop(t) => {
                clients[t.cid as usize] = String::new();
            },
            Item::ConsoleCommand(t) => {
                if t.cid >= 0 && t.flag_mask & 128 == 0 {
                    let time = basetime + Duration::seconds((tick.expect("in tick") / 50) as i64);
                    if !first { print!(","); }
                    else { first = false; }
                    print!("[\"{}\",\"{}\",\"{}\"]", time.date().naive_utc(), clients[t.cid as usize], String::from_utf8_lossy(t.cmd));
                }
            },
            _ => {
                //println!("{} {:?}", tick.expect("in tick"), item);
            },
        }
    }
    println!("]");
    assert!(tick.is_none());
    Ok(())
}

fn main() {
    use clap::App;
    use clap::Arg;

    logger::init();

    let matches = App::new("Teehistorian auditor")
        .about("Reads teehistorian files and dumps admin/mod actions")
        .arg(Arg::with_name("TEEHISTORIAN")
            .help("Sets the teehistorian file to dump")
            .required(true)
        )
        .get_matches();

    let path = Path::new(matches.value_of_os("TEEHISTORIAN").unwrap());

    match process(path) {
        Ok(()) => {},
        Err(err) => {
            eprintln!("{}: {:?}", path.display(), err);
            process::exit(1);
        }
    }
}