/// <summary> Parses the replay.server.battlelobby file in a replay file. </summary>
        /// <param name="replay"> The replay file to apply the parsed data to. </param>
        /// <param name="buffer"> The buffer containing the replay.initdata file. </param>
        public static void Parse(Replay replay, byte[] buffer)
        {
            using (var stream = new MemoryStream(buffer))
            {
                var reader = new BitReader(stream);
                
                int arrayLength = reader.ReadByte();
                var stringLength = reader.ReadByte();
                for (var i = 0; i < arrayLength; i++)
                {
                    reader.ReadString(stringLength);
                    reader.ReadBytes(2); // Unknown
                }

                // This is not always here; we can't blindly wait for 's2mh'
                /* while (!reader.EndOfStream)
                    if (reader.ReadString(1) == "s" && reader.ReadString(1) == "2" && reader.ReadString(1) == "m" && reader.ReadString(1) == "h")
                    {
                        reader.stream.Position -= 4;
                        break;
                    }

                if (reader.EndOfStream)
                    return;

                for (var j = 0; j < arrayLength; j++)
                {
                    reader.ReadString(4); // s2mh
                    reader.ReadBytes(2); // 0x00 0x00
                    reader.ReadBytes(2); // 'Realm'
                    reader.ReadBytes(32); // 'DepHash'
                }
                reader.ReadBytes(2); // 0x00 0x00

                // Different Skins / Artifacts / Characters - I think this is what users mouse over in the UI before the game
                arrayLength = reader.ReadInt16();
                for (var j = 0; j < arrayLength; j++)
                    reader.ReadString(reader.ReadByte());

                reader.ReadBytes(2); // 0x00 0x00
                reader.ReadInt16();

                do
                    arrayLength = reader.ReadByte();
                while (!reader.EndOfStream && (arrayLength == 0 || arrayLength == 1));

                if (reader.EndOfStream)
                    return; */

                // Now get the BattleTag for each player
                var battleTagDigits = new List<char>();
                foreach (var player in replay.Players.Where(i => i != null))
                {
                    // Find each player's name, and then their associated BattleTag
                    battleTagDigits.Clear();
                    var playerNameBytes = Encoding.UTF8.GetBytes(player.Name);
                    while (!reader.EndOfStream)
                    {
                        var isFound = true;
                        for (var i = 0; i < playerNameBytes.Length + 1; i++)
                            if ((i == playerNameBytes.Length && reader.ReadByte() != 35 /* '#' Character */) || (i < playerNameBytes.Length && reader.ReadByte() != playerNameBytes[i]))
                            {
                                isFound = false;
                                break;
                            }

                        if (isFound)
                            break;
                    }

                    // Get the numbers from the BattleTag
                    while (!reader.EndOfStream)
                    {
                        var currentCharacter = (char)reader.ReadByte();
                        if (char.IsDigit(currentCharacter))
                            battleTagDigits.Add(currentCharacter);
                        else
                            break;
                    }

                    if (reader.EndOfStream)
                        break;

                    player.BattleTag = int.Parse(string.Join("", battleTagDigits));
                }
            }
        }
        /// <summary> Parses the replay.initdata file in a replay file. </summary>
        /// <param name="replay"> The replay file to apply the parsed data to. </param>
        /// <param name="buffer"> The buffer containing the replay.initdata file. </param>
        public static void Parse(Replay replay, byte[] buffer)
        {
            using (var stream = new MemoryStream(buffer))
            {
                var reader = new BitReader(stream);
                
                var i = reader.ReadByte();

                var playerList = new string[i];
                for (int j = 0; j < i; j++)
                {
                    playerList[j] = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(8));

                    if (reader.ReadBoolean())
                    {
                        var clanTag = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(8));
                        // Console.WriteLine(clanTag);
                    }

                    if (reader.ReadBoolean())
                        // Clan Logo
                        reader.ReadBlobPrecededWithLength(40);

                    if (reader.ReadBoolean())
                    {
                        var highestLeague = reader.Read(8);
                        // Console.WriteLine(highestLeague);
                    }

                    if (reader.ReadBoolean())
                    {
                        var combinedRaceLevels = reader.ReadInt32();
                        // Console.WriteLine(combinedRaceLevels);
                    }

                    reader.ReadInt32(); // Random seed (So far, always 0 in Heroes)

                    if (reader.ReadBoolean())
                        reader.Read(8); // Race Preference

                    if (reader.ReadBoolean())
                        reader.Read(8); // Team Preference

                    reader.ReadBoolean(); //test map
                    reader.ReadBoolean(); //test auto
                    reader.ReadBoolean(); //examine
                    reader.ReadBoolean(); //custom interface

                    var unknown1 = reader.ReadInt32();

                    reader.Read(2);       //observer

                    var unknown2 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));
                    var unknown3 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));
                    var unknown4 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));
                    var unknown5 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));
                    var unknown6 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));
                    var unknown7 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));

                    // Console.WriteLine(unknown1 + unknown2 + unknown3 + unknown4 + unknown5 + unknown6 + unknown7);
                }

                // Marked as 'Random Value', so I will use as seed
                replay.RandomValue = (uint)reader.ReadInt32();

                reader.ReadBlobPrecededWithLength(10); // Dflt

                reader.ReadBoolean(); // Lock Teams
                reader.ReadBoolean(); // Teams Together
                reader.ReadBoolean(); // Advanced Shared Control
                reader.ReadBoolean(); // Random Races
                reader.ReadBoolean(); // BattleNet
                reader.ReadBoolean(); // AMM
                reader.ReadBoolean(); // Competitive
                reader.ReadBoolean(); // No Victory Or Defeat
                reader.ReadBoolean(); // Unknown 0
                reader.ReadBoolean(); // Unknown 1
                reader.ReadBoolean(); // Unknown 2
                reader.Read(2); // Fog
                reader.Read(2); // Observers
                reader.Read(2); // User Difficulty
                reader.ReadInt32(); reader.ReadInt32(); // 64 bit int: Client Debug Flags

                reader.Read(3); // Game Speed

                // Not sure what this 'Game Type' is
                reader.Read(3);

                var maxUsers = reader.Read(5);
                if (maxUsers != 10) // Max Players
                    replay.GameMode = GameMode.TryMe;

                reader.Read(5); // Max Observers
                reader.Read(5); // Max Players
                reader.Read(4); // + 1 = Max Teams
                reader.Read(6); // Max Colors
                reader.Read(8); // + 1 = Max Races
                reader.Read(8); // Max Controls

                replay.MapSize = new Point { X = (int)reader.Read(8), Y = (int)reader.Read(8) };
                if (replay.MapSize.Y == 1)
                    replay.MapSize.Y = replay.MapSize.X;
                else if (replay.MapSize.X == 0)
                    replay.MapSize.X = replay.MapSize.Y;

                // About 1000 bytes from here is a list of characters, character skins, character mounts, artifact selections, and other data
            }
        }