/**
         * once failed, try after 5 min
         * and (last write - last read) < 5s
         * and (now - last read) <  5s  // means not stuck
         * and latency < 200ms, try after 30s
         */
        public void ChooseNewServer()
        {
            SsServerInfo oldServer = _currentServer;
            List<ServerStatus> servers = new List<ServerStatus>(_serverStatus.Values);
            DateTime now = DateTime.Now;
            foreach (var status in servers)
            {
                // all of failure, latency, (lastread - lastwrite) normalized to 1000, then
                // 100 * failure - 2 * latency - 0.5 * (lastread - lastwrite)
                status.score =
                    100 * 1000 * Math.Min(5 * 60, (now - status.lastFailure).TotalSeconds)
                    - 2 * 5 * (Math.Min(2000, status.latency.TotalMilliseconds) / (1 + (now - status.lastTimeDetectLatency).TotalSeconds / 30 / 10) +
                    -0.5 * 200 * Math.Min(5, (status.lastRead - status.lastWrite).TotalSeconds));
                Logging.Debug(String.Format("server: {0} latency:{1} score: {2}", status.server.DisplayName(), status.latency, status.score));
            }
            ServerStatus max = null;
            foreach (var status in servers)
            {
                if (max == null)
                {
                    max = status;
                }
                else
                {
                    if (status.score >= max.score)
                    {
                        max = status;
                    }
                }
            }
            if (max != null)
            {
                _currentServer = max.server;
                if (_currentServer != oldServer)
                {
                    Console.WriteLine("HA switching to server: {0}", _currentServer.DisplayName());
                }

                Logging.Debug(String.Format("choosing server: {0}", _currentServer.DisplayName()));
            }
        }
        private void RemoveExpiredSsServerInfoFromConfig(SsServerInfo serverInfo)
        {
            try
            {
                var currentConfiguration = _controller.GetCurrentConfiguration();
                currentConfiguration.ServerInfos.Remove(serverInfo);
                _controller.SaveServers(currentConfiguration.ServerInfos, currentConfiguration.localPort);

                var aaa = string.Format("Expired ss-server ({0}) has been removed, {1} left", serverInfo.DisplayName(), currentConfiguration.ServerInfos.Count);
                Shadowsocks.View.MenuViewController.ShowBalloonTip("Info", aaa, System.Windows.Forms.ToolTipIcon.Warning, 1000);
            }
            catch (Exception ex)
            {
                Logging.LogUsefulException(ex);
            }
        }