public static void StartDownloadedMission(ScriptMissionData profile, string modInternalName)
		{
			var spring = new Spring(Program.SpringPaths);
			var name = Program.Conf.LobbyPlayerName;
			if (string.IsNullOrEmpty(name)) name = "Player";

			if (Utils.VerifySpringInstalled())
			{
				spring.StartGame(Program.TasClient,
								null,
								null,
								profile.StartScript.Replace("%MOD%", modInternalName).Replace("%MAP%", profile.MapName).Replace("%NAME%", name), Program.Conf.UseSafeMode, Program.Conf.UseMtEngine);
                var serv = GlobalConst.GetContentService();
				serv.NotifyMissionRun(Program.Conf.LobbyPlayerName, profile.Name);
			}
		}
        /// <summary>
        /// singleton, dont use, internal for designer
        /// </summary>
        internal BattleBar()
        {
            InitializeComponent();

            picoChat.ChatBackgroundColor = TextColor.background; //same color as Program.Conf.BgColor
            picoChat.IRCForeColor = 14; //mirc grey. Unknown use

            picoChat.DefaultTooltip = "Last lines from room chat, click to enter full screen chat";

            client = Program.TasClient;
            spring = new Spring(Program.SpringPaths);


            try
            {
                // silly way to create speech and voice engines on runtime - needed due to mono crash
                speech = Activator.CreateInstance(Type.GetType("ZeroKLobby.ChatToSpeech"), spring);
            }
            catch (Exception ex)
            {
                Trace.TraceWarning("Failed to init VoiceCommands:{0}", ex.Message);
            }

            spring.SpringExited += (s, e) =>
                {
                    client.ChangeMyUserStatus(isInGame: false);

                    if (e.Data)
                    {
                        Program.MainWindow.InvokeFunc(() =>
                            {
                                var defaultButton = MessageBoxDefaultButton.Button2;
                                var icon = MessageBoxIcon.None;
                                if (
                                    MessageBox.Show("Do you want me to set Low details?\n(will effect: lups.cfg and springsettings.cfg)\n\nIf you wish to file a bug report, please include a copy of infolog.txt in your game data folder (accessible through Settings).\nUpload it to a text sharing site such as pastebin.com.",
                                                    "Spring engine has crashed, update your video and audio drivers please!",
                                                    MessageBoxButtons.YesNo,
                                                    icon,
                                                    defaultButton) == DialogResult.Yes)
                                {
                                    Program.Conf.UseSafeMode = true;
                                    Program.EngineConfigurator.Configure(true, 0);
                                }
                            });
                    }
                };

            spring.SpringStarted += (s, e) => { client.ChangeMyUserStatus(isInGame: true); };

            client.Rang += (s, e) =>
                {
                    if (e.User == GlobalConst.NightwatchName)
                        //Nightwatch RING is from UserController.cs (website code)
                        MainWindow.Instance.NotifyUser("chat/zkadmin", "New report arrive at zkadmin channel", true, true);
                    else
                    {
                        MainWindow.Instance.NotifyUser("chat/battle", "Someone demands your attention in battle room!", true, true);
                        AutoRespond();
                    }
                };

            client.BattleJoined += (s, e) =>
                {
                    if (!isVisible) ManualBattleStarted();
                    if (IsHostGameRunning()) barContainer.btnDetail.Text = "Rejoin";
                    else barContainer.btnDetail.Text = "Start";
                    //client.ChangeMyUserStatus(false, false);
                    var battle = client.MyBattle;
                    lastBattleFounder = battle.Founder.Name;

                    if (battle.Founder.Name.StartsWith("PlanetWars") || battle.Founder.Name.StartsWith("Zk")) ChangeDesiredSpectatorState(false); // TODO pw unpsec hack, remove later

                    if (battle.IsQueue)
                    {
                        barContainer.Title = string.Format("Joined {0} Quick Match Queue", battle.QueueName);
                        barContainer.TitleTooltip = "Please await people, game will start automatically";
                        lbQueue.Visible = true;
                        radioPlay.Visible = false;
                        radioSpec.Visible = false;
                        barContainer.btnDetail.Visible = false;
                    }
                    else
                    {
                        barContainer.Title = string.Format("Joined battle room hosted by {0}", battle.Founder.Name);
                        barContainer.TitleTooltip = "Use button on the left side to start a game";
                        lbQueue.Visible = false;
                        radioPlay.Visible = true;
                        radioSpec.Visible = true;
                        barContainer.btnDetail.Visible = true;
                    }

                    Program.Downloader.GetResource(DownloadType.MAP, battle.MapName);
                    Program.Downloader.GetResource(DownloadType.MOD, battle.ModName);
                    engineVersionNeeded = battle.EngineVersion;
                    if (engineVersionNeeded != Program.SpringPaths.SpringVersion) Program.Downloader.GetAndSwitchEngine(engineVersionNeeded);
                    else engineVersionNeeded = null;

                    if (gameBox.Image != null) gameBox.Image.Dispose();
                    DpiMeasurement.DpiXYMeasurement(this);
                    int scaledIconHeight = DpiMeasurement.ScaleValueY(BattleIcon.Height);
                    int scaledIconWidth = DpiMeasurement.ScaleValueX(BattleIcon.Width);
                    gameBox.Image = new Bitmap(scaledIconWidth, scaledIconHeight);
                    using (var g = Graphics.FromImage(gameBox.Image))
                    {
                        g.FillRectangle(Brushes.White, 0, 0, scaledIconWidth, scaledIconHeight);
                        var bi = Program.BattleIconManager.GetBattleIcon(battle.BattleID);
                        g.DrawImageUnscaled(bi.Image, 0, 0);
                    }
                    gameBox.Invalidate();

                    RefreshTooltip();


                    var alliance =
                        Enumerable.Range(0, TasClient.MaxAlliances - 1)
                                  .FirstOrDefault(allyTeam => !battle.Users.Values.Any(user => user.AllyNumber == allyTeam));
                    var team = battle.GetFreeTeamID(client.UserName);

                    client.ChangeMyBattleStatus(desiredSpectatorState, HasAllResources() ? SyncStatuses.Synced : SyncStatuses.Unsynced, alliance, team);
                };


            client.MyBattleMapChanged += (s, e) =>
                {
                    if (client.MyBattle != null && !Program.SpringScanner.HasResource(client.MyBattle.MapName))
                    {
                        client.ChangeMyBattleStatus(syncStatus: SyncStatuses.Unsynced);
                        Program.Downloader.GetResource(DownloadType.MAP, client.MyBattle.MapName);
                    }
                    RefreshTooltip();
                };

            client.MyBattleHostExited += (s, e) => { barContainer.btnDetail.Text = "Start"; };

            client.MyBattleStarted += (s, e) =>
                {
                    try
                    {
                        barContainer.btnDetail.Text = "Rejoin";
                        if (client.MyBattleStatus.SyncStatus == SyncStatuses.Synced)
                        {
                            if (Utils.VerifySpringInstalled())
                            {
                                if (spring.IsRunning) spring.ExitGame();
                                lastScript = spring.StartGame(client, null, null, null, Program.Conf.UseSafeMode, client.MyBattleStatus.IsSpectator ? Program.Conf.UseMtEngine : false); //use MT tag when in spectator slot
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Error starting spring: " + ex.Message);
                    }
                    RefreshTooltip();
                };

            client.BattleMyUserStatusChanged += (s, e) =>
                {
                    if (client.MyBattleStatus != null)
                    {
                        barContainer.btnDetail.Enabled = client.MyBattleStatus.SyncStatus == SyncStatuses.Synced;

                        if (client.MyBattleStatus.IsSpectator && radioPlay.Checked) ChangeGuiSpectatorWithoutEvent(false); // i was spectated
                        if (!client.MyBattleStatus.IsSpectator && radioSpec.Checked) ChangeGuiSpectatorWithoutEvent(true); //i was unspectated
                    }
                };

            client.BattleClosed += (s, e) =>
                {
                    barContainer.btnDetail.Text = "Start";
                    if (gameBox.Image != null) gameBox.Image.Dispose();
                    gameBox.Image = null;
                    RefreshTooltip();
                    Stop();
                };

            client.MyBattleRemoved += (s, e) =>
                {
                    var t = new Timer();
                    var tryCount = 0;
                    t.Interval = 1000;
                    t.Tick += (s2, e2) =>
                        {
                            tryCount++;
                            if (tryCount > 15)
                            {
                                t.Stop();
                                t.Dispose();
                            }
                            else if (client.IsLoggedIn && client.MyBattle == null)
                            {
                                var bat = client.ExistingBattles.Values.FirstOrDefault(x => x.Founder.Name == lastBattleFounder && !x.IsPassworded);
                                if (bat != null)
                                {
                                    ActionHandler.JoinBattle(bat.BattleID, null);
                                    t.Stop();
                                    t.Dispose();
                                }
                            }
                        };
                    t.Start();
                };

            client.ConnectionLost += (s, e) =>
                {
                    if (gameBox.Image != null) gameBox.Image.Dispose();
                    gameBox.Image = null;
                    RefreshTooltip();
                    Stop();
                };


            // process special queue message to display in label
            client.Said += (s, e) =>
            {
                if (e.Place == SayPlace.Battle && client.MyBattle != null && client.MyBattle.Founder.Name == e.UserName && e.Text.StartsWith("Queue"))
                {
                    var t = e.Text.Substring(6);
                    queueLabelFormatter = Regex.Replace(t,
                        "([0-9]+)s",
                        m =>
                        {
                            var queueSeconds = int.Parse(m.Groups[1].Value);
                            queueTarget = DateTime.Now.AddSeconds(queueSeconds);
                            return "{0}s";
                        });
                    lbQueue.Text = string.Format(queueLabelFormatter, Math.Round(queueTarget.Subtract(DateTime.Now).TotalSeconds));
                }
            };


            timer.Tick += (s, e) =>
                {
                    if (client.IsLoggedIn)
                    {
                        if (WindowsApi.IdleTime.TotalMinutes > Program.Conf.IdleTime) {
                            if (!client.MyUser.IsAway) client.ChangeMyUserStatus(isAway: true);
                        } else {
                            if (client.MyUser.IsAway) client.ChangeMyUserStatus(isAway: false);
                        }
                        CheckMyBattle();
                    }
                    if (client.MyBattle != null && client.MyBattle.IsQueue)
                    {
                        lbQueue.Text = string.Format(queueLabelFormatter, Math.Round(queueTarget.Subtract(DateTime.Now).TotalSeconds));
                    }
                };
            timer.Interval = 1000;
            timer.Start();

            Program.BattleIconManager.BattleChanged += BattleIconManager_BattleChanged;

            //picoChat.Font = new Font(Program.Conf.ChatFont.FontFamily, Program.Conf.ChatFont.Size*0.8f);
            picoChat.ShowHistory = false;
            picoChat.ShowJoinLeave = false;
            //picoChat.HideScroll = true;

            BattleChatControl.BattleLine += (s, e) => picoChat.AddLine(e.Data);

            picoChat.MouseClick += (s, e) => NavigationControl.Instance.Path = "chat/battle";
        }
        private void MissionBar_Load(object sender, EventArgs e)
        {
            label1.Text = string.Format("Starting mission {0} - please wait", missionName);

            var down = Program.Downloader.GetResource(DownloadType.MOD, missionName);
            if (down==null)
            {   //okay Mission exist, but lets check for dependency!
                down = Program.Downloader.GetDependenciesOnly(missionName);
            }

            var engine = Program.Downloader.GetAndSwitchEngine(Program.SpringPaths.SpringVersion);

            ZkData.Utils.StartAsync(() =>
            {
                var metaWait = new EventWaitHandle(false, EventResetMode.ManualReset);
                Mod modInfo = null;
                Program.SpringScanner.MetaData.GetModAsync(missionName,
                                                           mod =>
                                                           {
                                                               if (!mod.IsMission)
                                                               {
                                                                   Program.MainWindow.InvokeFunc(() =>
                                                                   {
                                                                       label1.Text = string.Format("{0} is not a valid mission", missionName);
                                                                       container.btnStop.Enabled = true;
                                                                   });
                                                               }

                                                               else modInfo = mod;

                                                               metaWait.Set();
                                                           },
                                                           error =>
                                                           {
                                                               Program.MainWindow.InvokeFunc(() =>
                                                               {
                                                                   label1.Text = string.Format("Download of metadata failed: {0}", error.Message);
                                                                   container.btnStop.Enabled = true;
                                                               });
                                                               metaWait.Set();
                                                           });
                //if (down != null) WaitHandle.WaitAll(new WaitHandle[] { down.WaitHandle, metaWait });
                //else metaWait.WaitOne();
                
                var waitHandles = new List<EventWaitHandle>();
                
                waitHandles.Add(metaWait);
                if (down != null)  waitHandles.Add(down.WaitHandle);
                if (engine != null) waitHandles.Add(engine.WaitHandle);
                
                if (waitHandles.Any()) WaitHandle.WaitAll(waitHandles.ToArray());

                if ((down != null && down.IsComplete == false) || (engine != null && engine.IsComplete == false) || modInfo==null)
                {
                    Program.MainWindow.InvokeFunc(() =>
                    {
                        label1.Text = string.Format("Download of {0} failed", missionName);

                        container.btnStop.Enabled = true;
                    });
                }

                if (modInfo != null && (down == null || down.IsComplete == true) && (engine == null || engine.IsComplete == true))
                {
                    if (Utils.VerifySpringInstalled())
                    {
                        var spring = new Spring(Program.SpringPaths);
                        spring.StartGame(Program.TasClient,
                                         null,
                                         null,
                                         modInfo.MissionScript, Program.Conf.UseSafeMode);

                        var cs = GlobalConst.GetContentService();
                        cs.NotifyMissionRun(Program.Conf.LobbyPlayerName, missionName);
                    }
                    Program.MainWindow.InvokeFunc(() => Program.NotifySection.RemoveBar(this));
                }
            });
        }
        public static void JoinBattleSpec(int battleId)
        {
            Battle bat;
            if (!Program.TasClient.ExistingBattles.TryGetValue(battleId, out bat)) return;
            Program.TasClient.Say(SayPlace.User, bat.Founder.Name, string.Format("!adduser {0}", Program.TasClient.UserName),false);

            var de = Program.Downloader.GetAndSwitchEngine(bat.EngineVersion);
            var dm = Program.Downloader.GetResource(DownloadType.MAP, bat.MapName);
            var dg = Program.Downloader.GetResource(DownloadType.MOD, bat.ModName);
        
            ZkData.Utils.StartAsync(() =>
            {
                if (de != null)
                {
                    de.WaitHandle.WaitOne();
                    if (de.IsComplete == false) return;
                }
                if (dm != null)
                {
                    dm.WaitHandle.WaitOne();
                    if (dm.IsComplete == false) return;
                }
                if (dg != null)
                {
                    dg.WaitHandle.WaitOne();
                    if (dg.IsComplete == false) return;
                }


                var spring = new Spring(Program.SpringPaths);
                
                Thread.Sleep(200);// give host time to adduser
                spring.StartGame(Program.TasClient, null, null, null, Program.Conf.UseSafeMode, battleOverride: bat);
            });
           


        }