using Common; using System; using System.Collections.Generic; using System.Text; using TBF.Rig.Generic; using TBF.Rig.Input.DataStorage.UniDataStorageReader.Readers; using TBF.Rig.Input.DataStorage.UniDataStorageReader.Searching.Database; using static TBF.Rig.Input.DataStorage.UniDataStorageReader.ReaderCfg; namespace TBF.Rig.Input.DataStorage.UniDataStorageReader { /// /// UI configuration control for UniDataStorageReader. /// Provides testing capabilities for data source and query execution. /// public partial class ReaderCfgCtrl : Configs.ConfigCtrlUtils, IComponentCfgCtrl { private readonly List batchQueryParamValues = new List(); public bool ShowMore { get { return false; } } private ReaderCfg config; public IComponentCfg Config { get { return config as IComponentCfg; } set { config = value as ReaderCfg; Redraw(); } } public ReaderCfgCtrl() { InitializeComponent(); connectToDataSourceButton.Click += testByDataSourceButton_Click; getDataByQueryParamAndTemplateButton.Click += getDataByQueryParamAndTemplateButton_Click; buttonAddParam.Click += buttonAddParam_Click; buttonRemoveParam.Click += buttonRemoveParam_Click; } private void ReaderCfgCtrl_Load(object sender, EventArgs e) { if (config == null) return; Redraw(); } public void Closing() { } /// /// Refreshes UI with current configuration values. /// private void Redraw() { if (config == null) return; classNameLabel.Text = config.Factory.ClassName; nameTextBox.Text = config.Name; dataSourceTextBox.Text = config.DataSource; queryTemplateTextBox.Text = config.QueryTemplate; var values = config.ParamValues(0); dataStorageTypeComboBox.Items.Clear(); if (values != null) { foreach (var item in values) { dataStorageTypeComboBox.Items.Add(item); } } dataStorageTypeComboBox.Text = config.DataStorageType; RefreshQueryParamsListBox(); } /// /// Enables editing controls. /// public void Unlock() { nameTextBox.Enabled = true; dataStorageTypeComboBox.Enabled = true; dataSourceTextBox.Enabled = true; queryTemplateTextBox.Enabled = true; textBox1.Enabled = true; textBox1.ReadOnly = true; textBox2.Enabled = true; textBox2.ReadOnly = true; queryParamValueTextBox.Enabled = true; listBoxQueryParams.Enabled = true; buttonAddParam.Enabled = true; buttonRemoveParam.Enabled = true; } public CfgUpdateFlags VerifyCfg(ref string message) { return CfgUpdateFlags.None; } /// /// Applies changes from UI into configuration. /// public CfgUpdateFlags UpdateCfg() { CfgUpdateFlags flags = CfgUpdateFlags.None; if (config == null) return CfgUpdateFlags.Error; if (config.Name != nameTextBox.Text) { config.Name = nameTextBox.Text; flags |= (CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd); } flags |= UpdateDifferent(ref config.DataStorageType, dataStorageTypeComboBox.Text, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd); flags |= UpdateDifferent(ref config.DataSource, dataSourceTextBox.Text, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd); flags |= UpdateDifferent(ref config.QueryTemplate, queryTemplateTextBox.Text, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd); return flags; } /// /// Builds temporary configuration from UI. /// Used by test actions so saved configuration is not required. /// private ReaderCfg BuildTemporaryConfigFromUi() { ReaderCfg tmpCfg = new ReaderCfg( string.IsNullOrWhiteSpace(nameTextBox.Text) ? "UniDataStorageReader" : nameTextBox.Text, config != null ? config.Factory : new Factory()); tmpCfg.DataStorageType = (dataStorageTypeComboBox.Text ?? string.Empty).Trim(); tmpCfg.DataSource = dataSourceTextBox.Text; tmpCfg.QueryTemplate = queryTemplateTextBox.Text; return tmpCfg; } /// /// Creates appropriate reader implementation based on selected storage type. /// private IDataStorageReader CreateReader(ReaderCfg cfg) { switch ((cfg.DataStorageType ?? string.Empty).Trim()) { case StorageTypes.RestApi: return new RestApiReader(cfg); case StorageTypes.RemoteDatabase: case StorageTypes.LocalDatabase: return new DatabaseReader(cfg); case StorageTypes.RemoteJson: case StorageTypes.LocalJson: return new JsonReader(cfg); case StorageTypes.RemoteCsv: case StorageTypes.LocalCsv: return new CsvReader(cfg); default: throw new NotSupportedException( string.Format("Unsupported DataStorageType: '{0}'", cfg.DataStorageType)); } } /// /// Calls reader diagnostic for source validation and displays the result. /// private void testByDataSourceButton_Click(object sender, EventArgs e) { textBox1.Clear(); try { ReaderCfg tmpCfg = BuildTemporaryConfigFromUi(); IDataStorageReader reader = CreateReader(tmpCfg); ReaderDiagnosticResult result = reader.TestSource(true); textBox1.Text = BuildDiagnosticHeader(tmpCfg, "Source test") + result.ToDisplayDiag(); } catch (Exception ex) { textBox1.Text = BuildExceptionText("Data source test failed", ex); } } /// /// Executes query using values from the batch list only. /// private void getDataByQueryParamAndTemplateButton_Click(object sender, EventArgs e) { textBox2.Clear(); try { if (batchQueryParamValues.Count == 0) throw new InvalidOperationException("At least one batch test value must be provided."); ReaderCfg tmpCfg = BuildTemporaryConfigFromUi(); IDataStorageReader reader = CreateReader(tmpCfg); StringBuilder sb = new StringBuilder(); sb.Append(BuildDiagnosticHeader(tmpCfg, "Query test")); foreach (var value in batchQueryParamValues) { Interfaces.PublicModels.DataQuery query = new Interfaces.PublicModels.DataQuery(); query.QueryParams.Add(value); object queryResult = reader.GetData(query); sb.AppendLine("--- Param: " + value + " ---"); if (queryResult is DatabaseSearchResult dbResult) { sb.AppendLine("Found: " + dbResult.Found); sb.AppendLine("Query: " + dbResult.Query); if (dbResult.Values != null && dbResult.Values.Count > 0) { sb.AppendLine("Returned values:"); foreach (var kvp in dbResult.Values) sb.AppendLine(kvp.Key + " = " + (kvp.Value ?? "")); } } else if (queryResult is ReaderDiagnosticResult diagResult) { sb.AppendLine(diagResult.ToDisplayDiag()); } else { sb.AppendLine(queryResult != null ? queryResult.ToString() : ""); } sb.AppendLine(); } textBox2.Text = sb.ToString(); } catch (Exception ex) { textBox2.Text = BuildExceptionText("GetData test failed", ex); } } /// /// Adds a single batch test value into the list. /// private void buttonAddParam_Click(object sender, EventArgs e) { string value = queryParamValueTextBox.Text?.Trim(); if (string.IsNullOrWhiteSpace(value)) return; batchQueryParamValues.Add(value); queryParamValueTextBox.Clear(); RefreshQueryParamsListBox(); } /// /// Removes the selected batch test value from the list. /// private void buttonRemoveParam_Click(object sender, EventArgs e) { int index = listBoxQueryParams.SelectedIndex; if (index < 0 || index >= batchQueryParamValues.Count) return; batchQueryParamValues.RemoveAt(index); RefreshQueryParamsListBox(); } /// /// Refreshes ListBox content and shows line numbering. /// private void RefreshQueryParamsListBox() { listBoxQueryParams.Items.Clear(); for (int i = 0; i < batchQueryParamValues.Count; i++) { listBoxQueryParams.Items.Add(string.Format("{0}. {1}", i + 1, batchQueryParamValues[i])); } } /// /// Builds common header for diagnostic output. /// private string BuildDiagnosticHeader(ReaderCfg cfg, string testName) { StringBuilder sb = new StringBuilder(); sb.AppendLine("=== " + testName + " ==="); sb.AppendLine("Storage type: " + StorageTypeToDisplayName(cfg.DataStorageType)); sb.AppendLine("Data source: " + Safe(cfg.DataSource)); sb.AppendLine("Query template: " + Safe(cfg.QueryTemplate)); sb.AppendLine(); return sb.ToString(); } /// /// Builds exception text including inner exceptions. /// private string BuildExceptionText(string title, Exception ex) { StringBuilder sb = new StringBuilder(); sb.AppendLine(title + ":"); sb.AppendLine(ex.Message); Exception inner = ex.InnerException; while (inner != null) { sb.AppendLine(); sb.AppendLine("Inner exception:"); sb.AppendLine(inner.Message); inner = inner.InnerException; } return sb.ToString(); } /// /// Returns safe printable text for diagnostics. /// private string Safe(string text) { return string.IsNullOrWhiteSpace(text) ? "" : text; } /// /// Converts internal storage type identifier to user-friendly name. /// private string StorageTypeToDisplayName(string storageType) { switch ((storageType ?? string.Empty).Trim()) { case StorageTypes.RestApi: return "REST API"; case StorageTypes.RemoteDatabase: return "Remote database"; case StorageTypes.RemoteJson: return "Remote JSON"; case StorageTypes.RemoteCsv: return "Remote CSV"; case StorageTypes.LocalDatabase: return "Local database"; case StorageTypes.LocalJson: return "Local JSON"; case StorageTypes.LocalCsv: return "Local CSV"; default: return Safe(storageType); } } } }