using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Text;

using InfServer.Logic;
using InfServer.Game;
using InfServer.Scripting;
using InfServer.Bots;
using InfServer.Protocol;

using Assets;

namespace InfServer.Script.GameType_Multi
{
    public class Match
    {
        private Arena _arena;
        public Team _team1;
        public Team _team2;
        private CfgInfo _config;                //The zone config
        private int _deathMatchTimer;
        private int _lastTickerUpdate;
        private int _lastKillStreakUpdate;
        public int LeagueSeason;
        public int OvertimeCount;
        public bool overtime;
        public bool AwardMVP;

        #region Stat Recording
        public string FileName;
        private List<Team> activeTeams = null;
        private Team lastTeam1, lastTeam2;  //Records the previous team before overtime starts(We get team stats from this since ot is not recorded)
        public Team victoryTeam = null;
        DateTime startTime;

        /// <summary>
        /// Current game player stats
        /// </summary>
        private Dictionary<string, PlayerStat> _savedPlayerStats;
        /// <summary>
        /// Only used when overtime is about to be initiated
        /// </summary>
        private Dictionary<string, PlayerStat> _lastSavedStats;

        /// <summary>
        /// Stores our player information
        /// </summary>
        private class PlayerStat
        {
            public Player player { get; set; }
            public string teamname { get; set; }
            public string alias { get; set; }
            public string squad { get; set; }
            public long points { get; set; }
            public int kills { get; set; }
            public int deaths { get; set; }
            public int killPoints { get; set; }
            public int assistPoints { get; set; }
            public int bonusPoints { get; set; }
            public int playSeconds { get; set; }
            public bool hasPlayed { get; set; }
            public string classType { get; set; }

            //Kill stats
            public ItemInfo.Projectile lastUsedWep { get; set; }
            public int lastUsedWepKillCount { get; set; }
            public long lastUsedWepTick { get; set; }
            public int lastKillerCount { get; set; }

            //Medic stats
            public int potentialHealthHealed { get; set; }

            public bool onPlayingField { get; set; }
        }
        #endregion

        #region Misc Gameplay Pointers
        private Team BountyA, BountyB;
        private Player lastKiller;

        public Match(Arena arena)
        {
            _arena = arena;
            _config = arena._server._zoneConfig;
            _savedPlayerStats = new Dictionary<string, PlayerStat>();

            //Lets see what season we are in (Match related)
            //Lets try from the usl site first then season directory if that fails
            string season = string.Empty;

            if (!GetUslSeason(@"http://www.uslzone.com/usl/view_schedule.php", out season))
            { season = Logic_File.GetSeasonDirectory(); }
            if (season.Contains("Season"))
                season = (season.Split(' ')).ElementAt(1);
            if (!Int32.TryParse(season, out LeagueSeason))
                LeagueSeason = 1;
        }

        public void setTeams(Team team1, Team team2, bool isScrim)
        {
            _team1 = team1;
            _team2 = team2;
        }


        public void Poll(int now)
        {

            if (now - _lastTickerUpdate >= 1000)
            {
                UpdateTickers();
                _lastTickerUpdate = now;
            }

            if (now - _lastKillStreakUpdate >= 500)
            {
                UpdateKillStreaks();
                _lastKillStreakUpdate = now;
            }
        }
        #endregion

        #region Gametype Events
        public void gameStart()
        {
            if (_arena.ActiveTeams.Count() == 0)
                return;

            ResetKiller(null);

            _savedPlayerStats.Clear();
            foreach (Player p in _arena.Players)
            {
                PlayerStat temp = new PlayerStat();
                temp.teamname = p._team._name;
                temp.alias = p._alias;
                temp.points = 0;
                temp.assistPoints = 0;
                temp.bonusPoints = 0;
                temp.killPoints = 0;
                temp.playSeconds = 0;
                temp.squad = p._squad;
                temp.kills = 0;
                temp.deaths = 0;
                temp.player = p;
                temp.hasPlayed = p.IsSpectator ? false : true;
                if (!p.IsSpectator)
                {
                    if (p._baseVehicle != null)
                        temp.classType = p._baseVehicle._type.Name;
                }

                temp.lastKillerCount = 0;
                temp.lastUsedWep = null;
                temp.lastUsedWepKillCount = 0;
                temp.lastUsedWepTick = -1;
                temp.potentialHealthHealed = 0;
                temp.onPlayingField = false;
                _savedPlayerStats.Add(p._alias, temp);
            }

            //Ranked?
            if (_arena._isMatch)
                MatchSetup();


            UpdateTickers();


            //Let everyone know
            _arena.sendArenaMessage("Game has started!");
            _arena.setTicker(1, 3, 1800 * 100, "Time Left: ",
                delegate ()
                {   //Trigger game end
                    _arena.gameEnd();
                }
            );
        }

        public bool playerFlagAction(Player player, bool bPickup, bool bInPlace, LioInfo.Flag flag)
        {


            return false;
        }

