Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
TokensModel.cs
3using LegalLab.Tabs;
4using NeuroFeatures;
7using System;
8using System.Collections.Generic;
9using System.Threading.Tasks;
10using System.Windows.Controls;
11using System.Windows.Input;
13using Waher.Events;
17
19{
23 [Singleton]
24 public class TokensModel : PersistedModel, IDisposable
25 {
26 private readonly List<TokenModel> tokens = new();
27 private readonly List<TokenTotal> totals = new();
28
29 private readonly NeuroFeaturesClient neuroFeaturesClient;
30
31 private TokenModel selectedItem = null;
32 private TokenEventDetail[] events = null;
33 private Control[] tokenMenuItems = null;
34
35 private readonly Command addTextNote;
36 private readonly Command addXmlNote;
37
44 public TokensModel(XmppClient Client, ContractsClient Contracts, string ComponentJid)
45 : base()
46 {
47 this.neuroFeaturesClient = new NeuroFeaturesClient(Client, Contracts, ComponentJid);
48
49 this.neuroFeaturesClient.TokenAdded += this.NeuroFeaturesClient_TokenAdded;
50 this.neuroFeaturesClient.TokenRemoved += this.NeuroFeaturesClient_TokenRemoved;
51
52 this.neuroFeaturesClient.StateUpdated += this.NeuroFeaturesClient_StateUpdated;
53 this.neuroFeaturesClient.VariablesUpdated += this.NeuroFeaturesClient_VariablesUpdated;
54
55 this.addTextNote = new Command(this.CanExecuteAddNote, this.ExecuteAddTextNote);
56 this.addXmlNote = new Command(this.CanExecuteAddNote, this.ExecuteAddXmlNote);
57 }
58
59 private Task NeuroFeaturesClient_TokenAdded(object Sender, TokenEventArgs e)
60 {
61 MainWindow.UpdateGui(async () =>
62 {
63 TokenModel Token = await TokenModel.CreateAsync(this.neuroFeaturesClient, e.Token, "en", MainWindow.DesignModel);
64 Token.Selected += this.Token_Selected;
65 Token.Deselected += this.Token_Deselected;
66 Token.NoteAdded += this.Token_NoteAdded;
67
68 lock (this.tokens)
69 {
70 this.tokens.Insert(0, Token);
71 }
72
73 this.RaisePropertyChanged(nameof(this.Tokens));
74
75 Task _ = this.LoadTotals();
76 });
77
78 return Task.CompletedTask;
79 }
80
81 private void Token_NoteAdded(object sender, EventArgs e)
82 {
83 this.LoadEvents();
84 }
85
86 private void Token_Deselected(object sender, EventArgs e)
87 {
88 if (this.selectedItem == sender)
89 {
90 this.selectedItem = null;
91 this.RaisePropertyChanged(nameof(this.SelectedItem));
92
93 this.events = null;
94 this.RaisePropertyChanged(nameof(this.Events));
95
96 this.tokenMenuItems = null;
97 this.RaisePropertyChanged(nameof(this.TokenMenuItems));
98 }
99 }
100
101 private async void Token_Selected(object sender, EventArgs e)
102 {
103 try
104 {
105 this.selectedItem = sender as TokenModel;
106 this.RaisePropertyChanged(nameof(this.SelectedItem));
107
108 bool PrepareMenuItems = true;
109
110 if (this.selectedItem is not null)
111 {
112 string TokenId = this.selectedItem.TokenId;
113
114 if (this.selectedItem.CurrentState is null || this.selectedItem.CurrentVariables is null)
115 {
116 await this.neuroFeaturesClient.GetCurrentState(TokenId, async (sender2, e2) =>
117 {
118 if (e2.Ok && this.selectedItem is not null && this.selectedItem.TokenId == TokenId)
119 {
120 PrepareMenuItems = false;
121
122 this.selectedItem.StateUpdated(e2.CurrentState);
123 this.selectedItem.VariablesUpdated(e2.Variables);
124 await this.selectedItem.UpdateNoteCommands();
125
126 MainWindow.UpdateGui(async () =>
127 {
128 await this.PrepareTokenMenuItems();
129 });
130 }
131 }, null);
132 }
133 }
134
135 this.LoadEvents();
136
137 if (PrepareMenuItems)
138 await this.PrepareTokenMenuItems();
139 }
140 catch (Exception ex)
141 {
142 Log.Exception(ex);
143 }
144 }
145
146 private void LoadEvents()
147 {
148 this.events = Array.Empty<TokenEventDetail>();
149 this.RaisePropertyChanged(nameof(this.Events));
150
151 this.neuroFeaturesClient.GetEvents(this.selectedItem.TokenId, 0, 100, (sender, e) =>
152 {
153 if (e.Ok && e.Events.Length > 0 && e.Events[0].TokenId == (string)e.State)
154 {
155 int i, c = e.Events.Length;
156 TokenEventDetail[] Events = new TokenEventDetail[c];
157
158 for (i = 0; i < c; i++)
159 Events[i] = TokenEventDetail.Create(e.Events[i]);
160
161 this.events = Events;
162
163 MainWindow.UpdateGui(() =>
164 {
165 this.RaisePropertyChanged(nameof(this.Events));
166 return Task.CompletedTask;
167 });
168 }
169
170 return Task.CompletedTask;
171 }, this.selectedItem.TokenId);
172 }
173
174 private async Task PrepareTokenMenuItems()
175 {
176 List<Control> Items = new();
177 TokenModel Model = this.selectedItem;
178
179 if (Model is not null)
180 {
181 Items.Add(new MenuItem()
182 {
183 Header = "Add Text Note...",
184 Command = this.addTextNote
185 });
186
187 Items.Add(new MenuItem()
188 {
189 Header = "Add XML Note...",
190 Command = this.addXmlNote
191 });
192
193 Items.Add(new Separator());
194
195 Items.Add(new MenuItem()
196 {
197 Header = "Present State...",
198 Command = Model.ViewPresentReport
199 });
200
201 Items.Add(new MenuItem()
202 {
203 Header = "History...",
204 Command = Model.ViewHistoryReport
205 });
206
207 Items.Add(new MenuItem()
208 {
209 Header = "State Diagram...",
210 Command = Model.ViewStateDiagramReport
211 });
212
213 Items.Add(new MenuItem()
214 {
215 Header = "Profiling...",
216 Command = Model.ViewProfilingReport
217 });
218
219 KeyValuePair<NoteCommand, int>[] Commands = await Model.GetContextSpecificNoteCommands(true);
220
221 if (Commands.Length > 0)
222 {
223 Items.Add(new Separator());
224
225 foreach (KeyValuePair<NoteCommand, int> P in Commands)
226 {
227 NoteCommand Command = P.Key;
228 int i = P.Value;
229
230 Items.Add(new MenuItem()
231 {
232 Header = Command.Title?.Find("en"),
233 ToolTip = Command.ToolTip?.Find("en"),
234 Command = Model.NoteCommand,
235 CommandParameter = i
236 });
237 }
238 }
239 }
240
241 this.tokenMenuItems = Items.ToArray();
242 this.RaisePropertyChanged(nameof(this.TokenMenuItems));
243 }
244
245 private Task NeuroFeaturesClient_TokenRemoved(object Sender, TokenEventArgs e)
246 {
248 {
249 lock (this.tokens)
250 {
251 int i, c = this.tokens.Count;
252
253 for (i = 0; i < c; i++)
254 {
255 if (this.tokens[i].TokenId == e.Token.TokenId)
256 {
257 this.tokens.RemoveAt(i);
258 break;
259 }
260 }
261 }
262
263 this.RaisePropertyChanged(nameof(this.Tokens));
264
265 Task _ = this.LoadTotals();
266
267 return Task.CompletedTask;
268 });
269
270 return Task.CompletedTask;
271 }
272
274 public void Dispose()
275 {
276 this.neuroFeaturesClient.Dispose();
277 }
278
282 public NeuroFeaturesClient NeuroFeaturesClient => this.neuroFeaturesClient;
283
287 public IEnumerable<TokenModel> Tokens
288 {
289 get
290 {
291 lock (this.tokens)
292 {
293 return this.tokens.ToArray();
294 }
295 }
296 }
297
301 public TokenModel SelectedItem
302 {
303 get => this.selectedItem;
304 set => this.selectedItem = value;
305 }
306
310 public TokenEventDetail[] Events => this.events;
311
315 public Control[] TokenMenuItems => this.tokenMenuItems;
316
317 public IEnumerable<TokenTotal> Totals
318 {
319 get
320 {
321 lock (this.totals)
322 {
323 return this.totals.ToArray();
324 }
325 }
326 }
327
328 private async Task LoadTotals()
329 {
330 try
331 {
332 TokenTotalsEventArgs e = await this.neuroFeaturesClient.GetTotalsAsync();
333 if (e.Ok)
334 {
335 lock (this.totals)
336 {
337 this.totals.Clear();
338 this.totals.AddRange(e.Totals);
339 }
340
341 this.RaisePropertyChanged(nameof(this.Totals));
342 }
343 }
344 catch (Exception ex)
345 {
346 Log.Exception(ex);
347 }
348 }
349
353 public ICommand AddTextNote => this.addTextNote;
354
358 public ICommand AddXmlNote => this.addXmlNote;
359
360 private bool CanExecuteAddNote()
361 {
362 return this.selectedItem is not null;
363 }
364
365 private async Task ExecuteAddTextNote()
366 {
367 string s = MainWindow.PromptUser("Add Text Note", "Enter text note to add to token:");
368
369 if (!string.IsNullOrEmpty(s))
370 {
371 if (this.selectedItem is null)
372 MainWindow.ErrorBox("No token selected.");
373 else
374 {
375 try
376 {
377 await this.neuroFeaturesClient.AddTextNoteAsync(this.selectedItem.TokenId, s);
378 this.LoadEvents();
379 }
380 catch (Exception ex)
381 {
382 MainWindow.ErrorBox(ex.Message);
383 }
384 }
385 }
386 }
387
388 private async Task ExecuteAddXmlNote()
389 {
390 string s = string.Empty;
391
392 do
393 {
394 s = MainWindow.PromptUser("Add XML Note", "Enter XML note to add to token:", s);
395 if (string.IsNullOrEmpty(s))
396 return;
397 }
398 while (!XML.IsValidXml(s));
399
400 if (this.selectedItem is null)
401 MainWindow.ErrorBox("No token selected.");
402 else
403 {
404 try
405 {
406 await this.neuroFeaturesClient.AddXmlNoteAsync(this.selectedItem.TokenId, s);
407 this.LoadEvents();
408 }
409 catch (Exception ex)
410 {
411 MainWindow.ErrorBox(ex.Message);
412 }
413 }
414 }
415
417 public override async Task Start()
418 {
420 {
421 MainWindow.currentInstance.TokensTab.DataContext = this;
422 return Task.CompletedTask;
423 });
424
425 await this.LoadTotals();
426
427 int Offset = 0;
428 int c = 20;
429
430 TokensEventArgs e2 = await this.neuroFeaturesClient.GetTokensAsync(Offset, c);
431 while (e2.Ok)
432 {
433 foreach (Token Token in e2.Tokens)
434 {
435 TokenModel TokenModel = await TokenModel.CreateAsync(this.neuroFeaturesClient, Token, "en", MainWindow.DesignModel);
436 TokenModel.Selected += this.Token_Selected;
437 TokenModel.Deselected += this.Token_Deselected;
438 TokenModel.NoteAdded += this.Token_NoteAdded;
439
440 lock (this.tokens)
441 {
442 this.tokens.Add(TokenModel);
443 }
444 }
445
446 this.RaisePropertyChanged(nameof(this.Tokens));
447
448 Offset += e2.Tokens.Length;
449 if (e2.Tokens.Length == 0)
450 break;
451
452 e2 = await this.neuroFeaturesClient.GetTokensAsync(Offset, c);
453 }
454
455 await base.Start();
456 }
457
458 private Task NeuroFeaturesClient_VariablesUpdated(object Sender, VariablesUpdatedEventArgs e)
459 {
460 MainWindow.UpdateGui(async () =>
461 {
462 try
463 {
464 foreach (TokenModel Token in this.tokens)
465 {
466 if (Token.TokenId == e.TokenId)
467 {
468 Token.VariablesUpdated(e.Variables);
469 await Token.UpdateNoteCommands();
470
471 if (this.selectedItem?.Token.TokenId == e.TokenId)
472 {
473 await this.PrepareTokenMenuItems();
474 }
475 }
476 }
477
478 foreach (object Control in MainWindow.currentInstance.TabControl.Items)
479 {
480 if (Control is not TabItem Tab)
481 continue;
482
483 if (Tab.Content is not ReportTab ReportTab)
484 continue;
485
486 if (ReportTab.Report.TokenId != e.TokenId)
487 continue;
488
489 await ReportTab.Report.OnVariablesUpdated(Sender, e);
490 }
491 }
492 catch (Exception ex)
493 {
494 MainWindow.ErrorBox(ex.Message);
495 }
496 });
497
498 return Task.CompletedTask;
499 }
500
501 private Task NeuroFeaturesClient_StateUpdated(object Sender, NewStateEventArgs e)
502 {
503 MainWindow.UpdateGui(async () =>
504 {
505 try
506 {
507 foreach (TokenModel Token in this.tokens)
508 {
509 if (Token.TokenId == e.TokenId)
510 {
511 Token.StateUpdated(e.NewState);
512 await Token.UpdateNoteCommands();
513
514 if (this.selectedItem?.Token.TokenId == e.TokenId)
515 await this.PrepareTokenMenuItems();
516 }
517 }
518
519 foreach (object Control in MainWindow.currentInstance.TabControl.Items)
520 {
521 if (Control is not TabItem Tab)
522 continue;
523
524 if (Tab.Content is not ReportTab ReportTab)
525 continue;
526
527 if (ReportTab.Report.TokenId != e.TokenId)
528 continue;
529
530 await ReportTab.Report.OnNewState(Sender, e);
531 }
532 }
533 catch (Exception ex)
534 {
535 MainWindow.ErrorBox(ex.Message);
536 }
537 });
538
539 return Task.CompletedTask;
540 }
541
542 }
543}
Event arguments events when the current state of a state-machine has changed.
Event arguments for token events.
Event arguments to totals response callback methods.
TokenTotal[] Totals
Token totals, per currency.
Event arguments for Tokens responses
Event arguments events when the variables of a state-machine has changed.
Information about a note command related to the state-machine associated with the token.
Definition: NoteCommand.cs:17
Neuro-Feature Token
Definition: Token.cs:43
string TokenId
Token ID
Definition: Token.cs:111
Helps with common XML-related tasks.
Definition: XML.cs:19
static bool IsValidXml(string Xml)
Checks if a string is valid XML
Definition: XML.cs:1223
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
Adds support for legal identities, smart contracts and signatures to an XMPP client.
bool Ok
If the response is an OK result response (true), or an error response (false).
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:59