#![feature(test)]

extern crate faf_replay_parser;
extern crate test;

#[cfg(test)]
mod from_memory {
    use test::Bencher;

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

    use faf_replay_parser::scfa::parser::parse_body_ticks;
    use faf_replay_parser::scfa::replay_command;
    use faf_replay_parser::scfa::*;

    const REPLAY_FILE: &str = "tests/data/6176549.scfareplay";

    #[bench]
    /// Build a new parser and use it to fully parse one replay from memory.
    fn build_and_parse_all(b: &mut Bencher) {
        // Read data to memory
        let mut f = BufReader::new(File::open(REPLAY_FILE).expect("Couldn't open file"));
        let mut data = Vec::new();
        f.read_to_end(&mut data).expect("Couldn't read from file");

        // Create parser and parse replay
        b.iter(|| {
            let parser = ParserBuilder::new().commands_all().build();
            let _replay = parser
                .parse(&mut data.as_slice())
                .expect("Failed to parse replay");
        });
    }

    fn bench_with_parser(parser: &Parser, b: &mut Bencher) {
        // Read data to memory
        let mut f = BufReader::new(File::open(REPLAY_FILE).expect("Couldn't open file"));
        let mut data = Vec::new();
        f.read_to_end(&mut data).expect("Couldn't read from file");

        // Parse replay
        b.iter(|| {
            let _replay = parser
                .parse(&mut data.as_slice())
                .expect("Failed to parse replay");
        });
    }

    #[bench]
    /// Fully parse one replay from memory. Reuses the same `Parser` for each iteration.
    fn parse_all(b: &mut Bencher) {
        let parser = ParserBuilder::new().commands_all().build();

        bench_with_parser(&parser, b);
    }

    #[bench]
    /// Extract the total tick count of a replay from memory. Reuses the same `Parser` for each
    /// iteration.
    fn parse_ticks_with_parser(b: &mut Bencher) {
        let parser = ParserBuilder::new()
            .command(replay_command::ADVANCE)
            .build();

        bench_with_parser(&parser, b);
    }

    #[bench]
    /// Extract the total tick count of a replay from memory using `body_ticks`
    fn parse_ticks_fast(b: &mut Bencher) {
        // Read data to memory
        let mut f = BufReader::new(File::open(REPLAY_FILE).expect("Couldn't open file"));
        let mut data = Vec::new();
        f.read_to_end(&mut data).expect("Couldn't read from file");

        let start = body_offset(&data).unwrap();
        let body = &data[start..];

        // Parse replay
        b.iter(|| {
            let _count = body_ticks(body).expect("Failed to parse replay");
        });
    }

    #[bench]
    /// Extract the total tick count of a replay from memory using `parse_body_ticks`
    fn parse_ticks_reader(b: &mut Bencher) {
        // Read data to memory
        let mut f = BufReader::new(File::open(REPLAY_FILE).expect("Couldn't open file"));
        let mut data = Vec::new();
        f.read_to_end(&mut data).expect("Couldn't read from file");

        let start = body_offset(&data).unwrap();

        // Parse replay
        b.iter(|| {
            let _count = parse_body_ticks(&mut &data[start..]).expect("Failed to parse replay");
        });
    }

    #[bench]
    /// Extract the total tick count of a replay from memory without saving each parsed command
    /// to the `commands` Vec. Reuses the same `Parser` for each iteration.
    fn parse_ticks_no_save_commands(b: &mut Bencher) {
        let parser = ParserBuilder::new()
            .command(replay_command::ADVANCE)
            .save_commands(false)
            .build();

        bench_with_parser(&parser, b);
    }
}