            /// <summary>
            /// Called when the statistical breakdown is displayed
            /// </summary>
            public void individualBreakdown(Player from, bool bCurrent)
        {	//Allows additional "custom" breakdown information
            from.sendMessage(0, "#Team Statistics Breakdown");

            IEnumerable<Team> activeTeams = _arena.Teams.OrderByDescending(entry => entry._currentGameKills).ToList();
            int idx = 3;	//Only display top three teams
            foreach (Team t in activeTeams)
            {
                if (t == null)
                    continue;

                if (idx-- == 0)
                    break;

                string format = "!3rd (K={0} D={1}): {2}";
                switch (idx)
                {
                    case 2:
                        format = "!1st (K={0} D={1}): {2}";
                        break;
                    case 1:
                        format = "!2nd (K={0} D={1}): {2}";
                        break;
                }

                from.sendMessage(0, string.Format(format,
                    t._currentGameKills, t._currentGameDeaths,
                    t._name));
            }

            from.sendMessage(0, "#Individual Statistics Breakdown");
            idx = 3;        //Only display the top 3 players
            List<Player> rankers = new List<Player>();
            foreach (Player p in _arena.Players.ToList())
            {
                if (p == null)
                    continue;
                if (_savedPlayerStats.ContainsKey(p._alias) && _savedPlayerStats[p._alias].hasPlayed)
                    rankers.Add(p);
            }

            if (rankers.Count > 0)
            {
                var rankedPlayerGroups = rankers.Select(player => new
                {
                    Alias = player._alias,
                    Kills = _savedPlayerStats[player._alias].kills,
                    Deaths = _savedPlayerStats[player._alias].deaths
                })
                .GroupBy(pl => pl.Kills)
                .OrderByDescending(k => k.Key)
                .Take(idx)
                .Select(g => g.OrderBy(plyr => plyr.Deaths));

                foreach (var group in rankedPlayerGroups)
                {
                    if (idx <= 0)
                        break;

                    string placeWord = "";
                    string format = " (K={0} D={1}): {2}";
                    switch (idx)
                    {
                        case 3:
                            placeWord = "!1st";
                            break;
                        case 2:
                            placeWord = "!2nd";
                            break;
                        case 1:
                            placeWord = "!3rd";
                            break;
                    }

                    idx -= group.Count();
                    if (group.First() != null)
                        from.sendMessage(0, string.Format(placeWord + format, group.First().Kills,
                            group.First().Deaths, string.Join(", ", group.Select(g => g.Alias))));
                }

                IEnumerable<Player> specialPlayers = rankers.OrderByDescending(player => _savedPlayerStats[player._alias].deaths);
                int topDeaths = (specialPlayers.First() != null ? _savedPlayerStats[specialPlayers.First()._alias].deaths : 0), deaths = 0;
                if (topDeaths > 0)
                {
                    from.sendMessage(0, "Most Deaths");
                    int i = 0;
                    List<string> mostDeaths = new List<string>();
                    foreach (Player p in specialPlayers)
                    {
                        if (p == null)
                            continue;

                        if (_savedPlayerStats.ContainsKey(p._alias))
                        {
                            deaths = _savedPlayerStats[p._alias].deaths;
                            if (deaths == topDeaths)
                            {
                                if (i++ >= 1)
                                    mostDeaths.Add(p._alias);
                                else
                                    mostDeaths.Add(string.Format("(D={0}): {1}", deaths, p._alias));
                            }
                        }
                    }
                    if (mostDeaths.Count > 0)
                    {
                        string s = string.Join(", ", mostDeaths.ToArray());
                        from.sendMessage(0, s);
                    }
                }

                IEnumerable<Player> Healed = rankers.Where(player => _savedPlayerStats[player._alias].potentialHealthHealed > 0);
                if (Healed.Count() > 0)
                {
                    IEnumerable<Player> mostHealed = Healed.OrderByDescending(player => _savedPlayerStats[player._alias].potentialHealthHealed);
                    idx = 3;
                    from.sendMessage(0, "&Most HP Healed");
                    foreach (Player p in mostHealed)
                    {
                        if (p == null) continue;
                        if (_savedPlayerStats[p._alias] != null)
                        {
                            if (idx-- <= 0)
                                break;

                            string placeWord = "&3rd";
                            string format = " (HP Total={0}): {1}";
                            switch (idx)
                            {
                                case 2:
                                    placeWord = "&1st";
                                    break;
                                case 1:
                                    placeWord = "&2nd";
                                    break;
                            }
                            from.sendMessage(0, string.Format(placeWord + format, _savedPlayerStats[p._alias].potentialHealthHealed, p._alias));
                        }
                    }
                }
            }

            //Are they on the list?
            if (_savedPlayerStats.ContainsKey(from._alias))
            {
                string personalFormat = "!Personal Score: (K={0} D={1})";
                from.sendMessage(0, string.Format(personalFormat,
                    _savedPlayerStats[from._alias].kills,
                    _savedPlayerStats[from._alias].deaths));
            }
            //If not, give them the generic one
            else
            {
                string personalFormat = "!Personal Score: (K=0 D=0)";
                from.sendMessage(0, personalFormat);
            }
        }

