public void CalculateBattleElo(BattleEvent e)
        {
            var teams =
                e.EndGameInfos.Where(p => !p.Spectator).GroupBy(p => p.OnVictoryTeam).OrderBy(g => g.Key).ToList();

            var loserCount = teams[0].Count();
            var winnerCount = teams[1].Count();

            var loserElo = teams[0].Average(p => GetPlayer(p.Name).Elo);
            var winnerElo = teams[1].Average(p => GetPlayer(p.Name).Elo);

            var eWin = 1 / (1 + Math.Pow(10, (loserElo - winnerElo) / 400));
            var eLose = 1 / (1 + Math.Pow(10, (winnerElo - loserElo) / 400));

            var scoreWin = 32 * (1 - eWin) / winnerCount;
            var scoreLose = 32 * (0 - eLose) / loserCount;

            foreach (var p in teams[0])
            {
                GetPlayer(p.Name).Elo += scoreLose;
            }

            foreach (var p in teams[1])
            {
                GetPlayer(p.Name).Elo += scoreWin;
            }

            bool is1v1 = e.AreUpgradesDisabled && loserCount == 1 && winnerCount == 1;
            if (is1v1) {
                var pLose = GetPlayer(teams[0].First().Name);
                var pWin = GetPlayer(teams[1].First().Name);
                loserElo = pLose.Elo1v1;
                winnerElo = pWin.Elo1v1;

                eWin = 1 / (1 + Math.Pow(10, (loserElo - winnerElo) / 400));
                eLose = 1 / (1 + Math.Pow(10, (winnerElo - loserElo) / 400));

                scoreWin = 32 * (1 - eWin) / winnerCount;
                scoreLose = 32 * (0 - eLose) / loserCount;

                pLose.Elo1v1 += scoreLose;
                pWin.Elo1v1 += scoreWin;
            }
        }
		public SendBattleResultOutput SendBattleResult(AuthInfo springieLogin,
		                                               string mapName,
		                                               ICollection<EndGamePlayerInfo> usersInGame)
		{
			var ret = new SendBattleResultOutput();
			ret.RankNotifications = new List<RankNotification>();
			if (springieLogin == null) {
				throw new ArgumentNullException("springieLogin");
			}
			if (usersInGame == null) {
				throw new ArgumentNullException("usersInGame");
			}
			if (!ValidateSpringieLogin(springieLogin)) {
				return ret; // silently ignore other than valid springie
			}

			var invalids = usersInGame.Where(x => !x.Spectator && Galaxy.GetPlayer(x.Name) == null).ToList();
			foreach (var u in invalids) {
				ret.MessageToDisplay += "Invalid players " + u.Name + " ignored";
				usersInGame.Remove(u);
			}

			if (!usersInGame.Any(p => p.OnVictoryTeam)) {
				ret.MessageToDisplay += "No losing players";
				return ret;
			}
			if (!usersInGame.Any(p => !p.OnVictoryTeam)) {
				ret.MessageToDisplay += "Only losing players";
				return ret;
			}

			if (!usersInGame.All(u => u.Spectator || Galaxy.GetPlayer(u.Name) != null)) {
				throw new Exception("Player is not registered.");
			}
			if (
				!usersInGame.All(
				 	u =>
				 	u.Spectator ||
				 	String.Equals(Galaxy.GetPlayer(u.Name).FactionName, u.Side, StringComparison.InvariantCultureIgnoreCase))) {
				throw new Exception("Faction mismatch.");
			}

			var isWithoutUpgrades = disabledUpgradesHosts.Contains(springieLogin.Login);

			Faction victoriousFaction = null;

			foreach (var user in usersInGame) {
				if (user.Spectator) {
					continue;
				}
				var player = Galaxy.Players.Single(p => p.Name == user.Name);
				if (user.OnVictoryTeam) {
					player.Victories++;
					player.MeasuredVictories++;
					player.MetalEarned += Settings.Default.MetalForVictory;
					if (victoriousFaction == null) {
						victoriousFaction = Galaxy.Factions.Single(f => f.Name == player.FactionName);
					}
				} else {
					player.Defeats++;
					player.MeasuredDefeats++;
					player.MetalEarned += Settings.Default.MetalForDefeat;
				}
			}

			if (victoriousFaction == null) {
				ret.MessageToDisplay += "No winners";
				return ret;
			}
			var planet = Galaxy.Planets.Single(p => p.MapName == mapName);
			var isConquest = planet.FactionName != victoriousFaction.Name;
			planet.FactionName = victoriousFaction.Name;

			if (!isWithoutUpgrades) {
				KillFleetsAndUpgrades(victoriousFaction, planet);
			}

			LastChanged = DateTime.Now;

			var sb = new StringBuilder();
			var encircledPlanetIDs = new List<int>();
			if (isConquest) {
				var encircledPlanets =
					Galaxy.Planets.Where(p => p.FactionName != victoriousFaction.Name && Galaxy.IsPlanetEncircled(p));
				foreach (var p in encircledPlanets) {
					p.FactionName = victoriousFaction.Name;
					sb.AppendFormat(",{0} ", p.Name);
					encircledPlanetIDs.Add(p.ID);
				}
				if (sb.Length != 0) {
					sb.Append("have fallen due to lack of supply.");
				}
			}

			if (!SpringieStates.ContainsKey(springieLogin.Login)) {
				throw new Exception("No springie state found!");
			}
			var attackingFaction = SpringieStates[springieLogin.Login].GameStartedStatus.OffensiveFactionName;
			var defendingFaction = Galaxy.Factions.Single(f => f.Name != attackingFaction).Name;
			Galaxy.Turn++;
			Galaxy.OffensiveFactionInternal = victoriousFaction.Name;

			List<PlayerRankChangedEvent> changedRanks;
			Galaxy.CalculatePlayerRanks(out changedRanks);
			Galaxy.SwapUnusedPlanets();
			CalculateEndTurnMetal();

			foreach (var e in changedRanks) {
				if (e.NewRank > e.OldRank) {
					new RankNotification(e.PlayerName, string.Format("Congratulations, you have been promoted to {0}!", e.NewRank));
				} else {
					new RankNotification(e.PlayerName, string.Format("You have just lost a rank! Conquer planets to regain it!"));
				}
			}

			var spaceFleetOwners = from f in Galaxy.Fleets
			                       where f.IsAtDestination(Galaxy.Turn)
			                       select f.OwnerName;

			var battleEvent = new BattleEvent(
				DateTime.Now,
				usersInGame.Where(u => !u.Spectator).ToList(),
				mapName,
				attackingFaction,
				defendingFaction,
				victoriousFaction.Name,
				disabledUpgradesHosts.Contains(springieLogin.Login),
				State.Galaxy,
				encircledPlanetIDs,
				spaceFleetOwners);
			State.Galaxy.Events.Add(battleEvent);
			Galaxy.CalculateBattleElo(battleEvent);

			var enemyPlanetCount = Galaxy.Planets.Count(p => p.FactionName != victoriousFaction.Name);
			if (enemyPlanetCount == 0) {
				State.Galaxy = Galaxy.AdvanceRound(Settings.Default.GalaxyTemplatePath);
				ForceSaveState();
				ret.MessageToDisplay += string.Format(
					"{0} HAS FINALLY CONQUERED THE GALAXY! (New round is starting)", victoriousFaction.Name);
				return ret;
			}

			ForceSaveState();
			ret.MessageToDisplay += string.Format(
				"Congratulations, planet {0} {2} by {1} {3}",
				planet.Name,
				victoriousFaction.Name,
				isConquest ? "conquered" : "held",
				sb);
			return ret;
		}