public static PlayerJoinResult AutohostPlayerJoined(BattleContext context, int accountID) {
            var res = new PlayerJoinResult();
            var db = new ZkDataContext();
            AutohostMode mode = context.GetMode();

            if (mode == AutohostMode.Planetwars) {
                Planet planet = db.Galaxies.Single(x => x.IsDefault).Planets.SingleOrDefault(x => x.Resource.InternalName == context.Map);
                if (planet == null) {
                    res.PublicMessage = "Invalid map";
                    return res;
                }
                Account account = db.Accounts.Find(accountID); // accountID is in fact lobbyID

                if (account != null) {
                    var config = context.GetConfig();
                    if (account.Level < config.MinLevel)
                    {
                        res.PrivateMessage = string.Format("Sorry, PlanetWars is competive online campaign for experienced players. You need to be at least level {0} to play here. To increase your level, play more games on other hosts or open multiplayer game and play against computer AI bots.  You can still spectate this game, however.", config.MinLevel);
                        res.ForceSpec = true;
                        return res;
                    }


                    string owner = "";
                    if (planet.Account != null) owner = planet.Account.Name;
                    string facRoles = string.Join(",",
                                                  account.AccountRolesByAccountID.Where(x => !x.RoleType.IsClanOnly).Select(x => x.RoleType.Name).ToList());
                    if (!string.IsNullOrEmpty(facRoles)) facRoles += " of " + account.Faction.Name + ", ";

                    string clanRoles = string.Join(",",
                                                   account.AccountRolesByAccountID.Where(x => x.RoleType.IsClanOnly).Select(x => x.RoleType.Name).ToList());
                    if (!string.IsNullOrEmpty(clanRoles)) clanRoles += " of " + account.Clan.ClanName;

                    res.PublicMessage = string.Format("Greetings {0} {1}{2}, welcome to {3} planet {4} {6}/PlanetWars/Planet/{5}",
                                                      account.Name,
                                                      facRoles,
                                                      clanRoles,
                                                      owner,
                                                      planet.Name,
                                                      planet.PlanetID,
                                                      GlobalConst.BaseSiteUrl);

                    return res;
                }
            }
            Account acc = db.Accounts.Find(accountID); // accountID is in fact lobbyID

            if (acc != null)
            {
                AutohostConfig config = context.GetConfig();
                if (acc.Level < config.MinLevel)
                {
                    res.PrivateMessage = string.Format("Sorry, you need to be at least level {0} to play here. To increase your level, play more games on other hosts or open multiplayer game and play against computer AI bots. You can still spectate this game, however.",
                                                           config.MinLevel);
                    res.ForceSpec = true;
                    return res;
                }
                else if (acc.Level > config.MaxLevel)
                {
                    res.PrivateMessage = string.Format("Sorry, your level must be {0} or lower to play here. Pick on someone your own size! You can still spectate this game, however.",
                                                           config.MaxLevel);
                    res.ForceSpec = true;
                    return res;
                }

                // FIXME: use 1v1 Elo for 1v1
                if (acc.EffectiveElo < config.MinElo)
                {
                    res.PrivateMessage = string.Format("Sorry, you need to have an Elo rating of at least {0} to play here. Win games against human opponents to raise your Elo. You can still spectate this game, however.",
                                                           config.MinElo);
                    res.ForceSpec = true;
                    return res;
                }
                else if (acc.EffectiveElo > config.MaxElo)
                {
                    res.PrivateMessage = string.Format("Sorry, your Elo rating must be {0} or lower to play here. Pick on someone your own size! You can still spectate this game, however.",
                                                           config.MaxElo);
                    res.ForceSpec = true;
                    return res;
                }
            }

            return null;
        }
		public static RecommendedMapResult GetRecommendedMap(BattleContext context, bool pickNew) {
			var mode = context.GetMode();
		    var config = context.GetConfig();
			var res = new RecommendedMapResult();
			using (var db = new ZkDataContext()) {
				if (mode == AutohostMode.Planetwars)
				{

				    var info = Global.PlanetWarsMatchMaker.GetBattleInfo(context.AutohostName);
				    if (info != null)
				    {
				        res.MapName = info.Map;
                        res.Message = String.Format("Welcome to planet {0} {2}/PlanetWars/Planet/{1} attacked", info.Name, info.PlanetID, GlobalConst.BaseSiteUrl);
				    } else res.MapName = context.Map;
				}
				else { 
					if (!pickNew) {
						// autohost is not managed or has valid featured map - check disabled
    					res.MapName = context.Map;
						return res;
					}
					List<Resource> list = null;
					var players = context.Players.Count(x => !x.IsSpectator);
                    if (config != null && config.SplitBiggerThan != null && players > config.SplitBiggerThan) players = players/2; // expect the split
					switch (mode) {
                        case AutohostMode.Generic:
                        case AutohostMode.Teams:
                        case AutohostMode.None:
							var ret = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsTeams != false && x.MapIsSpecial != true);
							if (players > 11) ret = ret.Where(x => (x.MapHeight*x.MapHeight + x.MapWidth*x.MapWidth) > 16*16);
							else if (players > 8) ret = ret.Where(x => (x.MapHeight*x.MapHeight + x.MapWidth*x.MapWidth) > 16*16 && (x.MapHeight*x.MapHeight + x.MapWidth*x.MapWidth) <= 24*24);
                            else if (players > 5) ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 24 * 24 || x.MapIs1v1 == true);
							else ret = ret.Where(x => (x.MapHeight*x.MapHeight + x.MapWidth*x.MapWidth) <= 16*16 || x.MapIs1v1 == true);
							list = ret.ToList();

							break;
						case AutohostMode.Game1v1:
							list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIs1v1 == true && x.MapIsSpecial != true).ToList();
							break;
						case AutohostMode.GameChickens:
							ret = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsSpecial != true && (x.MapIsChickens == true || x.MapWaterLevel == 1));
                            if (players > 5) ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) > 16 * 16);
                            else if (players > 4) ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) > 16 * 16 && (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 24 * 24);
                            else if (players > 2) ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 24 * 24 || x.MapIs1v1 == true);
                            else ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 16 * 16 || x.MapIs1v1 == true);
							list = ret.ToList();

							break;
						case AutohostMode.GameFFA:
							list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsFfa == true && x.MapFFAMaxTeams == players).ToList();
							if (!list.Any()) list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsFfa == true && (players%x.MapFFAMaxTeams == 0)).ToList();
							if (!list.Any()) list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsFfa == true).ToList();

							break;
					}
					if (list != null) {
						var r = new Random();
                        if (list.Count > 0)  res.MapName = list[r.Next(list.Count)].InternalName;
					}
				}
			}
			return res;
		}
        public static BalanceTeamsResult BalanceTeams(BattleContext context, bool isGameStart, int? allyCount, bool? clanWise) {
            var config = context.GetConfig();
            var playerCount = context.Players.Count(x => !x.IsSpectator);

            // game is managed, is bigger than split limit and wants to start -> split into two and issue starts
            if (isGameStart && context.GetMode() != AutohostMode.None && config.SplitBiggerThan != null && config.SplitBiggerThan < playerCount) {
                new Thread(() =>
                    {
                        try {
                            SplitAutohost(context, true);
                        } catch (Exception ex) {
                            Trace.TraceError("Error when splitting game:{0}", ex);
                        }
                    }).Start();
                return new BalanceTeamsResult
                       {
                           CanStart = false,
                           Message =
                               string.Format("Game too big - splitting into two - max players is {0} here",
                                             config.SplitBiggerThan)
                       };
            }

            
            if (clanWise == null && (config.AutohostMode == AutohostMode.Generic || config.AutohostMode == AutohostMode.Teams)) clanWise = true;

            var res = PerformBalance(context, isGameStart, allyCount, clanWise, config, playerCount);

            if (context.GetMode() != AutohostMode.Planetwars) // planetwars skip other checks
            {

                if (isGameStart)
                {
                    if (playerCount < (config.MinToStart ?? 0))
                    {
                        res.Message = string.Format("This host needs at least {0} people to start", config.MinToStart);
                        res.CanStart = false;
                        return res;
                    }
                    if (playerCount > (config.MaxToStart ?? 99))
                    {
                        res.Message = string.Format("This host can only start with at most {0} players", config.MaxToStart);
                        res.CanStart = false;
                        return res;
                    }

                    // dont allow to start alone
                    if (playerCount <= 1)
                    {
                        if (res.DeleteBots)
                            return new BalanceTeamsResult
                            {
                                CanStart = false,
                                Message = "You cannot play alone on this host, wait for players or join another game room and play with bots."
                            };
                        if (!context.Bots.Any())
                            return new BalanceTeamsResult
                            {
                                CanStart = false,
                                Message = "Cannot play alone, you can add bots using button on bottom left."
                            };
                    }
                }
            }
            if (isGameStart) VerifySpecCheaters(context, res);

            return res;
        }