        public void gameEnd()
        {
            //Ignore squad battles!
            if (_arena._isMatch)
            {
                if (!overtime)
                {
                    //Make sure to get an accurate playing time
                    foreach (KeyValuePair<string, PlayerStat> pair in _savedPlayerStats)
                    {   //Did they play or exist?
                        if (!pair.Value.hasPlayed || pair.Value.player == null)
                            continue;
                        //Stats are migrated first due to game.end being called before our script callsync
                        pair.Value.playSeconds = pair.Value.player.StatsLastGame.playSeconds;
                    }
                }
                MatchEnd();
            }
        }

        public void gameReset()
        {

        }
        #endregion

        #region Player Events

        /// <summary>
        /// Triggered when a player tries to heal
        /// </summary>
        public void PlayerRepair(Player from, ItemInfo.RepairItem item)
        {
            if (!_savedPlayerStats.ContainsKey(from._alias))
                return;
            if (item.repairType == 0 && item.repairDistance < 0)
            {   //Get all players near
                List<Player> players = _arena.getPlayersInRange(from._state.positionX, from._state.positionY, -item.repairDistance);
                int totalHealth = 0;
                foreach (Player p in players)
                {
                    if (p == null || p == from || p._state.health >= 100 || p._state.health <= 0)
                        continue;
                    totalHealth += (p._baseVehicle._type.Hitpoints - p._state.health);
                }
                _savedPlayerStats[from._alias].potentialHealthHealed += totalHealth;

                if (_arena._isMatch)
                    from.ZoneStat4 += totalHealth;
            }
        }

        public bool playerUnspec(Player player)
        {

            //Add them to the list if not in it
            if (!_savedPlayerStats.ContainsKey(player._alias))
            {
                PlayerStat temp = new PlayerStat();
                temp.alias = player._alias;
                temp.squad = player._squad;
                temp.assistPoints = 0;
                temp.bonusPoints = 0;
                temp.killPoints = 0;
                temp.points = 0;
                temp.playSeconds = 0;
                temp.deaths = 0;
                temp.kills = 0;
                temp.player = player;
                temp.onPlayingField = false;
                _savedPlayerStats.Add(player._alias, temp);
            }
            _savedPlayerStats[player._alias].hasPlayed = true;
            if (player._baseVehicle != null)
                _savedPlayerStats[player._alias].classType = player._baseVehicle._type.Name;

            return true;
        }

        public void playerSpec(Player player)
        {


        }

        public void playerSpawn(Player player, bool death)
        {
        }

        public void playerEnterArena(Player player)
        {
            //Add them to the list if not in it
            if (!_savedPlayerStats.ContainsKey(player._alias))
            {
                PlayerStat temp = new PlayerStat();
                temp.squad = player._squad;
                temp.assistPoints = 0;
                temp.bonusPoints = 0;
                temp.killPoints = 0;
                temp.points = 0;
                temp.playSeconds = 0;
                temp.alias = player._alias;
                temp.deaths = 0;
                temp.kills = 0;
                temp.player = player;
                temp.onPlayingField = false;
                _savedPlayerStats.Add(player._alias, temp);
            }
            _savedPlayerStats[player._alias].teamname = player._team._name;
            _savedPlayerStats[player._alias].hasPlayed = player.IsSpectator ? false : true;
            if (player._baseVehicle != null)
                _savedPlayerStats[player._alias].classType = player._baseVehicle._type.Name;
        }

        public void playerLeaveArena(Player player)
        {

        }


        public void playerExplosion(Player player, ItemInfo.Projectile weapon, short posX, short posY, short posZ)
        {

        }

        public void playerPlayerKill(Player victim, Player killer)
        {   //Update our kill streak
             UpdateKiller(killer);
             UpdateDeath(victim, killer);

            if (_savedPlayerStats.ContainsKey(killer._alias))
            {
                _savedPlayerStats[killer._alias].kills++;
                long wepTick = _savedPlayerStats[killer._alias].lastUsedWepTick;
                if (wepTick != -1)
                    UpdateWeaponKill(killer);
            }
            if (_savedPlayerStats.ContainsKey(victim._alias))
                _savedPlayerStats[victim._alias].deaths++;

            if (killer != null && victim != null && victim._bounty >= 300)
                _arena.sendArenaMessage(string.Format("{0} has ended {1}'s bounty.", killer._alias, victim._alias), 8);
        }

        public void playerDeath(Player victim, Player killer, Helpers.KillType killType, CS_VehicleDeath update)
        {
         
        }
        #endregion

