using Microsoft.VisualBasic.FileIO; using ModVersionChecker.data.model; using ModVersionChecker.managers.interfaces; using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window; namespace ModVersionChecker.forms { public class AppDetailsForm : Form { private readonly IConfigManager _configManager; private readonly IAppsManager _appsManager; private readonly ISourcesDefManager _sourcesDefManager; private readonly ICheckerTypesDefManager _checkerTypesDefManager; private readonly IFlightSimsManager _flightSimsManager; private readonly GlobalConfig _globalConfig; private int _currentRow; //private string? _appId; private bool _isEditable; //private List _apps; private List _sourcesDef; private List _checkerTypesDef; private TextBox _nameField, _downloadUrlField; private Label _nameLabel, _msfsVersionsLabel, _sourceLabel, _paramsSubtitle, _downloadUrlLabel; private ComboBox _sourceField; private Button _saveButton, _closeButton; private TableLayoutPanel _mainLayout, _paramsPanel, _fsFieldsPanel; private FlowLayoutPanel _buttonsPanel, _fsPanel; private readonly Dictionary _paramFields = new Dictionary(); private readonly Dictionary> _fsFields = new Dictionary>(); private List _selectedFs = new List(); private List _fsCheckBoxes = new List(); private AppConfig? _currentApp; private List _flightSims; public event EventHandler OnAppChanged; public AppDetailsForm( IConfigManager configManager, IAppsManager appsManager, ISourcesDefManager sourcesDefManager, ICheckerTypesDefManager checkerTypesDefManager, IFlightSimsManager flightSimsManager ) { _configManager = configManager ?? throw new ArgumentNullException(nameof(configManager)); _appsManager = appsManager ?? throw new ArgumentNullException(nameof(appsManager)); _sourcesDefManager = sourcesDefManager ?? throw new ArgumentNullException(nameof(sourcesDefManager)); _checkerTypesDefManager = checkerTypesDefManager ?? throw new ArgumentNullException(nameof(checkerTypesDefManager)); _flightSimsManager = flightSimsManager ?? throw new ArgumentNullException(nameof(flightSimsManager)); _flightSims = _flightSimsManager.Load() ?? new List(); _globalConfig = _configManager.Load() ?? new GlobalConfig(); _sourcesDef = _sourcesDefManager.List() ?? new List(); _checkerTypesDef = _checkerTypesDefManager.Load() ?? new List(); _selectedFs = _flightSims.Select(sim => sim.ShortName).ToList(); _mainLayout = new TableLayoutPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 14, ColumnStyles = { new ColumnStyle(SizeType.Absolute, 150), new ColumnStyle(SizeType.Percent, 100) } }; // App Name _nameLabel = new Label { Text = "Name:" }; _nameField = new TextBox { Text = "", Enabled = _isEditable, Width = 300 }; // FS Versions _msfsVersionsLabel = new Label { Text = "FS:" }; _fsPanel = new FlowLayoutPanel { FlowDirection = FlowDirection.LeftToRight, AutoSize = true, Dock = DockStyle.Fill }; //_msfs2020CheckBox = new CheckBox { Text = "MSFS 2020", Enabled = _isEditable }; //_msfs2024CheckBox = new CheckBox { Text = "MSFS 2024", Enabled = _isEditable }; // Source _sourceLabel = new Label { Text = "Source:" }; _sourceField = new ComboBox { Enabled = _isEditable, Width = 300, DropDownStyle = ComboBoxStyle.DropDownList }; _sourceField.Items.AddRange(_sourcesDef.Select(sd => sd.Id).ToArray()); _sourceField.SelectedIndexChanged += OnSourceFieldIndexChanged; // Parameters _paramsSubtitle = new Label { Text = "SourceParameters:", Font = new System.Drawing.Font(Font, System.Drawing.FontStyle.Bold) }; _paramsPanel = new TableLayoutPanel { AutoSize = true, BackColor = Color.White, Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 2, ColumnStyles = { new ColumnStyle(SizeType.Absolute, 150), new ColumnStyle(SizeType.Percent, 100) } }; // Fs Fields Panel _fsFieldsPanel = new TableLayoutPanel { AutoSize = true, BackColor = Color.White, Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 2, ColumnStyles = { new ColumnStyle(SizeType.Absolute, 150), new ColumnStyle(SizeType.Percent, 100) } }; // App Name _downloadUrlLabel = new Label { Text = "Download Url:" }; _downloadUrlField = new TextBox { Text = "", Enabled = _isEditable, Width = 300 }; _buttonsPanel = new FlowLayoutPanel { FlowDirection = FlowDirection.RightToLeft, AutoSize = true, Dock = DockStyle.Fill }; _saveButton = new Button { Text = "Save", Width = 100 }; _closeButton = new Button { Text = "Close", Width = 100 }; _saveButton.Click += OnSaveButtonClicked; _closeButton.Click += (s, e) => Close(); Controls.Add(_mainLayout); Size = new System.Drawing.Size(500, 500); StartPosition = FormStartPosition.CenterParent; InitializeForm(); } public void SetApp(AppConfig? app, bool update = true) { _currentApp = app; _selectedFs = _currentApp?.MsfsVersions ?? new List(); if (update) { UpdateForm(); } } public void SetEditable(bool isEditable, bool update = true) { _isEditable = isEditable; if (update) { UpdateForm(); } } public void UpdateForm() { Text = _currentApp == null ? "Add App" : (_isEditable ? "Edit App" : "App Details"); _nameField.Text = _currentApp != null ? _currentApp.Name : ""; _downloadUrlField.Enabled = _nameField.Enabled = _sourceField.Enabled = _isEditable; _downloadUrlField.Text = _currentApp != null ? _currentApp.DownloadUrl : ""; _flightSims.ForEach(fs => { if (_currentApp != null && _currentApp.MsfsVersions.Contains(fs.ShortName)) { if (!_selectedFs.Contains(fs.ShortName)) { _selectedFs.Add(fs.ShortName); } } }); for (int i = 0; i < _fsCheckBoxes.Count; i++) { var fsKey = _flightSims.FirstOrDefault(f => f.ShortName == _fsCheckBoxes[i].Text)?.ShortName; if (fsKey != null) { _fsCheckBoxes[i].Checked = _currentApp != null && _currentApp.MsfsVersions.Contains(fsKey); } } _sourceField.SelectedIndex = _sourceField.Items.IndexOf(_currentApp != null ? _currentApp.Source : ""); UpdateFsFields(); UpdateParamFields(); } private bool isFsSelected(FsModPathConfig fs) { return _selectedFs.Contains(fs.ShortName); } private void UpdateFsFields() { _fsFields.Clear(); _fsFieldsPanel.Controls.Clear(); foreach (var fs in _flightSims) { if (fs == null || !isFsSelected(fs)) { continue; } var fsKey = fs.ShortName; var fieldsDict = new Dictionary(); _fsFields[fsKey] = fieldsDict; int currentRow = 0; Label horizontalSeparator = new Label { Height = 50, Padding = new Padding(10, 0, 0, 0), BackColor = Color.GhostWhite, // Line-like separator Dock = DockStyle.Fill, TextAlign = ContentAlignment.MiddleLeft, Text = fsKey, // Optional: Add text to the separator ForeColor = Color.FromArgb(50, 50, 50) // Text color contrasts with background }; _fsFieldsPanel.Controls.Add(horizontalSeparator, 0, currentRow); _fsFieldsPanel.SetColumnSpan(horizontalSeparator, 2); currentRow++; foreach (var field in fs.Fields) { Control control; var value = GetFsFieldValue(fsKey, field.Name); var label = new Label { Text = $"{field.Label} ({(field.Required ? "Required" : "Optional")}):", Width = 100, AutoSize = true }; var textBox = new TextBox { Width = 300, Enabled = _isEditable, Text = value }; switch (field.Control.ToLower()) { case "directory": textBox.ReadOnly = true; control = new TableLayoutPanel { AutoSize = true, Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 1, ColumnStyles = { new ColumnStyle(SizeType.Percent, 80), new ColumnStyle(SizeType.Percent, 20) } }; (control as TableLayoutPanel).Controls.Add(textBox, 0, 0); var browseButton = new Button { Text = "Browse", Width = 80, Enabled = _isEditable }; browseButton.Click += (s, e) => { using (var folderDialog = new FolderBrowserDialog()) { folderDialog.Description = $"Select directory for {field.Label}"; folderDialog.SelectedPath = textBox.Text == "" ? Path.Combine(fs.Path) : textBox.Text; if (folderDialog.ShowDialog() == DialogResult.OK) { string selectedDirectory = folderDialog.SelectedPath; string folderName = Path.GetFileName(selectedDirectory); textBox.Text = folderName; } } }; (control as TableLayoutPanel).Controls.Add(browseButton, 1, 0); break; default: control = textBox; break; } fieldsDict[field.Name] = textBox; _fsFieldsPanel.Controls.Add(label, 0, currentRow); _fsFieldsPanel.Controls.Add(control, 1, currentRow); currentRow++; } } } private string GetFsFieldValue(string fsKey, string fieldName) { if (_currentApp == null) return ""; var fsFields = _currentApp.FsFields.ContainsKey(fsKey) ? _currentApp.FsFields[fsKey] : new Dictionary(); if (fsFields.ContainsKey(fieldName)) { return fsFields[fieldName]; } return ""; } private void UpdateParamFields() { if (_sourceField?.SelectedItem == null) return; var selectedSource = _sourcesDef.FirstOrDefault(sd => sd.Id == _sourceField.SelectedItem.ToString()); if (selectedSource == null) return; var checkerType = _checkerTypesDef.FirstOrDefault(ct => ct.Name == selectedSource.Type); if (checkerType == null) return; _paramFields.Clear(); _paramsPanel.Controls.Clear(); int currentRow = 0; foreach (var paramDef in checkerType.Params) { var label = new Label { Text = $"{paramDef.Label} ({(paramDef.Required ? "Required" : "Optional")}):", Width = 100, AutoSize = true }; var textBox = new TextBox { Width = 300, Enabled = _isEditable, Text = GetParamValue(paramDef.Name, selectedSource) }; _paramFields[paramDef.Name] = textBox; _paramsPanel.Controls.Add(label, 0, currentRow); _paramsPanel.Controls.Add(textBox, 1, currentRow); currentRow++; } } private string GetParamValue(string paramName, SourceDef source) { var valueFromSource = source.Defaults != null && source.Defaults.ContainsKey(paramName) ? source.Defaults[paramName] : ""; if (_currentApp == null || _currentApp.Params == null || !_currentApp.Params.ContainsKey(paramName)) return valueFromSource; return _currentApp.Params[paramName]; } private void InitializeForm() { _currentRow = 0; _mainLayout.Controls.Add(_nameLabel, 0, _currentRow); _mainLayout.Controls.Add(_nameField, 1, _currentRow++); _mainLayout.Controls.Add(_msfsVersionsLabel, 0, _currentRow++); _mainLayout.Controls.Add(_fsPanel, 1, _currentRow); _mainLayout.SetColumnSpan(_fsPanel, 2); _currentRow++; _mainLayout.Controls.Add(_fsFieldsPanel, 0, _currentRow); _mainLayout.SetColumnSpan(_fsFieldsPanel, 2); _currentRow++; _mainLayout.Controls.Add(_sourceLabel, 0, _currentRow); _mainLayout.Controls.Add(_sourceField, 1, _currentRow++); _mainLayout.Controls.Add(_paramsSubtitle, 0, _currentRow); _mainLayout.SetColumnSpan(_paramsSubtitle, 2); _currentRow++; _mainLayout.Controls.Add(_paramsPanel, 0, _currentRow); _mainLayout.SetColumnSpan(_paramsPanel, 2); _currentRow++; _mainLayout.Controls.Add(_downloadUrlLabel, 0, _currentRow); _mainLayout.Controls.Add(_downloadUrlField, 1, _currentRow++); _currentRow++; _mainLayout.Controls.Add(_buttonsPanel, 0, _currentRow++); AddFsCheckboxes(); AddButtons(); // UpdateForm(); } private void AddFsCheckboxes() { foreach (var fs in _flightSims) { var checkBox = new CheckBox { Text = fs.ShortName, Checked = _currentApp != null && _currentApp.MsfsVersions.Contains(fs.ShortName), }; checkBox.CheckedChanged += (s, e) => { if (checkBox.Checked) { if (!_selectedFs.Contains(fs.ShortName)) { _selectedFs.Add(fs.ShortName); } } else { _selectedFs.Remove(fs.ShortName); } UpdateFsFields(); }; _fsPanel.Controls.Add(checkBox); _fsCheckBoxes.Add(checkBox); } } private void OnSourceFieldIndexChanged(object? sender, EventArgs e) { if (_isEditable && _sourceField.SelectedItem != null) { UpdateParamFields(); } } private void AddButtons() { _buttonsPanel.Controls.Clear(); _buttonsPanel.Controls.Add(_saveButton); _buttonsPanel.Controls.Add(_closeButton); } private void OnSaveButtonClicked(object? sender, EventArgs e) { try { var paramsDict = _paramFields.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Text.Trim()); var fsFieldsDict = _fsFields.ToDictionary( kvp => kvp.Key, kvp => kvp.Value.ToDictionary(fkvp => fkvp.Key, fkvp => fkvp.Value.Text.Trim()) ); var requiredParams = _checkerTypesDef .First(ct => ct.Name == _sourcesDef.FirstOrDefault(sd => sd.Id == _sourceField.SelectedItem?.ToString())?.Type) .Params.Where(p => p.Required) .Select(p => p.Name); if (requiredParams.Any(rp => string.IsNullOrWhiteSpace(paramsDict[rp]))) { throw new Exception("All required parameters must be filled."); } var msfsVersions = _selectedFs; var isNewApp = (_currentApp == null || string.IsNullOrEmpty(_currentApp.Id)); var app = new AppConfig { Id = isNewApp ? GetUuid() : _currentApp.Id, Name = _nameField.Text.Trim(), MsfsVersions = msfsVersions, Source = _sourceField.SelectedItem?.ToString() ?? "", Params = paramsDict, FsFields = fsFieldsDict, DownloadUrl = _downloadUrlField.Text.Trim(), CurrentVersion = _currentApp?.CurrentVersion ?? "", LatestVersion = _currentApp?.LatestVersion ?? "", Status = _currentApp?.Status ?? AppStatus.None }; if (isNewApp) { _appsManager.Insert(app); } else { _appsManager.Update(app); } _currentApp = app; OnAppChanged?.Invoke(this, "App saved"); Close(); } catch (Exception ex) { MessageBox.Show($"Error: {ex.Message}", "Invalid Input", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private string GetUuid() { Guid uuid = Guid.NewGuid(); return uuid.ToString(); } } }