using System; using System.Drawing; using System.Collections.Generic; using System.Data; using System.Linq; using System.Windows.Forms; using System.Windows.Forms.DataVisualization.Charting; using Shadowsocks.Controller; using Shadowsocks.Model; using Shadowsocks.Properties; namespace Shadowsocks.View { public partial class StatisticsStrategyConfigurationForm : Form { private readonly ShadowsocksController _controller; private StatisticsStrategyConfiguration _configuration; private readonly DataTable _dataTable = new DataTable(); private List _servers; private readonly Series _speedSeries; private readonly Series _packageLossSeries; private readonly Series _pingSeries; public StatisticsStrategyConfigurationForm(ShadowsocksController controller) { if (controller == null) return; InitializeComponent(); Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); _speedSeries = StatisticsChart.Series["Speed"]; _packageLossSeries = StatisticsChart.Series["Package Loss"]; _pingSeries = StatisticsChart.Series["Ping"]; _controller = controller; _controller.ConfigChanged += (sender, args) => LoadConfiguration(); UpdateTexts(); LoadConfiguration(); Load += (sender, args) => InitData(); } private void UpdateTexts() { Control[] controls = new Control[] { StatisticsEnabledCheckBox,PingCheckBox,label6, byHourOfDayCheckBox,label9,label8,label2,label3, label1,chartModeSelector,dayMode,allMode, OKButton,CancelButton }; foreach (var item in controls) { item.Text = I18N.GetString(item.Text); } foreach (var item in StatisticsChart.Series) { item.Name = I18N.GetString(item.Name); } } private void LoadConfiguration() { var configs = _controller.GetCurrentConfiguration().configs; _servers = configs.Select(server => server.Identifier()).ToList(); _configuration = _controller.StatisticsConfiguration ?? new StatisticsStrategyConfiguration(); if (_configuration.Calculations == null) { _configuration = new StatisticsStrategyConfiguration(); } } private void InitData() { bindingConfiguration.Add(_configuration); foreach (var kv in _configuration.Calculations) { var calculation = new CalculationControl(kv.Key, kv.Value); calculationContainer.Controls.Add(calculation); } serverSelector.DataSource = _servers; _dataTable.Columns.Add("Timestamp", typeof(DateTime)); _dataTable.Columns.Add("Speed", typeof(int)); _speedSeries.XValueMember = "Timestamp"; _speedSeries.YValueMembers = "Speed"; // might be empty _dataTable.Columns.Add("Package Loss", typeof(int)); _dataTable.Columns.Add("Ping", typeof(int)); _packageLossSeries.XValueMember = "Timestamp"; _packageLossSeries.YValueMembers = "Package Loss"; _pingSeries.XValueMember = "Timestamp"; _pingSeries.YValueMembers = "Ping"; StatisticsChart.DataSource = _dataTable; LoadChartData(); StatisticsChart.DataBind(); } private void CancelButton_Click(object sender, EventArgs e) { Close(); } private void OKButton_Click(object sender, EventArgs e) { foreach (CalculationControl calculation in calculationContainer.Controls) { _configuration.Calculations[calculation.Value] = calculation.Factor; } _controller?.SaveStrategyConfigurations(_configuration); _controller?.UpdateStatisticsConfiguration(StatisticsEnabledCheckBox.Checked); Close(); } private void LoadChartData() { var serverName = _servers[serverSelector.SelectedIndex]; _dataTable.Rows.Clear(); //return directly when no data is usable if (_controller.availabilityStatistics?.FilteredStatistics == null) return; List statistics; if (!_controller.availabilityStatistics.FilteredStatistics.TryGetValue(serverName, out statistics)) return; IEnumerable> dataGroups; if (allMode.Checked) { _pingSeries.XValueType = ChartValueType.DateTime; _packageLossSeries.XValueType = ChartValueType.DateTime; _speedSeries.XValueType = ChartValueType.DateTime; dataGroups = statistics.GroupBy(data => data.Timestamp.DayOfYear); StatisticsChart.ChartAreas["DataArea"].AxisX.LabelStyle.Format = "g"; StatisticsChart.ChartAreas["DataArea"].AxisX2.LabelStyle.Format = "g"; } else { _pingSeries.XValueType = ChartValueType.Time; _packageLossSeries.XValueType = ChartValueType.Time; _speedSeries.XValueType = ChartValueType.Time; dataGroups = statistics.GroupBy(data => data.Timestamp.Hour); StatisticsChart.ChartAreas["DataArea"].AxisX.LabelStyle.Format = "HH:00"; StatisticsChart.ChartAreas["DataArea"].AxisX2.LabelStyle.Format = "HH:00"; } var finalData = from dataGroup in dataGroups orderby dataGroup.Key select new { dataGroup.First().Timestamp, Speed = dataGroup.Max(data => data.MaxInboundSpeed) ?? 0, Ping = (int)(dataGroup.Average(data => data.AverageResponse) ?? 0), PackageLossPercentage = (int)(dataGroup.Average(data => data.PackageLoss) ?? 0) * 100 }; foreach (var data in finalData.Where(data => data.Speed != 0 || data.PackageLossPercentage != 0 || data.Ping != 0)) { _dataTable.Rows.Add(data.Timestamp, data.Speed, data.PackageLossPercentage, data.Ping); } StatisticsChart.DataBind(); } private void serverSelector_SelectionChangeCommitted(object sender, EventArgs e) { LoadChartData(); } private void dayMode_CheckedChanged(object sender, EventArgs e) { LoadChartData(); } private void allMode_CheckedChanged(object sender, EventArgs e) { LoadChartData(); } private void PingCheckBox_CheckedChanged(object sender, EventArgs e) { repeatTimesNum.ReadOnly = !PingCheckBox.Checked; } } }