5using System.Text.RegularExpressions;
6using System.Threading.Tasks;
21 private readonly
string threadId;
22 private readonly SortedDictionary<string, SourceState> sources =
new SortedDictionary<string, SourceState>();
24 private readonly
int maxPaletteSize;
25 private Dictionary<string, KeyValuePair<SKColor, int>> legend =
null;
27 private SKColor[] palette =
null;
28 private object tag =
null;
29 private int nrTop = 0;
30 private int nrBottom = 0;
31 private bool filterSources =
false;
42 this.maxPaletteSize = MaxPaletteSize;
55 await this.synchObject.BeginRead();
58 string[] Result =
new string[this.sources.Count];
59 this.sources.Keys.CopyTo(Result, 0);
64 await this.synchObject.EndRead();
73 await this.synchObject.BeginRead();
88 await this.synchObject.EndRead();
97 get => this.filterSources;
98 set => this.filterSources = value;
107 set => this.tag = value;
118 return this.
Add(Source, Markdown,
string.Empty);
130 return this.
Add(Source, Markdown, Id,
false,
false);
139 public Task<bool>
Add(
string Source,
string Text)
141 return this.
Add(Source, Text,
string.Empty);
151 public Task<bool>
Add(
string Source,
string Text,
string Id)
153 return this.
Add(Source, Text, Id,
false,
false);
165 return this.
Add(Source, Markdown, Id,
true,
false);
175 public Task<bool>
Update(
string Source,
string Text,
string Id)
177 return this.
Add(Source, Text, Id,
true,
false);
189 private async Task<bool>
Add(
string Source,
string Text,
string Id,
bool Update,
bool IsDefault)
192 return await this.
Add(Source, Doc, Id,
Update, IsDefault);
203 return this.
Add(Source, Text,
string.Empty,
false,
true);
214 return this.
Add(Source, Markdown,
string.Empty,
false,
true);
231 await this.synchObject.BeginWrite();
234 if ((Result = !this.sources.TryGetValue(Source, out
SourceState State)) || State.IsDefault)
236 if (Result && this.filterSources)
240 this.sources[Source] = State;
243 if (Markdown is
null)
247 Type = await State.Update(Markdown, Id);
249 Type = await State.Add(Markdown, Id);
251 if ((
int)(this.type & Type) != 0)
252 this.type = (
DocumentType)Math.Max((
int)this.type, (int)Type);
264 string[] Rows0 =
null;
267 foreach (SourceState Info
in this.sources.Values)
269 Rows = Info.FirstDocument.Rows;
275 this.nrTop = this.nrBottom = d;
281 c = Math.Min(this.nrTop, d);
283 for (i = 0; i < c; i++)
285 if (Rows[i] != Rows0[i])
291 c = Math.Min(this.nrBottom, d);
293 for (i = 0; i < c; i++)
295 if (Rows[d - i - 1] != Rows0[d0 - i - 1])
303 if (this.nrTop < 1 || this.nrBottom <= 1)
308 if (this.sources.Count >= 2)
315 await this.synchObject.EndWrite();
319 await this.Raise(this.
Updated, Source);
321 await this.Raise(this.
Added, Source);
326 private Task Raise(EventHandlerAsync<SourceEventArgs> Handler,
string Source)
328 return Handler.Raise(
this,
new SourceEventArgs(Source));
334 public event EventHandlerAsync<SourceEventArgs>
Added =
null;
339 public event EventHandlerAsync<SourceEventArgs>
Updated =
null;
345 [Obsolete(
"Use GenerateMarkdownAsync() instead.")]
357 StringBuilder Markdown =
new StringBuilder();
359 await this.synchObject.BeginRead();
370 Markdown.AppendLine(
"| Nr | Source | Response |");
373 Markdown.AppendLine(
"|---:|:-------|-------:|");
375 Markdown.AppendLine(
"|---:|:-------|:-------|");
379 foreach (KeyValuePair<string, SourceState> P
in this.sources)
381 Markdown.Append(
"| ");
383 Markdown.Append(
" | `");
384 Markdown.Append(P.Key);
385 Markdown.Append(
"` | ");
386 Markdown.Append((await P.Value.GetFirstText()).Trim());
387 Markdown.AppendLine(
" |");
393 Markdown.AppendLine(
"| Nr | Source | Response |");
394 Markdown.AppendLine(
"|---:|:-------|:-------|");
398 foreach (KeyValuePair<string, SourceState> P
in this.sources)
400 Markdown.Append(
"| ");
402 Markdown.Append(
" | `");
403 Markdown.Append(P.Key);
404 Markdown.Append(
"` | ");
406 foreach (
string Row
in P.Value.FirstDocument.Rows)
408 Markdown.Append(Row);
409 Markdown.Append(
"<br/>");
412 Markdown.AppendLine(
"|");
421 int d = this.sources.Count;
423 foreach (KeyValuePair<string, SourceState> P
in this.sources)
425 string[] Rows = P.Value.FirstDocument.Rows;
437 ConsolidatedRows.Add(Rows[i]);
440 if (ConsolidatedRows[0].StartsWith(
"```dot", StringComparison.OrdinalIgnoreCase))
441 OptimizeDotEdges(ConsolidatedRows);
443 foreach (
string Row
in ConsolidatedRows)
444 Markdown.AppendLine(Row);
453 foreach (KeyValuePair<string, SourceState> P
in this.sources)
457 if (!(Doc?.Table is
null))
472 this.GenerateComplexLocked(Markdown);
483 this.legend ??=
new Dictionary<string, KeyValuePair<SKColor, int>>();
486 foreach (KeyValuePair<string, SourceState> P
in this.sources)
490 if (!(Doc?.
Graph is
null))
492 i = this.legend.Count % this.maxPaletteSize;
494 this.legend[P.Key] =
new KeyValuePair<SKColor, int>(this.palette[i], i);
504 Markdown.AppendLine(
"```Graph");
506 Markdown.AppendLine();
507 Markdown.AppendLine(
"```");
509 if (this.legend.Count > 0)
511 string[] Labels =
new string[this.legend.Count];
512 SKColor[] Colors =
new SKColor[this.legend.Count];
515 Markdown.AppendLine();
517 foreach (KeyValuePair<
string, KeyValuePair<SKColor, int>> P
in this.legend)
520 Colors[i] = P.Value.Key;
526 Markdown.AppendLine(
"```layout");
527 Markdown.AppendLine(LegandXml);
528 Markdown.AppendLine(
"```");
529 Markdown.AppendLine();
532 Markdown.AppendLine();
537 this.GenerateComplexLocked(Markdown);
543 this.GenerateComplexLocked(Markdown);
549 await this.synchObject.EndRead();
552 return Markdown.ToString();
555 private static readonly Regex dotEdge =
new Regex(
"^(?'A'(\"[^\"]*\"|'[^']*'|[^\\s]*))\\s*->\\s*(?'B'(\"[^\"]*\"|'[^']*'|[^\\s]*))\\s*([\\[](?'Note'[^\\]]*)[\\]]\\s*)?;\\s*$", RegexOptions.Singleline | RegexOptions.Compiled);
561 string Row, Row2, A, B, Note;
562 int i, j, c = Rows.
Count;
563 bool Changed =
false;
565 Matches =
new Match[c];
567 for (i = 0; i < c; i++)
573 M = dotEdge.Match(Row);
577 if (!M.Success || M.Index > 0 || M.Length < Row.Length)
580 A = M.Groups[
"A"].Value;
581 B = M.Groups[
"B"].Value;
582 Note = M.Groups[
"Note"].Value;
584 for (j = i + 1; j < c; j++)
590 M = dotEdge.Match(Row2);
596 M.Length == Row.Length &&
597 M.Groups[
"A"].Value == B &&
598 M.Groups[
"B"].Value == A &&
599 M.Groups[
"Note"].Value == Note)
601 StringBuilder sb =
new StringBuilder();
609 if (!
string.IsNullOrEmpty(Note))
612 sb.Append(
"dir=both];");
616 Rows[j] =
string.Empty;
628 if (
string.IsNullOrEmpty(Rows[i]))
646 SKColor[] Result =
new SKColor[N];
647 double d = 360.0 / Math.Max(N, 12);
650 for (i = 0; i < N; i++)
651 Result[i] = SKColor.FromHsl((
float)(d * i), 100, 75);
656 private void GenerateComplexLocked(StringBuilder Markdown)
658 foreach (KeyValuePair<string, SourceState> P
in this.sources)
660 Markdown.Append(
'`');
661 Markdown.Append(P.Key);
662 Markdown.AppendLine(
"`");
663 Markdown.AppendLine();
667 if (Info.Length == 0)
668 Markdown.AppendLine(
":\t");
678 Markdown.AppendLine(
":\t");
680 if (!(Doc?.Rows is
null))
682 foreach (
string Row
in Doc.
Rows)
684 Markdown.Append(
":\t");
685 Markdown.AppendLine(Row);
691 Markdown.AppendLine();
698 [Obsolete(
"Use DisposeAsync() instead.")]
716 return this.
Disposed.Raise(
this, EventArgs.Empty,
false);
Represents a consolidated table.
async Task Export(StringBuilder Markdown)
Exports the consolidated table to Markdown.
async Task Add(string Source, Table MarkdownTable)
Adds data from a Markdown table to the consolidated table.
static async Task< ConsolidatedTable > CreateAsync(string Source, Table MarkdownTable)
Creates a consolidated table.
Consolidates Markdown from multiple sources, sharing the same thread.
Task< bool > Add(string Source, MarkdownDocument Markdown, string Id)
Adds incoming markdown information.
void Dispose()
IDisposable.Dispose
Task< bool > Add(string Source, string Text, string Id)
Adds incoming markdown information.
Task< bool > AddDefault(string Source, string Text)
Adds default markdown to present, until a proper response is returned.
Task< bool > Add(string Source, string Text)
Adds incoming markdown information.
Task< bool > Update(string Source, string Text, string Id)
Updates incoming markdown information.
object Tag
External tag object that can be tagged to the object by its owner.
async Task< int > GetNrReportedSources()
Number of sources that have reported content.
async Task< string[]> GetSources()
Consolidated sources.
string GenerateMarkdown()
Generates consolidated markdown from all sources.
Consolidator(string ThreadId, int MaxPaletteSize)
Consolidates Markdown from multiple sources, sharing the same thread.
EventHandlerAsync< SourceEventArgs > Added
Event raised when content from a source has been added.
Task DisposeAsync()
IDisposable.Dispose
Task< bool > AddDefault(string Source, MarkdownDocument Markdown)
Adds default markdown to present, until a proper response is returned.
async Task< string > GenerateMarkdownAsync()
Generates consolidated markdown from all sources.
Task< bool > Update(string Source, MarkdownDocument Markdown, string Id)
Updates incoming markdown information.
bool FilterSources
If input should be restricted to a defined set of sources.
EventHandlerAsync Disposed
Event raised when consolidator has been disposed.
static SKColor[] CreatePalette(int N)
Creates a palette for graphs.
EventHandlerAsync< SourceEventArgs > Updated
Event raised when content from a source has been updated.
Task< bool > Add(string Source, MarkdownDocument Markdown)
Adds incoming markdown information.
Information about a document.
Graph Graph
Graph object, if DocumentType.SingleGraph
Table Table
Table object, if DocumentType.SingleTable
Maintains the state of one source.
bool IsDefault
If the content is default content (true), or reported content (false).
Contains a markdown document. This markdown document class supports original markdown,...
static Task< MarkdownDocument > CreateAsync(string MarkdownText, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
Static class managing the application event log. Applications and services log events on this static ...
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.
Creates a legend that can be displayed in association with a graph containing multiple series.
static string CreateLayout(string[] Labels, SKColor[] Colors, SKColor FgColor, int NrColumns, Variables Variables)
Creates a graph bitmap containing a legend.
A chunked list is a linked list of chunks of objects of type T .
void RemoveAt(int Index)
Removes the item at the specified index.
override string ToString()
int Count
Number of elements in collection.
Represents an object that allows single concurrent writers but multiple concurrent readers....
string ToXml()
Exports the graph to XML.
abstract bool TrySetDefaultColor(SKColor Color)
Tries to set the default color.
virtual ISemiGroupElementWise AddRightElementWise(ISemiGroupElementWise Element)
Tries to add an element to the current element, from the right, element-wise.
Interface for consolidators.
DocumentType
Type of markdown document.
delegate string ToString(IElement Element)
Delegate for callback methods that convert an element value to a string.
delegate Task EventHandlerAsync(object Sender, EventArgs e)
Asynchronous version of EventArgs.