context: #region Copyright & License Information
  /*
   * Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
   * This file is part of OpenRA, which is free software. It is made
   * available to you under the terms of the GNU General Public License
   * as published by the Free Software Foundation. For more information,
   * see COPYING.
   */
  #endregion
  
  using System;
  using System.Collections.Generic;
  using System.Drawing;
  using System.Linq;
  using System.Net;
  using OpenRA.Graphics;
  using OpenRA.Network;
  using OpenRA.Primitives;
  using OpenRA.Traits;
  using OpenRA.Widgets;
  
  namespace OpenRA.Mods.Common.Widgets.Logic
  {
  	public static class LobbyUtils
  	{
  		class SlotDropDownOption
  		{
  			public string Title;
  			public string Order;
  			public Func<bool> Selected;
  
  			public SlotDropDownOption(string title, string order, Func<bool> selected)
  			{
  				Title = title;
  				Order = order;
  				Selected = selected;
  			}
  		}
  
  		public static void ShowSlotDropDown(Ruleset rules, DropDownButtonWidget dropdown, Session.Slot slot,
  			Session.Client client, OrderManager orderManager)
  		{
  			var options = new Dictionary<string, IEnumerable<SlotDropDownOption>>() { { "Slot", new List<SlotDropDownOption>()
  			{
  				new SlotDropDownOption("Open", "slot_open " + slot.PlayerReference, () => (!slot.Closed && client == null)),
  				new SlotDropDownOption("Closed", "slot_close " + slot.PlayerReference, () => slot.Closed)
  			} } };
  
  			var bots = new List<SlotDropDownOption>();
  			if (slot.AllowBots)
  			{
  				foreach (var b in rules.Actors["player"].Traits.WithInterface<IBotInfo>().Select(t => t.Name))
  				{
  					var bot = b;
  					var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
  					bots.Add(new SlotDropDownOption(bot,
  						"slot_bot {0} {1} {2}".F(slot.PlayerReference, botController.Index, bot),
  						() => client != null && client.Bot == bot));
  				}
  			}
  
  			options.Add(bots.Any() ? "Bots" : "Bots Disabled", bots);
  
  			Func<SlotDropDownOption, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
  			{
  				var item = ScrollItemWidget.Setup(itemTemplate,
  					o.Selected,
  					() => orderManager.IssueOrder(Order.Command(o.Order)));
  				item.Get<LabelWidget>("LABEL").GetText = () => o.Title;
  				return item;
  			};
  
  			dropdown.ShowDropDown<SlotDropDownOption>("LABEL_DROPDOWN_TEMPLATE", 167, options, setupItem);
  		}
  
  		public static void ShowTeamDropDown(DropDownButtonWidget dropdown, Session.Client client,
  			OrderManager orderManager, int teamCount)
  		{
  			Func<int, ScrollItemWidget, ScrollItemWidget> setupItem = (ii, itemTemplate) =>
  			{
  				var item = ScrollItemWidget.Setup(itemTemplate,
  					() => client.Team == ii,
  					() => orderManager.IssueOrder(Order.Command("team {0} {1}".F(client.Index, ii))));
  				item.Get<LabelWidget>("LABEL").GetText = () => ii == 0 ? "-" : ii.ToString();
  				return item;
  			};
  
  			var options = Enumerable.Range(0, teamCount + 1);
  			dropdown.ShowDropDown("TEAM_DROPDOWN_TEMPLATE", 150, options, setupItem);
  		}
  
  		public static void ShowSpawnDropDown(DropDownButtonWidget dropdown, Session.Client client,
  			OrderManager orderManager, IEnumerable<int> spawnPoints)
  		{
  			Func<int, ScrollItemWidget, ScrollItemWidget> setupItem = (ii, itemTemplate) =>
  			{
  				var item = ScrollItemWidget.Setup(itemTemplate,
  					() => client.SpawnPoint == ii,
  					() => SetSpawnPoint(orderManager, client, ii));
  				item.Get<LabelWidget>("LABEL").GetText = () => ii == 0 ? "-" : Convert.ToChar('A' - 1 + ii).ToString();
  				return item;
  			};
  
  			dropdown.ShowDropDown("SPAWN_DROPDOWN_TEMPLATE", 150, spawnPoints, setupItem);
  		}
  
  		public static void ShowRaceDropDown(DropDownButtonWidget dropdown, Session.Client client,
  			OrderManager orderManager, Dictionary<string, LobbyCountry> countries)
  		{
  			Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (race, itemTemplate) =>
  			{
  				var item = ScrollItemWidget.Setup(itemTemplate,
  					() => client.Race == race,
  					() => orderManager.IssueOrder(Order.Command("race {0} {1}".F(client.Index, race))));
  				var country = countries[race];
  				item.Get<LabelWidget>("LABEL").GetText = () => country.Name;
  				var flag = item.Get<ImageWidget>("FLAG");
  				flag.GetImageCollection = () => "flags";
  				flag.GetImageName = () => race;
  				item.GetTooltipText = () => country.Description;
  				return item;
  			};
  
  			var options = countries.Where(c => c.Value.Selectable).GroupBy(c => c.Value.Side)
  				.ToDictionary(g => g.Key ?? "", g => g.Select(c => c.Key));
  
  			dropdown.ShowDropDown("RACE_DROPDOWN_TEMPLATE", 150, options, setupItem);
  		}
  
  		public static void ShowColorDropDown(DropDownButtonWidget color, Session.Client client,
  			OrderManager orderManager, World world, ColorPreviewManagerWidget preview)
  		{
  			Action onExit = () =>
  			{
  				if (client.Bot == null)
  				{
  					Game.Settings.Player.Color = preview.Color;
  					Game.Settings.Save();
  				}
  
  				color.RemovePanel();
  				orderManager.IssueOrder(Order.Command("color {0} {1}".F(client.Index, preview.Color)));
  			};
  
  			Action<HSLColor> onChange = c => preview.Color = c;
  
  			var colorChooser = Game.LoadWidget(world, "COLOR_CHOOSER", null, new WidgetArgs()
  			{
  				{ "onChange", onChange },
  				{ "initialColor", client.Color }
  			});
  
  			color.AttachPanel(colorChooser, onExit);
  		}
  
  		public static Dictionary<CPos, SpawnOccupant> GetSpawnOccupants(Session lobbyInfo, MapPreview preview)
  		{
  			var spawns = preview.SpawnPoints;
  			return lobbyInfo.Clients
  				.Where(c => (c.SpawnPoint - 1 >= 0) && (c.SpawnPoint - 1 < spawns.Length))
  				.ToDictionary(c => spawns[c.SpawnPoint - 1], c => new SpawnOccupant(c));
  		}
  
  		public static Dictionary<CPos, SpawnOccupant> GetSpawnOccupants(IEnumerable<GameInformation.Player> players, MapPreview preview)
  		{
  			var spawns = preview.SpawnPoints;
  			return players
  					.Where(c => (c.SpawnPoint - 1 >= 0) && (c.SpawnPoint - 1 < spawns.Length))
  					.ToDictionary(c => spawns[c.SpawnPoint - 1], c => new SpawnOccupant(c));
  		}
  
  		public static void SelectSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi)
  		{
  			if (mi.Button != MouseButton.Left)
  				return;
  
  			if (!orderManager.LocalClient.IsObserver && orderManager.LocalClient.State == Session.ClientState.Ready)
  				return;
  
  			var spawnSize = new float2(ChromeProvider.GetImage("lobby-bits", "spawn-unclaimed").Bounds.Size);
  			var selectedSpawn = preview.SpawnPoints
  				.Select((sp, i) => Pair.New(mapPreview.ConvertToPreview(sp), i))
  				.Where(a => ((a.First - mi.Location).ToFloat2() / spawnSize * 2).LengthSquared <= 1)
  				.Select(a => a.Second + 1)
  				.FirstOrDefault();
  
  			var locals = orderManager.LobbyInfo.Clients.Where(c => c.Index == orderManager.LocalClient.Index || (Game.IsHost && c.Bot != null));
  			var playerToMove = locals.FirstOrDefault(c => ((selectedSpawn == 0) ^ (c.SpawnPoint == 0) && !c.IsObserver));
  			SetSpawnPoint(orderManager, playerToMove, selectedSpawn);
  		}
  
  		private static void SetSpawnPoint(OrderManager orderManager, Session.Client playerToMove, int selectedSpawn)
  		{
  			var owned = orderManager.LobbyInfo.Clients.Any(c => c.SpawnPoint == selectedSpawn);
  			if (selectedSpawn == 0 || !owned)
  				orderManager.IssueOrder(Order.Command("spawn {0} {1}".F((playerToMove ?? orderManager.LocalClient).Index, selectedSpawn)));
  		}
  
  		public static Color LatencyColor(Session.ClientPing ping)
  		{
  			if (ping == null)
  				return Color.Gray;
  
  			// Levels set relative to the default order lag of 3 net ticks (360ms)
  			// TODO: Adjust this once dynamic lag is implemented
  			if (ping.Latency < 0)
  				return Color.Gray;
  			if (ping.Latency < 300)
  				return Color.LimeGreen;
  			if (ping.Latency < 600)
  				return Color.Orange;
  			return Color.Red;
  		}
  
  		public static string LatencyDescription(Session.ClientPing ping)
  		{
  			if (ping == null)
  				return "Unknown";
  
  			if (ping.Latency < 0)
  				return "Unknown";
  			if (ping.Latency < 300)
  				return "Good";
  			if (ping.Latency < 600)
  				return "Moderate";
  			return "Poor";
  		}
  
  		public static string DescriptiveIpAddress(string ip)
  		{
  
gt: 			if (ip == null)