Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ContractParametersModel.cs
1using DocumentFormat.OpenXml.EMMA;
8using System;
9using System.Collections.Generic;
10using System.Text;
11using System.Threading.Tasks;
12using System.Windows;
13using System.Windows.Controls;
14using System.Windows.Media;
15using Waher.Events;
20using Waher.Script;
21
23{
28 {
29 private static readonly Contract emptyContract = new();
30
31 private readonly Property<bool> parametersOk;
32 private readonly Property<ParameterInfo[]> parameters;
33 private readonly Property<string> language;
34 private readonly Property<Iso__639_1.Record[]> languages;
35
36 protected readonly Dictionary<CaseInsensitiveString, ParameterInfo> parametersByName = new();
37 private readonly DesignModel designModel;
38 private StackPanel languageOptions = null;
39 private StackPanel parameterOptions = null;
40 private StackPanel additionalCommands = null;
41
42 private Contract contract;
43 private Parameter[] contractParameters;
44
53 {
54 this.parametersOk = new Property<bool>(nameof(this.ParametersOk), false, this);
55 this.parameters = new Property<ParameterInfo[]>(nameof(this.Parameters), Array.Empty<ParameterInfo>(), this);
56 this.language = new Property<string>(nameof(this.Language), Language, this);
57 this.languages = new Property<Iso__639_1.Record[]>(nameof(this.Languages), Array.Empty<Iso__639_1.Record>(), this);
58 this.contract = Contract ?? emptyContract;
59 this.designModel = DesignModel;
60
61 this.SetParameters(Parameters);
62 }
63
68 public virtual Task SetContract(Contract Contract)
69 {
70 if (this.contract is not null)
71 this.contract.FormatParameterDisplay -= this.Contract_FormatParameterDisplay;
72
73 this.contract = Contract;
74 this.contract.FormatParameterDisplay += this.Contract_FormatParameterDisplay;
75
76 this.SetParameters(Contract.Parameters);
77
78 return Task.CompletedTask;
79 }
80
81 private Task Contract_FormatParameterDisplay(object Sender, ParameterValueFormattingEventArgs e)
82 {
83 if (e.Value is Waher.Content.Duration D)
84 e.Value = DurationToString.ToString(D);
85
86 return Task.CompletedTask;
87 }
88
89 protected void SetParameters(Parameter[] ContractParameters)
90 {
91 this.contractParameters = ContractParameters;
92
93 string PrevLanguage = this.Language;
94 bool Found = false;
95
96 this.Languages = this.contract.GetLanguages().ToIso639_1();
97
98 if (!string.IsNullOrWhiteSpace(PrevLanguage))
99 {
100 foreach (Iso__639_1.Record Rec in this.Languages)
101 {
102 if (Rec.Code == PrevLanguage)
103 {
104 Found = true;
105 break;
106 }
107 }
108 }
109
110 this.Language = Found ? PrevLanguage : this.contract.DefaultLanguage;
111
112 if (string.IsNullOrEmpty(this.Language) && (this.Languages?.Length ?? 0) == 0)
113 {
114 this.Languages = new string[] { "en" }.ToIso639_1();
115 this.Language = "en";
116 }
117
118 List<ParameterInfo> Parameters = new();
119
120 if (ContractParameters is not null)
121 {
122 foreach (Parameter Parameter in ContractParameters)
123 {
124 if (this.parametersByName.TryGetValue(Parameter.Name, out ParameterInfo ParameterInfo))
125 {
128 }
129 }
130 }
131
132 this.Parameters = Parameters.ToArray();
133 }
134
138 public Contract Contract => this.contract;
139
143 public string Language
144 {
145 get => this.language.Value;
146 set => this.SetLanguage(value).Wait();
147 }
148
153 {
154 get => this.languages.Value;
155 set => this.languages.Value = value;
156 }
157
162 protected virtual async Task<bool> SetLanguage(string Language)
163 {
164 try
165 {
166 this.language.Value = Language;
167
168 if (!string.IsNullOrEmpty(Language))
169 {
170 foreach (ParameterInfo PI in this.Parameters)
171 {
173
174 if (Text is null)
175 PI.DescriptionAsMarkdown = string.Empty;
176 else
177 PI.DescriptionAsMarkdown = (await Text.GenerateMarkdown(this.contract, MarkdownType.ForEditing) ?? string.Empty).Trim();
178 }
179
180 if (this.languageOptions is not null)
181 await this.PopulateParameters(this.languageOptions, this.parameterOptions, this.additionalCommands, null);
182 }
183
184 return true;
185 }
186 catch (Exception ex)
187 {
188 Log.Exception(ex);
189 MainWindow.ErrorBox(ex.Message);
190
191 return false;
192 }
193 }
194
198 public bool ParametersOk
199 {
200 get => this.parametersOk.Value;
201 set
202 {
203 this.parametersOk.Value = value;
204 this.ParametersOkChanged();
205 }
206 }
207
208 protected virtual void ParametersOkChanged()
209 {
210 // Do nothing by default.
211 }
212
221 public virtual async Task<Control> PopulateParameters(StackPanel Languages, StackPanel Parameters, StackPanel AdditionalCommands,
222 Dictionary<CaseInsensitiveString, object> PresetValues)
223 {
224 List<ParameterInfo> ParameterList = new();
226 Control First = null;
227
228 this.languageOptions = Languages;
229 if (this.languageOptions is not null)
230 this.languageOptions.DataContext = this;
231
232 this.parameterOptions = Parameters;
233 this.parameterOptions.Children.Clear();
234 this.parameterOptions.DataContext = this;
235 this.parametersByName.Clear();
236
237 foreach (Parameter Parameter in this.contractParameters)
238 {
239 if (Parameter is BooleanParameter BP)
240 {
241 CheckBox CheckBox = new()
242 {
243 Tag = Parameter.Name,
244 IsChecked = BP.Value.HasValue && BP.Value.Value,
245 VerticalContentAlignment = VerticalAlignment.Center,
246 Content = Parameter.GetLabel(),
247 ToolTip = await Parameter.ToSimpleXAML(this.Language, this.contract),
248 Margin = new Thickness(0, 10, 0, 0)
249 };
250
251 if ((PresetValues?.TryGetValue(Parameter.Name, out object PresetValue) ?? false) && PresetValue is bool b)
252 {
253 BP.Value = b;
254 CheckBox.IsChecked = b;
255 }
256
257 CheckBox.Checked += this.Parameter_CheckedChanged;
258 CheckBox.Unchecked += this.Parameter_CheckedChanged;
259
260 this.parametersByName[Parameter.Name] = ParameterInfo = new BooleanParameterInfo(this.contract, BP, CheckBox, null, this.parameters);
261
262 Parameters.Children.Add(CheckBox);
263
264 First ??= CheckBox;
265 }
266 else
267 {
268 System.Windows.Controls.Label Label = new()
269 {
270 Content = Parameter.GetLabel(),
271 Margin = new Thickness(0, 10, 0, 0)
272 };
273
274 TextBox TextBox = new()
275 {
276 Tag = Parameter.Name,
278 ToolTip = await Parameter.ToSimpleXAML(this.Language, this.contract)
279 };
280
281 if (PresetValues?.TryGetValue(Parameter.Name, out object PresetValue) ?? false)
282 TextBox.Text = MoneyToString.ToString(PresetValue) ?? string.Empty;
283 else
284 PresetValue = null;
285
286 TextBox.TextChanged += this.Parameter_TextChanged;
287
289 {
290 if (PresetValue is decimal d)
291 NP.Value = d;
292
293 this.parametersByName[Parameter.Name] = ParameterInfo = new NumericalParameterInfo(this.contract, NP, TextBox,
294 null, null, null, null, this.designModel, this.parameters);
295 }
296 else if (Parameter is StringParameter SP)
297 {
298 if (PresetValue is string s)
299 SP.Value = s;
300
301 this.parametersByName[Parameter.Name] = ParameterInfo = new StringParameterInfo(this.contract, SP, TextBox,
302 null, null, null, null, null, null, null, this.designModel, this.parameters);
303 }
304 else if (Parameter is DateParameter DP)
305 {
306 if (PresetValue is DateTime TP)
307 DP.Value = TP;
308
309 this.parametersByName[Parameter.Name] = ParameterInfo = new DateParameterInfo(this.contract, DP, TextBox,
310 null, null, null, null, this.designModel, this.parameters);
311 }
312 else if (Parameter is DateTimeParameter DTP)
313 {
314 if (PresetValue is DateTime TP)
315 DTP.Value = TP;
316
317 this.parametersByName[Parameter.Name] = ParameterInfo = new DateTimeParameterInfo(this.contract, DTP, TextBox,
318 null, null, null, null, this.designModel, this.parameters);
319 }
320 else if (Parameter is TimeParameter TP)
321 {
322 if (PresetValue is TimeSpan TS)
323 TP.Value = TS;
324
325 this.parametersByName[Parameter.Name] = ParameterInfo = new TimeParameterInfo(this.contract, TP, TextBox,
326 null, null, null, null, this.designModel, this.parameters);
327 }
328 else if (Parameter is DurationParameter DrP)
329 {
330 if (PresetValue is Waher.Content.Duration D)
331 DrP.Value = D;
332
333 this.parametersByName[Parameter.Name] = ParameterInfo = new DurationParameterInfo(this.contract, DrP, TextBox,
334 null, null, null, null, this.designModel, this.parameters);
335 }
336 else if (Parameter is CalcParameter CP)
337 {
338 TextBox.IsReadOnly = true;
339
340 this.parametersByName[Parameter.Name] = ParameterInfo = new CalcParameterInfo(this.contract, CP, TextBox,
341 this.designModel, this.parameters);
342 }
344 {
345 if (PresetValue is string s)
346 CRP.Value = s;
347
348 this.parametersByName[Parameter.Name] = ParameterInfo = new ContractReferenceParameterInfo(this.contract, CRP, TextBox,
349 this.designModel, this.parameters);
350 }
351 else
352 continue;
353
354 Parameters.Children.Add(Label);
355 Parameters.Children.Add(TextBox);
356
357 First ??= TextBox;
358 }
359
360 ParameterList.Add(ParameterInfo);
361 }
362
363 this.Parameters = ParameterList.ToArray();
364
365 await this.ValidateParameters();
366
367 this.additionalCommands = AdditionalCommands;
368 if (this.additionalCommands is not null)
369 {
370 this.additionalCommands.DataContext = this;
371 this.additionalCommands.Visibility = Visibility.Visible;
372 this.additionalCommands.InvalidateVisual();
373 }
374
375 return First;
376 }
377
378 private async void Parameter_CheckedChanged(object sender, RoutedEventArgs e)
379 {
380 try
381 {
382 if (sender is not CheckBox CheckBox || !this.parametersByName.TryGetValue(CheckBox.Tag.ToString(), out ParameterInfo ParameterInfo))
383 return;
384
385 ParameterInfo.Value = CheckBox.IsChecked;
386
387 await this.ValidateParameters();
388 }
389 catch (Exception ex)
390 {
391 Log.Exception(ex);
392 }
393
394 await this.RaiseParametersChanged();
395 }
396
397 protected async Task RaiseParametersChanged()
398 {
399 try
400 {
401 await this.ParametersChanged();
402 }
403 catch (Exception ex)
404 {
405 Log.Exception(ex);
406 }
407 }
408
409 protected virtual Task ParametersChanged()
410 {
411 return Task.CompletedTask; // Do nothing by default.
412 }
413
414 private async void Parameter_TextChanged(object sender, RoutedEventArgs e)
415 {
416 try
417 {
418 if (sender is not TextBox TextBox || !this.parametersByName.TryGetValue(TextBox.Tag.ToString(), out ParameterInfo ParameterInfo))
419 return;
420
421 try
422 {
423 if (ParameterInfo.Parameter is NumericalParameter && decimal.TryParse(TextBox.Text, out decimal d))
424 ParameterInfo.Value = d;
425 else if (ParameterInfo.Parameter is BooleanParameter && bool.TryParse(TextBox.Text, out bool b))
426 ParameterInfo.Value = b;
427 else if (ParameterInfo.Parameter is DateParameter && DateTime.TryParse(TextBox.Text, out DateTime TP))
428 {
429 if (TP.TimeOfDay != TimeSpan.Zero)
430 throw new Exception("Date only.");
431
432 ParameterInfo.Value = TP;
433 }
434 else if (ParameterInfo.Parameter is DateTimeParameter && DateTime.TryParse(TextBox.Text, out TP))
435 ParameterInfo.Value = TP;
436 else if (ParameterInfo.Parameter is TimeParameter && TimeSpan.TryParse(TextBox.Text, out TimeSpan TS))
437 ParameterInfo.Value = TS;
439 ParameterInfo.Value = Dr;
440 else if (ParameterInfo.Parameter is not CalcParameter)
441 ParameterInfo.Value = TextBox.Text;
442
443 TextBox.Background = ParameterInfo.Protection.DefaultBrush();
444
445 Log.Informational("Parameter " + ParameterInfo.Parameter.Name + " set to " + TextBox.Text.ToString());
446
447 await this.ValidateParameters();
448 }
449 catch (Exception ex)
450 {
451 TextBox.Background = Brushes.Salmon;
452 this.ParametersOk = false;
453
454 Log.Error("Unable to set parameter " + ParameterInfo.Parameter.Name + " to " + TextBox.Text.ToString() + ": " + ex.Message);
455 }
456
457 await this.RaiseParametersChanged();
458 }
459 catch (Exception ex)
460 {
461 Log.Exception(ex);
462 }
463 }
464
469 public virtual async Task<Variables> ValidateParameters()
470 {
471 Variables Variables = new();
472 bool Ok = true;
473
474 Variables["Duration"] = this.contract.Duration;
475
476 foreach (ParameterInfo P in this.parametersByName.Values)
478
479 foreach (ParameterInfo P in this.parametersByName.Values)
480 {
481 if (await P.ValidateParameter(Variables))
482 {
483 P.Control.Background = P.Protection.DefaultBrush();
484 Log.Informational("Parameter " + P.Name + " is OK.");
485 }
486 else
487 {
488 StringBuilder Msg = new();
489
490 Msg.Append("Parameter ");
491 Msg.Append(P.Name);
492 Msg.Append(" contains errors.");
493
494 if (P.ErrorReason.HasValue)
495 {
496 Msg.Append(" Reason: ");
497 Msg.Append(P.ErrorReason.Value.ToString());
498 }
499
500 if (!string.IsNullOrEmpty(P.ErrorText))
501 {
502 Msg.Append(", Text: ");
503 Msg.Append(P.ErrorText);
504 }
505
506 P.Control.Background = Brushes.Salmon;
507 Log.Error(Msg.ToString());
508 Ok = false;
509 }
510 }
511
512 this.ParametersOk = Ok;
513
514 return Ok ? Variables : null;
515 }
516
521 {
522 get => this.parameters.Value;
523 set => this.parameters.Value = value;
524 }
525 }
526}
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1647
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
Definition: Log.cs:682
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
Definition: Log.cs:334
Calculation contractual parameter
Contains the definition of a contract
Definition: Contract.cs:22
string[] GetLanguages()
Gets available languages encoded in contract.
Definition: Contract.cs:1901
Parameter[] Parameters
Defined parameters for the smart contract.
Definition: Contract.cs:267
string DefaultLanguage
Default language for contract.
Definition: Contract.cs:1884
Duration? Duration
Duration of the contract. Is counted from the time it is signed by the required parties.
Definition: Contract.cs:193
object Value
Value of parameter. Can be set by event handler, to format the value before it is being displayed.
Task< string > GenerateMarkdown(Contract Contract)
Generates markdown for the human-readable text.
HumanReadableText[] Descriptions
Discriptions of the object, in different languages.
Abstract base class for contractual parameters
Definition: Parameter.cs:17
abstract void Populate(Variables Variables)
Populates a variable collection with the value of the parameter.
abstract object ObjectValue
Parameter value.
Definition: Parameter.cs:104
String-valued contractual parameter
Collection of variables.
Definition: Variables.cs:25
Definition: App.xaml.cs:4
Represents a duration value, as defined by the xsd:duration data type: http://www....
Definition: Duration.cs:13
static bool TryParse(string s, out Duration Result)
Tries to parse a duration value.
Definition: Duration.cs:85