        #region Match calls
        /// <summary>
        /// Gets the arena ready for our match
        /// </summary>
        private void MatchSetup()
        {
            foreach (Player p in _arena.Players)
            {
                //Make sure no one has grant
                if (_arena.IsOwner(p))
                {
                    _arena._owner.Remove(p._alias);
                    //Reset any temp powers they might have
                    if (!p._developer && !p._admin && p._permissionTemp > Data.PlayerPermission.Normal)
                        p._permissionTemp = Data.PlayerPermission.Normal;
                }

                //Turn off banners for in game players (can cause the player lag by spamming them)
                if (!p.IsSpectator)
                    p._bAllowBanner = false;
            }

            //Record our start time if this is our initial start time
            if (!overtime)
            {
                startTime = DateTime.Now.ToLocalTime();
            }
            else
                OvertimeCount++;

            activeTeams = _arena.ActiveTeams.ToList();
        }

        /// <summary>
        /// Ends our gameplay and shows the results
        /// </summary>
        private void MatchEnd()
        {
            if (activeTeams == null || activeTeams.Count == 0)
                activeTeams = _arena.Teams.OrderByDescending(entry => entry._currentGameKills).ToList();

            Team team2 = activeTeams.Count > 1 ? activeTeams.ElementAt(1) : null;
            Team team1 = activeTeams.Count > 0 ? activeTeams.ElementAt(0) : null;

            //Spec all in game players
            foreach (Player p in _arena.PlayersIngame.ToList())
                p.spec();

            switch (activeTeams.Count)
            {
                case 0: //No teams, just break
                    break;
                case 1:
                    //Only one team? Just show whatever results we have
                    int idx = 2;
                    foreach (Team t in activeTeams)
                    {
                        if (idx-- == 0)
                            break;

                        string format = "!2nd (K={0} D={1}): {2}";
                        switch (idx)
                        {
                            case 1:
                                format = "!1st (K={0} D={1}): {2}";
                                break;
                        }
                        _arena.sendArenaMessage(string.Format(format, t._currentGameKills, t._currentGameDeaths, t._name));
                    }
                    break;
                case 2:
                    if (team1._currentGameKills > team2._currentGameKills)
                    {
                        victoryTeam = team1;
                        _arena.sendArenaMessage(string.Format("{0} has won with a {1}-{2} victory!", team1._name, team1._currentGameKills, team2._currentGameKills));
                        foreach (Player p in _arena.Players)
                        {
                            if (p._squad.Contains(team1._name))
                                p.ZoneStat1++;
                            if (p._squad.Contains(team2._name))
                                p.ZoneStat2++;
                        }
                    }
                    else if (team2._currentGameKills > team1._currentGameKills)
                    {
                        victoryTeam = team2;
                        _arena.sendArenaMessage(string.Format("{0} has won with a {1}-{2} victory!", team2._name, team2._currentGameKills, team1._currentGameKills));
                        foreach (Player p in _arena.Players)
                        {
                            if (p._squad.Contains(team2._name))
                                p.ZoneStat1++;
                            if (p._squad.Contains(team1._name))
                                p.ZoneStat2++;
                        }
                    }
                    else
                    {
                        _arena.sendArenaMessage(GetOT());

                        //We in overtime?
                        if (!overtime)
                        {   //Nope! Lets migrate stats, we migrate only once because ot is not recorded
                            lastTeam1 = new Team(_arena, _arena._server);
                            lastTeam1._name = team1._name;
                            lastTeam1._currentGameKills = team1._currentGameKills;
                            lastTeam1._currentGameDeaths = team1._currentGameDeaths;

                            lastTeam2 = new Team(_arena, _arena._server);
                            lastTeam2._name = team2._name;
                            lastTeam2._currentGameKills = team2._currentGameKills;
                            lastTeam2._currentGameDeaths = team2._currentGameDeaths;
                            _lastSavedStats = new Dictionary<string, PlayerStat>();
                            foreach (KeyValuePair<string, PlayerStat> pair in _savedPlayerStats)
                            {
                                if (pair.Value.hasPlayed)
                                    _lastSavedStats.Add(pair.Key, pair.Value);
                            }
                        }
                        overtime = true;

                        _arena.gameReset();
                        return; //Since this is ot, we want to return.. not continue
                    }
                    //Save to a file
                    ExportStats(team1, team2);

                    _arena._isMatch = false;
                    OvertimeCount = 0;
                    AwardMVP = true;
                    _arena.gameReset();
                    break;
            }
        }

        private string defaultOT = "Game ended in a draw. ";
        /// <summary>
        /// Gets the overtime string used for an arena message
        /// </summary>
        public string GetOT()
        {
            switch (OvertimeCount)
            {
                case 0:
                    return defaultOT + "Going into OVERTIME!!";
                case 1:
                    return defaultOT + "Going into DOUBLE OVERTIME!!";
                case 2:
                    return defaultOT + "Going into TRIPLE OVERTIME!!";
                case 3:
                    return defaultOT + "Going into QUADRUPLE OVERTIME?!?";
                default:
                    return defaultOT + "Script is tired of counting, ref's take over. AFK!!";
            }
        }


