tbf/TBF/Rig/Input/DataStorage/UniDataStorageReader/UI/ReaderCfgCtrl.cs

378 lines
12 KiB
C#

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
{
/// <summary>
/// UI configuration control for UniDataStorageReader.
/// Provides testing capabilities for data source and query execution.
/// </summary>
public partial class ReaderCfgCtrl : Configs.ConfigCtrlUtils, IComponentCfgCtrl
{
private readonly List<string> batchQueryParamValues = new List<string>();
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()
{
}
/// <summary>
/// Refreshes UI with current configuration values.
/// </summary>
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();
}
/// <summary>
/// Enables editing controls.
/// </summary>
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;
}
/// <summary>
/// Applies changes from UI into configuration.
/// </summary>
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;
}
/// <summary>
/// Builds temporary configuration from UI.
/// Used by test actions so saved configuration is not required.
/// </summary>
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;
}
/// <summary>
/// Creates appropriate reader implementation based on selected storage type.
/// </summary>
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));
}
}
/// <summary>
/// Calls reader diagnostic for source validation and displays the result.
/// </summary>
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);
}
}
/// <summary>
/// Executes query using values from the batch list only.
/// </summary>
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)
{
DataQuery query = new 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 ?? "<null>"));
}
}
else if (queryResult is ReaderDiagnosticResult diagResult)
{
sb.AppendLine(diagResult.ToDisplayDiag());
}
else
{
sb.AppendLine(queryResult != null ? queryResult.ToString() : "<null>");
}
sb.AppendLine();
}
textBox2.Text = sb.ToString();
}
catch (Exception ex)
{
textBox2.Text = BuildExceptionText("GetData test failed", ex);
}
}
/// <summary>
/// Adds a single batch test value into the list.
/// </summary>
private void buttonAddParam_Click(object sender, EventArgs e)
{
string value = queryParamValueTextBox.Text?.Trim();
if (string.IsNullOrWhiteSpace(value))
return;
batchQueryParamValues.Add(value);
queryParamValueTextBox.Clear();
RefreshQueryParamsListBox();
}
/// <summary>
/// Removes the selected batch test value from the list.
/// </summary>
private void buttonRemoveParam_Click(object sender, EventArgs e)
{
int index = listBoxQueryParams.SelectedIndex;
if (index < 0 || index >= batchQueryParamValues.Count)
return;
batchQueryParamValues.RemoveAt(index);
RefreshQueryParamsListBox();
}
/// <summary>
/// Refreshes ListBox content and shows line numbering.
/// </summary>
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]));
}
}
/// <summary>
/// Builds common header for diagnostic output.
/// </summary>
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();
}
/// <summary>
/// Builds exception text including inner exceptions.
/// </summary>
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();
}
/// <summary>
/// Returns safe printable text for diagnostics.
/// </summary>
private string Safe(string text)
{
return string.IsNullOrWhiteSpace(text) ? "<empty>" : text;
}
/// <summary>
/// Converts internal storage type identifier to user-friendly name.
/// </summary>
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);
}
}
}
}