#![feature(test)]

extern crate faf_replay_parser;
extern crate test;

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

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

    use faf_replay_parser::scfa::replay_command;
    use faf_replay_parser::scfa::ParserBuilder;
    use faf_replay_parser::ReplayReadError;

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

    #[bench]
    /// Open the replay and read its contents to an empty `Vec` using a `BufReader`.
    ///
    /// This should serve as a baseline for the minimum amount of time consumed by file IO
    /// in the parsing benchmarks.
    fn read_buffered(b: &mut Bencher) {
        b.iter(|| {
            let mut f = BufReader::new(File::open(SCFA_REPLAY_FILE).expect("Couldn't open file"));
            let mut data = Vec::new();

            f.read_to_end(&mut data).expect("Couldn't read from file");
        });
    }

    #[bench]
    /// Open the replay using a `BufReader` and fully parse it with all command parsers enabled.
    ///
    /// This should be the most time consuming operation that the parser could be used for.
    fn read_buffered_and_parse_all(b: &mut Bencher) {
        b.iter(|| {
            let mut f = BufReader::new(File::open(SCFA_REPLAY_FILE).expect("Couldn't open file"));
            let parser = ParserBuilder::new().commands_all().build();

            let _replay = parser.parse(&mut f).expect("Failed to parse replay");
        });
    }

    #[bench]
    /// Open the replay using a `BufReader` and extract the total tick count.
    ///
    /// This is probably the most common use case for replay parsing as the tick count is needed
    /// in order to determine the game length.
    fn read_buffered_and_parse_ticks(b: &mut Bencher) {
        b.iter(|| {
            let mut f = BufReader::new(File::open(SCFA_REPLAY_FILE).expect("Couldn't open file"));
            let parser = ParserBuilder::new()
                .command(replay_command::ADVANCE)
                .build();

            let _replay = parser.parse(&mut f).expect("Failed to parse replay");
        });
    }

    #[bench]
    /// Open the replay using a `BufReader` and call `Parser::parse` without any commands
    /// configured.
    ///
    /// This should effectively be the same as parsing only the header.
    fn read_buffered_and_parse_no_commands(b: &mut Bencher) {
        b.iter(|| {
            let mut f = BufReader::new(File::open(SCFA_REPLAY_FILE).expect("Couldn't open file"));
            let parser = ParserBuilder::new().build();

            let _replay = parser.parse(&mut f).expect("Failed to parse replay");
        });
    }

    #[bench]
    /// Open the replay using and fully parse it as a stream with all command parsers enabled.
    ///
    /// This should be the most time consuming operation that the parser could be used for.
    fn stream_and_parse_all(b: &mut Bencher) {
        b.iter(|| {
            let mut file = File::open(SCFA_REPLAY_FILE).expect("Couldn't open file");
            let mut stream = ParserBuilder::new().commands_all().build_stream();

            let _replay = {
                while stream.feed_reader(&mut file, 8192).unwrap() != 0 {
                    match stream.parse() {
                        Err(ReplayReadError::IO(_)) => {}
                        res => res.unwrap(),
                    }
                }
                stream.finalize().expect("Failed to parse replay")
            };
        });
    }

    #[cfg(feature = "faf")]
    mod faf {
        use super::*;

        const FAF_REPLAY_FILE_V1: &str = "tests/data/1265754.fafreplay";
        const FAF_REPLAY_FILE_V2: &str = "tests/data/100000.fafreplay";

        #[bench]
        fn extract_to_vec_v1(b: &mut Bencher) {
            b.iter(|| {
                let mut reader =
                    BufReader::new(File::open(FAF_REPLAY_FILE_V1).expect("Couldn't open file"));
                let mut out = Vec::new();

                faf_replay_parser::faf::extract_scfa(&mut reader, &mut out)
                    .expect("Failed to parse replay");
            });
        }

        #[bench]
        fn extract_to_vec_v2(b: &mut Bencher) {
            b.iter(|| {
                let mut reader =
                    BufReader::new(File::open(FAF_REPLAY_FILE_V2).expect("Couldn't open file"));
                let mut out = Vec::new();

                faf_replay_parser::faf::extract_scfa(&mut reader, &mut out)
                    .expect("Failed to parse replay");
            });
        }
    }
}