        /// <summary>
        /// Saves all league stats to a file and website
        /// </summary>
        private void ExportStats(Team team1, Team team2)
        {   //Sanity checks
            if (overtime)
            {
                if (_lastSavedStats.Count < 1)
                    return;

                string OT = "OT";
                if (OvertimeCount > 0)
                {
                    switch (OvertimeCount)
                    {
                        case 1:
                            OT = "D-OT";
                            break;
                        case 2:
                            OT = "T-OT";
                            break;
                        case 3:
                            OT = "Q-OT";
                            break;
                        default:
                            OT = "OT++";
                            break;
                    }
                }
                //Make the file with current date and filename
                string name1 = lastTeam1._name.Trim(' ');
                string name2 = lastTeam2._name.Trim(' ');
                string filename = string.Format("{0}vs{1} {2}", name1, name2, startTime.ToLocalTime().ToString());
                FileName = filename;
                StreamWriter fs = Logic_File.CreateStatFile(filename, string.Format("Season {0}", LeagueSeason.ToString()));

                fs.WriteLine();
                fs.WriteLine(string.Format("Team Name = {0}, Kills = {1}, Deaths = {2}, Win = {3}, In OT? = {4}",
                    lastTeam1._name, lastTeam1._currentGameKills, lastTeam1._currentGameDeaths, lastTeam1._name.Equals(victoryTeam._name) ? "Yes" : "No", OT));
                fs.WriteLine("--------------------------------------------------------------------");
                foreach (KeyValuePair<string, PlayerStat> p in _lastSavedStats)
                {
                    if (string.IsNullOrWhiteSpace(p.Key))
                        continue;

                    if (!p.Value.hasPlayed)
                        continue;

                    if (p.Value.teamname.Equals(team2._name))
                        continue;

                    bool yes = true; //We were an nt
                    if (team1._name.Contains(p.Value.squad))
                        yes = false; //We arent an nt
                    fs.WriteLine(string.Format("Name = {0}, NT? = {1}, Kills = {2}, Deaths = {3} PlaySeconds = {4}, Class = {5}",
                        p.Value.alias,
                        yes == false ? "No" : "Yes",
                        p.Value.kills,
                        p.Value.deaths,
                        p.Value.playSeconds,
                        p.Value.classType));
                }

                fs.WriteLine("---------------------------Medics-----------------------------------");
                foreach (KeyValuePair<string, PlayerStat> p in _lastSavedStats)
                {
                    if (string.IsNullOrWhiteSpace(p.Key))
                        continue;
                    if (!p.Value.hasPlayed)
                        continue;
                    if (p.Value.teamname.Equals(team2._name))
                        continue;
                    if (p.Value.potentialHealthHealed <= 0)
                        continue;
                    fs.WriteLine(string.Format("Name = {0}, Health Healed = {1}", p.Value.alias, p.Value.potentialHealthHealed));
                }
                fs.WriteLine("--------------------------------------------------------------------");
                fs.WriteLine();

                fs.WriteLine(string.Format("Team Name = {0}, Kills = {1}, Deaths = {2}, Win = {3}, In OT? = {4}",
                    lastTeam2._name, lastTeam2._currentGameKills, lastTeam2._currentGameDeaths, lastTeam2._name.Equals(victoryTeam._name) ? "Yes" : "No", OT));
                fs.WriteLine("--------------------------------------------------------------------");
                foreach (KeyValuePair<string, PlayerStat> p in _lastSavedStats)
                {
                    if (string.IsNullOrWhiteSpace(p.Key))
                        continue;

                    if (!p.Value.hasPlayed)
                        continue;

                    if (p.Value.teamname.Equals(team1._name))
                        continue;

                    bool yes = true; //We were an nt
                    if (team2._name.Contains(p.Value.squad))
                        yes = false; //We arent an nt
                    fs.WriteLine(string.Format("Name = {0}, NT? = {1}, Kills = {2}, Deaths = {3}, PlaySeconds = {4}, Class = {5}",
                        p.Value.alias,
                        yes == false ? "No" : "Yes",
                        p.Value.kills,
                        p.Value.deaths,
                        p.Value.playSeconds,
                        p.Value.classType));
                }

                fs.WriteLine("---------------------------Medics-----------------------------------");
                foreach (KeyValuePair<string, PlayerStat> p in _lastSavedStats)
                {
                    if (string.IsNullOrWhiteSpace(p.Key))
                        continue;
                    if (!p.Value.hasPlayed)
                        continue;
                    if (p.Value.teamname.Equals(team1._name))
                        continue;
                    if (p.Value.potentialHealthHealed <= 0)
                        continue;
                    fs.WriteLine(string.Format("Name = {0}, Health Healed = {1}", p.Value.alias, p.Value.potentialHealthHealed));
                }
                fs.WriteLine("--------------------------------------------------------------------");

                //Now set the format as per the export file function in the client
                foreach (KeyValuePair<string, PlayerStat> p in _lastSavedStats)
                {
                    if (string.IsNullOrWhiteSpace(p.Key))
                        continue;

                    if (!p.Value.hasPlayed)
                        continue;

                    fs.WriteLine(string.Format("{0},{1},{2},{3},{4},0,{5},0,{6},0,0,0,0,{7},{8}",
                        p.Value.alias,
                        p.Value.squad,
                        p.Value.points,
                        p.Value.kills,
                        p.Value.deaths,
                        p.Value.assistPoints,
                        p.Value.playSeconds,
                        p.Value.classType,
                        (p.Value.potentialHealthHealed <= 0 ? 0 : p.Value.potentialHealthHealed)));
                }
                fs.WriteLine("--------------------------------------------------------------------");

                //Close it
                fs.Close();

                //Report it
                _arena.sendArenaMessage("Stats have been backed up to a file. Please stay till refs are done recording.", 0);
            }
            else
            {
                //Make the file with current date and filename
                string name1 = team1._name.Trim(' ');
                string name2 = team2._name.Trim(' ');
                string filename = string.Format("{0}vs{1} {2}", name1, name2, startTime.ToLocalTime().ToString());
                FileName = filename;
                StreamWriter fs = Logic_File.CreateStatFile(filename, string.Format("Season {0}", LeagueSeason.ToString()));

                fs.WriteLine();
                fs.WriteLine(string.Format("Team Name = {0}, Kills = {1}, Deaths = {2}, Win = {3}, In OT? = No",
                    team1._name, team1._currentGameKills, team1._currentGameDeaths, team1 == victoryTeam ? "Yes" : "No"));
                fs.WriteLine("--------------------------------------------------------------------");
                foreach (KeyValuePair<string, PlayerStat> p in _savedPlayerStats)
                {
                    if (string.IsNullOrWhiteSpace(p.Key))
                        continue;

                    if (!p.Value.hasPlayed)
                        continue;

                    if (p.Value.teamname.Equals(team2._name))
                        continue;

                    bool yes = true; //We were an nt
                    if (team1._name.Contains(p.Value.squad))
                        yes = false; //We arent an nt
                    fs.WriteLine(string.Format("Name = {0}, NT? = {1}, Kills = {2}, Deaths = {3}, PlaySeconds = {4}, Class = {5}",
                        p.Value.alias,
                        yes == false ? "No" : "Yes",
                        p.Value.kills,
                        p.Value.deaths,
                        p.Value.playSeconds,
                        p.Value.classType));
                }

                fs.WriteLine("---------------------------Medics-----------------------------------");
                foreach (KeyValuePair<string, PlayerStat> p in _savedPlayerStats)
                {
                    if (string.IsNullOrWhiteSpace(p.Key))
                        continue;
                    if (!p.Value.hasPlayed)
                        continue;
                    if (p.Value.teamname.Equals(team2._name))
                        continue;
                    if (p.Value.potentialHealthHealed <= 0)
                        continue;
                    fs.WriteLine(string.Format("Name = {0}, Health Healed = {1}", p.Value.alias, p.Value.potentialHealthHealed));
                }
                fs.WriteLine("--------------------------------------------------------------------");
                fs.WriteLine();

                fs.WriteLine(string.Format("Team Name = {0}, Kills = {1}, Deaths = {2}, Win = {3}, In OT? = No",
                    team2._name, team2._currentGameKills, team2._currentGameDeaths, team2 == victoryTeam ? "Yes" : "No"));
                fs.WriteLine("--------------------------------------------------------------------");
                foreach (KeyValuePair<string, PlayerStat> p in _savedPlayerStats)
                {
                    if (string.IsNullOrWhiteSpace(p.Key))
                        continue;

                    if (!p.Value.hasPlayed)
                        continue;

                    if (p.Value.teamname.Equals(team1._name))
                        continue;

                    bool yes = true; //We were an nt
                    if (team2._name.Contains(p.Value.squad))
                        yes = false; //We arent an nt
                    fs.WriteLine(string.Format("Name = {0}, NT? = {1}, Kills = {2}, Deaths = {3}, PlaySeconds = {4}, Class = {5}",
                        p.Value.alias,
                        yes == false ? "No" : "Yes",
                        p.Value.kills,
                        p.Value.deaths,
                        p.Value.playSeconds,
                        p.Value.classType));
                }

                fs.WriteLine("---------------------------Medics-----------------------------------");
                foreach (KeyValuePair<string, PlayerStat> p in _savedPlayerStats)
                {
                    if (string.IsNullOrWhiteSpace(p.Key))
                        continue;
                    if (!p.Value.hasPlayed)
                        continue;
                    if (p.Value.teamname.Equals(team1._name))
                        continue;
                    if (p.Value.potentialHealthHealed <= 0)
                        continue;
                    fs.WriteLine(string.Format("Name = {0}, Health Healed = {1}", p.Value.alias, p.Value.potentialHealthHealed));
                }
                fs.WriteLine("--------------------------------------------------------------------");

                //Now set the format as per the export file function in the client
                foreach (KeyValuePair<string, PlayerStat> p in _savedPlayerStats)
                {
                    if (string.IsNullOrWhiteSpace(p.Key))
                        continue;

                    if (!p.Value.hasPlayed)
                        continue;

                    fs.WriteLine(string.Format("{0},{1},{2},{3},{4},0,{5},0,{6},0,0,0,0,{7},{8}",
                        p.Value.alias,
                        p.Value.squad,
                        p.Value.points,
                        p.Value.kills,
                        p.Value.deaths,
                        p.Value.assistPoints,
                        p.Value.playSeconds,
                        p.Value.classType,
                        (p.Value.potentialHealthHealed <= 0 ? 0 : p.Value.potentialHealthHealed)));
                }
                fs.WriteLine("--------------------------------------------------------------------");

                //Close it
                fs.Close();

                //Report it
                _arena.sendArenaMessage("Stats have been backed up to a file. Please stay till refs are done recording.", 0);
            }
        }

