Multiprocotol Terminalprogram (BAT)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MultiTerm/MultiTerm.Core/ViewModel/ConsoleViewModel.cs

159 lines
5.4 KiB

using Common.AppSettings;
using Common.Logging;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using MultiTerm.Core.Model;
using MultiTerm.Core.Types;
using MultiTerm.Protocols.Model;
using System.Text;
namespace MultiTerm.Core.ViewModel;
public partial class ConsoleViewModel : TerminalViewModel
{
public override TerminalViewType ViewType => TerminalViewType.Console;
private readonly ILogger logger;
private Encoding currentEncoding;
/* settings */
private readonly Encoding defaultEncoding = Encoding.ASCII; // default encoding instance
private const EncodingType defaultEncodingType = EncodingType.ASCII; // default encoding type
private const int DataMaxLength = 5000; // maximum amount of characters stored int the data textbox
#region Observable Properties
/// <summary>
/// Holds Console content.
/// </summary>
[ObservableProperty]
private string data = string.Empty;
/// <summary>
/// Encoding type of the sent and received messages.
/// </summary>
[ObservableProperty]
private EncodingType selectedEncodingType = defaultEncodingType;
/// <summary>
/// Holds message that is to be sent next. E.g. currently being typed in.
/// </summary>
[ObservableProperty]
private string sendableMessage = string.Empty;
#endregion
public ConsoleViewModel(IAppSettingsProvider appSettings, IMessenger messenger, ILogger logger) : base(appSettings, messenger)
{
this.logger = logger;
this.currentEncoding = this.GetEncoding(this.SelectedEncodingType);
}
public override void DisplayNewReceivedData(IEnumerable<ExtendedByte> newData)
{
// extract bytes
var bytes = newData.Select(b => b.Byte).ToArray();
string newDataDecoded = currentEncoding.GetString(bytes);
// calculate new legth
int newTotalLength = this.Data.Length + newDataDecoded.Length;
// trim current data at the beginning if new length is too long
if (newTotalLength > DataMaxLength)
{
// trim overshoot from start of string
this.Data = this.Data[(newTotalLength - DataMaxLength)..];
}
// append data
this.Data += newDataDecoded;
}
/// <summary>
/// Command to send a prepared message.
/// </summary>
[RelayCommand]
public void Send()
{
// encode
var encodedBytes = this.currentEncoding.GetBytes(this.SendableMessage);
// send
if (this.SendToCommunicationProtocol(encodedBytes))
{
// add to history
this.AddToSendHistory(new StringHistoryElement(this.SendableMessage));
// clear if sending was successful
this.SendableMessage = string.Empty;
}
}
protected override void HandleInsertElementFromHistory(object element)
{
if(element is not StringHistoryElement elementString) { throw new Exception($"'{HandleInsertElementFromHistory}()' in {nameof(ConsoleViewModel)} got wrong type of element. Got Type: {element.GetType()}"); }
// overwrite sendable message with history element
this.SendableMessage = elementString.Text;
}
/// <summary>
/// Command to clear the data that was received.
/// </summary>
[RelayCommand]
public void ClearData()
{
this.Data = string.Empty;
}
/// <summary>
/// Handles changing of encoding type.
/// </summary>
/// <param name="value">new value</param>
partial void OnSelectedEncodingTypeChanged(EncodingType value)
{
this.currentEncoding = this.GetEncoding(value);
}
#region Unused Methods
public override void DisplayNewSentData(IEnumerable<ExtendedByte> newData)
{
// no display of sent data
}
protected override void ActOnDataDisplayNewlineSeparatorTypeChanged(NewlineSeparatorType newType)
{
// No change when data display newline separator type changed
}
#endregion
#region Helpers
/// <summary>
/// Returns <see cref="Encoding"/> instance of <paramref name="encodingType"/>.
/// If the <paramref name="encodingType"/> is not supported or any issue arrived, the <see cref="SelectedEncodingType"/> is set to ASCII and ASCII <see cref="Encoding"/> is returned.
/// </summary>
/// <param name="encodingType">type of encoding</param>
/// <returns>encoding instance</returns>
private Encoding GetEncoding(EncodingType encodingType)
{
Encoding? encoding;
try
{
// Encoding Type value corresponds to codepage number, therefore can be get by cast to int
encoding = Encoding.GetEncoding(Convert.ToInt32(encodingType));
}
catch (Exception)
{
// log exception and set encoding to null
this.logger.LogWarn($"'{nameof(GetEncoding)}()' failed to resolve encoding type {encodingType} (codepage {Convert.ToInt32(encodingType)}). Reverted to default.", nameof(ConsoleViewModel));
encoding = null;
}
// failed to get encoding or got null encoding
if (encoding == null)
{
// set selected encoding type to default and return default encoding
this.SelectedEncodingType = defaultEncodingType;
encoding = defaultEncoding;
}
return encoding!;
}
#endregion
}