@ -4,26 +4,27 @@ using CommunityToolkit.Mvvm.ComponentModel;
using MultiTerm.Core.Types ;
using MultiTerm.Protocols.Model ;
using System.Collections.ObjectModel ;
using System.Text ;
namespace MultiTerm.Core.ViewModel ;
public partial class CommunicationDataViewModel : ObservableObject , ICommunicationDataViewModel < CharacterDataViewModel , ExtendedChar >
public partial class CommunicationDataViewModel : ObservableObject , ICommunicationDataViewModel < ByteDataViewModel , ExtendedByte >
{
private readonly IContext uiContext ;
private int dataCharacterCount = 0 ;
private List < char > ? listOfPreviousCharacters = null ;
private List < byte > ? listOfPreviousCharacters = null ;
#region ICommunicationDataViewModel Implementation
[ObservableProperty]
private ObservableCollection < Character DataViewModel> data = new ( ) ;
private ObservableCollection < Byte DataViewModel> data = new ( ) ;
[ObservableProperty]
private string dataAsString = string . Empty ;
[ObservableProperty]
private ObservableCollection < Character DataViewModel> ? selected = new ( ) ;
private ObservableCollection < Byte DataViewModel> ? selected = new ( ) ;
[ObservableProperty]
NewlineSeparatorType newlineSeparator = NewlineSeparatorType . None ;
@ -42,29 +43,30 @@ public partial class CommunicationDataViewModel : ObservableObject, ICommunicati
// int counter = 0;
// int lineNumber = 1;
// //List<ExtendedChar> listOfChars = new();
// foreach (var character in exampleData)
// foreach (var dataByte in exampleData)
// {
// if(++counter > 100 || character == '\n')
// if(++counter > 100 || dataByte == '\n')
// {
// //this.ReceivedData.Add();
// //listOfChars = new List<ExtendedChar>();
// counter = 0;
// lineNumber += 1;
// }
// var extdChar = new ExtendedChar(character );
// var extdChar = new ExtendedChar(dataByte );
// //listOfChars.Add(extdChar);
// this.ReceivedData.Add(new DataViewModel(extdChar, lineNumber));
// }
//}
}
public void HandleNewData ( IEnumerable < ExtendedChar > newRawData )
public void HandleNewData ( IEnumerable < ExtendedByte > newRawData )
{
// update collection and string, invoke ui thread if necessary
ContextHelpers . InvokeIfNecessary ( this . uiContext , ( Action ) delegate
{
InsertNewNewCharactersIntoCollection ( this . Data , ref this . dataCharacterCount , ref this . listOfPreviousCharacters , this . NewlineSeparator , newRawData ) ;
this . DataAsString = InsertNewCharactersIntoString ( this . DataAsString , newRawData ) ;
this . DataAsString = InsertNewNewCharactersIntoCollection ( this . Data , this . DataAsString ,
ref this . dataCharacterCount , ref this . listOfPreviousCharacters ,
this . NewlineSeparator , newRawData ) ;
} ) ;
}
@ -76,51 +78,69 @@ public partial class CommunicationDataViewModel : ObservableObject, ICommunicati
// update collection, invoke ui thread if necessary
ContextHelpers . InvokeIfNecessary ( this . uiContext , ( Action ) delegate
{
this . Data = ReorderCollection ( this . Data , value ) ;
this . DataAsString = ReorderString ( this . Data , value ) ;
var reorderedCollection = ReorderCollection ( this . Data , value ) ;
this . Data = reorderedCollection . Item1 ;
this . DataAsString = reorderedCollection . Item2 ;
} ) ;
}
public void Clear ( )
{
// update collection and string, invoke ui thread if necessary
ContextHelpers . InvokeIfNecessary ( this . uiContext , ( Action ) delegate
{
this . DataAsString = string . Empty ;
this . Data . Clear ( ) ;
} ) ;
}
#region Collection Manipulation
/// <summary>
/// Function that reorders a given collection with item type <see cref="CharacterDataViewModel"/> using the given <paramref name="newlineSeparatorType"/>.
/// Function that reorders a given collection with item type <see cref="Byte DataViewModel"/> using the given <paramref name="newlineSeparatorType"/>.
/// Reordered collection is returned, but LineIdentifier is also overwritten in the <paramref name="currentCollection"/> parameter.
/// </summary>
/// <param name="currentCollection">items in this collection will be reordered</param>
/// <param name="newlineSeparatorType">separator between lines</param>
/// <returns>reordered collection</returns>
private static ObservableCollection < CharacterDataViewModel > ReorderCollection ( ObservableCollection < CharacterDataViewModel > currentCollection , NewlineSeparatorType newlineSeparatorType )
/// <returns>reordered collection and string </returns>
private static Tuple < ObservableCollection < ByteDataViewModel > , string > ReorderCollection ( ObservableCollection < Byte DataViewModel> currentCollection , NewlineSeparatorType newlineSeparatorType )
{
ObservableCollection < CharacterDataViewModel > newCollection = new ( ) ;
ObservableCollection < ByteDataViewModel > newCollection = new ( ) ;
StringBuilder stringBuilder = new ( ) ;
// local vars
int lineCounter = 0 ;
List < char > ? previousCharacters = null ;
List < byte > ? previousByte s = null ;
// iterate through items
foreach ( Character DataViewModel item in currentCollection )
foreach ( Byte DataViewModel item in currentCollection )
{
item . LineIdentifier = lineCounter ;
newCollection . Add ( item ) ;
stringBuilder . Append ( item . DisplayStringChar ) ;
switch ( ShouldIntroduceNewlineAfterThisCharacter ( item . Character , previousCharacter s , newlineSeparatorType ) )
switch ( ShouldIntroduceNewlineAfterThisByte ( item . Byte , previousByte s , newlineSeparatorType ) )
{
case IntroduceNewlineAfterThisCharacter Result. NoNewline :
// a decision could be made, previousCharacter s can be cleared
if ( previousCharacter s ! = null ) { previousCharacter s = null ; }
case ShouldIntroduceNewlineAfterThisByte Result. NoNewline :
// a decision could be made, previousByte s can be cleared
if ( previousByte s ! = null ) { previousByte s = null ; }
// nothing to do
break ;
case IntroduceNewlineAfterThisCharacter Result. IntroduceNewline :
// a decision could be made, previousCharacter s can be cleared
if ( previousCharacter s ! = null ) { previousCharacter s = null ; }
// increase line count and break
case ShouldIntroduceNewlineAfterThisByte Result. IntroduceNewline :
// a decision could be made, previousByte s can be cleared
if ( previousByte s ! = null ) { previousByte s = null ; }
// increase line count
lineCounter + + ;
// append line in string
stringBuilder . AppendLine ( ) ;
break ;
case IntroduceNewlineAfterThisCharacter Result. RequiresMoreCharacters :
// first time that more character s are required => create new list
previousCharacter s ? ? = new List < char > ( ) ;
// add current character to list
previousCharacter s . Add ( item . Character ) ;
case ShouldIntroduceNewlineAfterThisByte Result. RequiresMoreCharacters :
// first time that more byte s are required => create new list
previousByte s ? ? = new List < byte > ( ) ;
// add current byte to list
previousByte s . Add ( item . Byte ) ;
break ;
default :
@ -128,65 +148,77 @@ public partial class CommunicationDataViewModel : ObservableObject, ICommunicati
}
}
return newCollection ;
return Tuple . Create ( newCollection , stringBuilder . ToString ( ) ) ;
}
/// <summary>
/// Function that handles a collection of new character s that should end up in the collection <paramref name="dataCollection"/>.
/// Function that handles a collection of new byte s that should end up in the collection <paramref name="dataCollection"/>.
/// In case a new line is required, according to the given <paramref name="newlineSeparatorType"/>, it is automatically introduced.
/// Following parameters need to be referenced and stored outside: <paramref name="collectionLineCounter"/> and <paramref name="previousCharacter s"/>.
/// Following parameters need to be referenced and stored outside: <paramref name="collectionLineCounter"/> and <paramref name="previousByte s"/>.
/// </summary>
/// <param name="dataCollection">collection to add the characters to</param>
/// <param name="dataCollection">collection to add the bytes to</param>
/// <param name="dataCollectionAsString">collection as string</param>
/// <param name="collectionLineCounter">current line count</param>
/// <param name="previousCharacters">list of previous character , newest at the last position of the list, null if nothing is stored</param>
/// <param name="previousBytes">list of previous bytes , newest at the last position of the list, null if nothing is stored</param>
/// <param name="newlineSeparatorType">separator between seperate lines</param>
/// <param name="newCharacters">characters to add to the <paramref name="dataCollection"/></param>
/// <param name="newBytes">bytes to add to the <paramref name="dataCollection"/></param>
/// <returns>string representation of data</returns>
/// <exception cref="Exception">in case of any error</exception>
private static void InsertNewNewCharactersIntoCollection ( ObservableCollection < CharacterDataViewModel > dataCollection ,
private static string InsertNewNewCharactersIntoCollection (
ObservableCollection < ByteDataViewModel > dataCollection ,
string dataCollectionAsString ,
ref int collectionLineCounter ,
ref List < char > ? previousCharacters ,
ref List < byte > ? previousByte s,
NewlineSeparatorType newlineSeparatorType ,
IEnumerable < ExtendedChar > newCharacter s )
IEnumerable < ExtendedByte > newByte s )
{
// go through every character
foreach ( var newExtdChar in newCharacters )
StringBuilder stringBuilder = new ( ) ;
stringBuilder . Append ( dataCollectionAsString ) ;
// go through every byte
foreach ( ExtendedByte newByte in newBytes )
{
// add to collection with the current counter, invoking UI context if necssary
// add to collection and string with the current counter, invoking UI context if necssary
var currentLineCounter = collectionLineCounter ;
dataCollection . Add ( new CharacterDataViewModel ( newExtdChar , currentLineCounter ) ) ;
dataCollection . Add ( new ByteDataViewModel ( newByte , currentLineCounter ) ) ;
stringBuilder . Append ( newByte . ToCharacterString ( ) ) ;
switch ( ShouldIntroduceNewlineAfterThisCharacter ( newExtdChar . Character , previousCharacter s , newlineSeparatorType ) )
switch ( ShouldIntroduceNewlineAfterThisByte ( newByte . Byte , previousByte s , newlineSeparatorType ) )
{
case IntroduceNewlineAfterThisCharacter Result. NoNewline :
// a decision could be made, previousCharacter s can be cleared
if ( previousCharacter s ! = null ) { previousCharacter s = null ; }
case ShouldIntroduceNewlineAfterThisByte Result. NoNewline :
// a decision could be made, previousByte s can be cleared
if ( previousByte s ! = null ) { previousByte s = null ; }
// nothing to do
break ;
case IntroduceNewlineAfterThisCharacter Result. IntroduceNewline :
// a decision could be made, previousCharacter s can be cleared
if ( previousCharacter s ! = null ) { previousCharacter s = null ; }
// increase line count and break
case ShouldIntroduceNewlineAfterThisByte Result. IntroduceNewline :
// a decision could be made, previousByte s can be cleared
if ( previousByte s ! = null ) { previousByte s = null ; }
// increase line count
collectionLineCounter + + ;
// append line in string
stringBuilder . AppendLine ( ) ;
break ;
case IntroduceNewlineAfterThisCharacter Result. RequiresMoreCharacters :
// first time that more character s are required => create new list
previousCharacter s ? ? = new List < char > ( ) ;
// add current character to list
previousCharacter s . Add ( newExtdChar . Character ) ;
case ShouldIntroduceNewlineAfterThisByte Result. RequiresMoreCharacters :
// first time that more byte s are required => create new list
previousByte s ? ? = new List < byte > ( ) ;
// add current byte to list
previousByte s . Add ( newByte . Byte ) ;
break ;
default :
throw new Exception ( $"'{nameof(InsertNewNewCharactersIntoCollection)}()' failed because of error when checking if a newline should be introduced." ) ;
}
}
return stringBuilder . ToString ( ) ;
}
/// <summary>
/// Result type for <see cref="ShouldIntroduceNewlineAfterThisCharacter "/>
/// Result type for <see cref="ShouldIntroduceNewlineAfterThisByte "/>
/// </summary>
public enum IntroduceNewlineAfterThisCharacter Result
public enum ShouldIntroduceNewlineAfterThisByte Result
{
/// <summary>
/// No newline is required.
@ -194,7 +226,7 @@ public partial class CommunicationDataViewModel : ObservableObject, ICommunicati
NoNewline ,
/// <summary>
/// A newline shall be introduced after this character .
/// A newline shall be introduced after this byte .
/// </summary>
IntroduceNewline ,
@ -205,17 +237,17 @@ public partial class CommunicationDataViewModel : ObservableObject, ICommunicati
}
/// <summary>
/// Function to check wether a newline shall be introduced after the given character .
/// Since some newline sequences will require multiple character s in correct order, a more complex handling is required, which is possible using this function.
/// Function to check wether a newline shall be introduced after the given <paramref name="dataByte"/> .
/// Since some newline sequences will require multiple byte s in correct order, a more complex handling is required, which is possible using this function.
/// </summary>
/// <param name="character">the current character in the collection (or a single character )</param>
/// <param name="previousCharacters">list of previous character , newest at the last position of the list, null if not required</param>
/// <param name="dataByte">the current dataByte in the collection (or a single byte )</param>
/// <param name="previousBytes">list of previous bytes , newest at the last position of the list, null if not required</param>
/// <param name="newlineSeparatorType">separator type</param>
/// <returns>complex result of type <see cref="IntroduceNewlineAfterThisCharacter Result"/></returns>
/// <returns>enum result of type <see cref="ShouldIntroduceNewlineAfterThisByte Result"/></returns>
/// <exception cref="NotImplementedException">if the handling for the <paramref name="newlineSeparatorType"/> is not implemented</exception>
private static IntroduceNewlineAfterThisCharacterResult ShouldIntroduceNewlineAfterThisCharacter ( char character , List < char > ? previousCharacter s, NewlineSeparatorType newlineSeparatorType )
private static ShouldIntroduceNewlineAfterThisByteResult ShouldIntroduceNewlineAfterThisByte ( byte dataByte , List < byte > ? previousByte s, NewlineSeparatorType newlineSeparatorType )
{
var result = IntroduceNewlineAfterThisCharacter Result. NoNewline ;
var result = ShouldIntroduceNewlineAfterThisByte Result. NoNewline ;
switch ( newlineSeparatorType )
{
@ -223,63 +255,41 @@ public partial class CommunicationDataViewModel : ObservableObject, ICommunicati
break ;
case NewlineSeparatorType . CR :
if ( character = = '\r' )
if ( dataByte = = ( byte ) '\r' )
{
result = IntroduceNewlineAfterThisCharacter Result. IntroduceNewline ;
result = ShouldIntroduceNewlineAfterThisByte Result. IntroduceNewline ;
}
break ;
case NewlineSeparatorType . LF :
if ( character = = '\n' )
if ( dataByte = = ( byte ) '\n' )
{
result = IntroduceNewlineAfterThisCharacter Result. IntroduceNewline ;
result = ShouldIntroduceNewlineAfterThisByte Result. IntroduceNewline ;
}
break ;
case NewlineSeparatorType . CR_LF :
if ( character = = '\r' )
if ( dataByte = = ( byte ) '\r' )
{
result = IntroduceNewlineAfterThisCharacter Result. RequiresMoreCharacters ;
result = ShouldIntroduceNewlineAfterThisByte Result. RequiresMoreCharacters ;
}
if ( character = = '\n' )
if ( dataByte = = ( byte ) '\n' )
{
if ( previousCharacter s ! = null & & previousCharacter s . Last ( ) = = '\r' )
if ( previousByte s ! = null & & previousByte s . Last ( ) = = ( byte ) '\r' )
{
result = IntroduceNewlineAfterThisCharacter Result. IntroduceNewline ;
result = ShouldIntroduceNewlineAfterThisByte Result. IntroduceNewline ;
}
}
break ;
default :
throw new NotImplementedException ( $"'{nameof(ShouldIntroduceNewlineAfterThisCharacter )}()' does not implement handling for {nameof(NewlineSeparatorType)} {newlineSeparatorType}" ) ;
throw new NotImplementedException ( $"'{nameof(ShouldIntroduceNewlineAfterThisByte )}()' does not implement handling for {nameof(NewlineSeparatorType)} {newlineSeparatorType}" ) ;
}
return result ;
}
# endregion
#region String Manipulation
// TODO Implement Line Handling
private static string InsertNewCharactersIntoString ( string dataAsString , IEnumerable < ExtendedChar > newRawData )
{
string newDataAsString = dataAsString ;
foreach ( ExtendedChar character in newRawData )
{
newDataAsString + = character . Character ;
}
return newDataAsString ;
}
private static string ReorderString ( ObservableCollection < CharacterDataViewModel > collection , NewlineSeparatorType value )
{
// Not yet implemented
return "Not implemented" ;
}
# endregion
}