        /// <summary>
        /// Checks for the current season from the usl site and returns a string
        /// </summary>
        public bool GetUslSeason(string url, out string result)
        {
            System.Net.WebClient webclient = new System.Net.WebClient();
            result = string.Empty;
            try
            {
                byte[] data = webclient.DownloadData(new Uri(url));
                if (data.Length <= 0)
                { return false; }
                else
                {
                    string downloadedString = Encoding.ASCII.GetString(data);
                    string pattern = @"\b(?i:s)eason\s\d+\b";
                    foreach (System.Text.RegularExpressions.Match match in System.Text.RegularExpressions.Regex.Matches(downloadedString, pattern))
                    {
                        result = match.Value;
                        break;
                    }
                }
                webclient.Dispose();
            }
            catch
            { return false; }

            if (string.IsNullOrEmpty(result))
            { return false; }

            return true;
        }

        #endregion 


        #region Updation Calls
        /// <summary>
        /// Updates our players kill streak timer
        /// </summary>
        private void UpdateKillStreaks()
        {
            foreach (PlayerStat p in _savedPlayerStats.Values)
            {
                if (p.lastUsedWepTick == -1)
                    continue;

                if (Environment.TickCount - p.lastUsedWepTick <= 0)
                    ResetWeaponTicker(p.player);
            }
        }

        /// <summary>
        /// Updates our tickers
        /// </summary>
        public void UpdateTickers()
        {
            if (!_arena._bGameRunning)
            { return; }

            IEnumerable<Team> active = _arena.ActiveTeams;
            if (activeTeams != null && activeTeams.Count() > 0)
            {
                active = activeTeams;
            }

            Team collie = active.Count() > 1 ? active.ElementAt(1) : _arena.getTeamByName(_config.teams[0].name);
            Team titan = active.Count() > 0 ? active.ElementAt(0) : _arena.getTeamByName(_config.teams[1].name);

            string format = string.Format("{0}={1} - {2}={3}", titan._name, titan._currentGameKills, collie._name, collie._currentGameKills);
            //We playing more events at the same time?
            if (active.Count() > 3)
            {
                Team third = active.ElementAt(2);
                Team fourth = active.ElementAt(3);
                format = string.Format("{0}={1} - {2}={3} | {4}={5} - {6}={7}", titan._name, titan._currentGameKills, collie._name, collie._currentGameKills,
                    third._name, third._currentGameKills, fourth._name, fourth._currentGameKills);
            }
            _arena.setTicker(1, 2, 0, format);

            //Personal Scores
            _arena.setTicker(2, 1, 0, delegate (Player p)
            {
                //Update their ticker
                if (_savedPlayerStats.ContainsKey(p._alias))
                    return string.Format("HP={0}          Personal Score: Kills={1} - Deaths={2}",
                        p._state.health,
                        _savedPlayerStats[p._alias].kills,
                        _savedPlayerStats[p._alias].deaths);
                return "";
            });

            //1st and 2nd place
            List<Player> ranked = new List<Player>();
            foreach (Player p in _arena.Players)
            {
                if (p == null)
                    continue;
                if (_savedPlayerStats.ContainsKey(p._alias) && _savedPlayerStats[p._alias].hasPlayed)
                    ranked.Add(p);
            }

            IEnumerable<Player> ranking = ranked.OrderBy(player => _savedPlayerStats[player._alias].deaths).OrderByDescending(player => _savedPlayerStats[player._alias].kills);
            int idx = 3; format = "";
            foreach (Player rankers in ranking)
            {
                if (idx-- == 0)
                    break;

                switch (idx)
                {
                    case 2:
                        format = string.Format("1st: {0}(K={1} D={2})", rankers._alias,
                          _savedPlayerStats[rankers._alias].kills, _savedPlayerStats[rankers._alias].deaths);
                        break;
                    case 1:
                        format = (format + string.Format(" 2nd: {0}(K={1} D={2})", rankers._alias,
                          _savedPlayerStats[rankers._alias].kills, _savedPlayerStats[rankers._alias].deaths));
                        break;
                }
            }
            if (!_arena.recycling)
                _arena.setTicker(2, 0, 0, format);
        }

        /// <summary>
        /// Resets the last killer object
        /// </summary>
        public void ResetKiller(Player killer)
        {
            lastKiller = killer;
        }

        /// <summary>
        /// Resets the weapon ticker to default (Time Expired)
        /// </summary>
        public void ResetWeaponTicker(Player target)
        {
            if (_savedPlayerStats.ContainsKey(target._alias))
            {
                _savedPlayerStats[target._alias].lastUsedWep = null;
                _savedPlayerStats[target._alias].lastUsedWepKillCount = 0;
                _savedPlayerStats[target._alias].lastUsedWepTick = -1;
            }
        }

        /// <summary>
        /// Updates the killer and their counter
        /// </summary>
        public void UpdateKiller(Player killer)
        {
            if (_savedPlayerStats.ContainsKey(killer._alias))
            {
                _savedPlayerStats[killer._alias].lastKillerCount++;
                switch (_savedPlayerStats[killer._alias].lastKillerCount)
                {
                    case 6:
                        _arena.sendArenaMessage(string.Format("{0} is on fire!", killer._alias), 17);
                        break;
                    case 8:
                        _arena.sendArenaMessage(string.Format("Someone kill {0}!", killer._alias), 18);
                        break;
                    case 10:
                        _arena.sendArenaMessage(string.Format("{0} is dominating!", killer._alias), 19);
                        break;
                    case 12:
                        _arena.sendArenaMessage(string.Format("DEATH TO {0}!", killer._alias), 30);
                        break;
                }
            }

            //Is this first blood?
            if (lastKiller == null)
            {
                //It is, lets make the sound
                _arena.sendArenaMessage(string.Format("{0} has drawn first blood.", killer._alias), 9);
            }
            lastKiller = killer;
        }

        /// <summary>
        /// Updates the victim's kill streaks
        /// </summary>
        public void UpdateDeath(Player victim, Player killer)
        {
            if (_savedPlayerStats.ContainsKey(victim._alias))
            {
                if (_savedPlayerStats[victim._alias].lastKillerCount >= 6)
                {
                    _arena.sendArenaMessage(string.Format("{0}", killer != null ? killer._alias + " has ended " + victim._alias + "'s kill streak." :
                        victim._alias + "'s kill streak has ended."), 7);
                }
                _savedPlayerStats[victim._alias].lastKillerCount = 0;
            }
        }

        /// <summary>
        /// Updates the last fired weapon and the ticker
        /// </summary>
        public void UpdateWeapon(Player from, ItemInfo.Projectile usedWep)
        {
            if (_savedPlayerStats.ContainsKey(from._alias))
            {
                _savedPlayerStats[from._alias].lastUsedWep = usedWep;
                //500 = Alive time for the schrapnel after main weap explosion
                _savedPlayerStats[from._alias].lastUsedWepTick = DateTime.Now.AddTicks(500).Ticks;
            }
        }

        /// <summary>
        /// Updates the last weapon kill counter
        /// </summary>
        public void UpdateWeaponKill(Player from)
        {
            if (_savedPlayerStats.ContainsKey(from._alias))
            {
                _savedPlayerStats[from._alias].lastUsedWepKillCount++;
                ItemInfo.Projectile lastUsedWep = _savedPlayerStats[from._alias].lastUsedWep;
                if (lastUsedWep == null)
                    return;

                if (lastUsedWep.name.Contains("Combat Knife"))
                    _arena.sendArenaMessage(string.Format("{0} is throwing out the knives.", from._alias), 6);

                switch (_savedPlayerStats[from._alias].lastUsedWepKillCount)
                {
                    case 2:
                        _arena.sendArenaMessage(string.Format("{0} just got a double {1} kill.", from._alias, lastUsedWep.name), 13);
                        break;
                    case 3:
                        _arena.sendArenaMessage(string.Format("{0} just got a triple {1} kill.", from._alias, lastUsedWep.name), 14);
                        break;
                    case 4:
                        _arena.sendArenaMessage(string.Format("A 4 {0} kill by {0}?!?", lastUsedWep.name, from._alias), 15);
                        break;
                    case 5:
                        _arena.sendArenaMessage(string.Format("Unbelievable! {0} with the 5 {1} kill?", from._alias, lastUsedWep.name), 16);
                        break;
                }
            }
        }
    }
}
#endregion