using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using H.Pipes;
using InABox.Logging;
using InABox.Wpf;
using Microsoft.Win32;
namespace PRSServer
{
public static class ItemsControlExtensions
{
public static void ScrollIntoView(
this ItemsControl control,
object item)
{
var framework =
control.ItemContainerGenerator.ContainerFromItem(item)
as FrameworkElement;
if (framework == null) return;
framework.BringIntoView();
}
public static void ScrollIntoView(this ItemsControl control)
{
var count = control.Items.Count;
if (count == 0) return;
var item = control.Items[count - 1];
control.ScrollIntoView(item);
}
}
///
/// Interaction logic for Console.xaml
///
public partial class Console : ThemableWindow
{
private PipeClient _client;
public CollectionViewSource _filtered;
private readonly ObservableCollection _logentries;
private readonly bool _monitoronly = true;
private PRSService _service;
public string ServiceName { get; private set; }
private readonly string description;
private readonly TimeSpan regexTimeOut = TimeSpan.FromMilliseconds(100);
private Timer? RefreshTimer;
private Regex? searchRegex;
public Console(string servicename, string description, bool monitoronly = true)
{
ServiceName = servicename;
_monitoronly = monitoronly;
InitializeComponent();
_logentries = new ObservableCollection();
_filtered = new CollectionViewSource();
_filtered.Source = _logentries;
_filtered.Filter += (sender, args) =>
{
var logEntry = (LogEntry)args.Item;
if (ShowImportant.IsChecked == true && !IsImportant(logEntry))
{
args.Accepted = false;
return;
}
if (UseRegEx.IsChecked == true && searchRegex != null)
args.Accepted = string.IsNullOrWhiteSpace(Search.Text)
|| searchRegex.IsMatch(logEntry.DateTime)
|| searchRegex.IsMatch(logEntry.Type)
|| searchRegex.IsMatch(logEntry.User)
|| searchRegex.IsMatch(logEntry.Message);
else
args.Accepted = string.IsNullOrWhiteSpace(Search.Text)
|| logEntry.DateTime.Contains(Search.Text)
|| logEntry.Type.Contains(Search.Text)
|| logEntry.User.Contains(Search.Text)
|| logEntry.Message.Contains(Search.Text);
};
DataContext = _filtered;
Title = description;
this.description = description;
}
private bool IsImportant(LogEntry entry)
{
return entry.Type == "IMPTNT";
}
private LogEntry ParseLogMessage(string logLine)
{
var datetime = logLine.Length > 32 ? logLine.Substring(0, 12) : string.Format("{0:HH:mm:ss.fff}", DateTime.Now);
var type = logLine.Length > 32 ? logLine.Substring(13, 6).Trim() : "INFO";
var user = logLine.Length > 32 ? logLine.Substring(20, 12) : "";
var msg = logLine.Length > 32 ? logLine.Substring(33) : logLine;
return new LogEntry
{
DateTime = datetime,
Type = type,
User = user,
Message = msg
};
}
private void Console_Loaded(object sender, RoutedEventArgs e)
{
_client = new PipeClient(ServiceName, ".");
_client.MessageReceived += (o, args) =>
{
var m = args.Message;
var logEntry = ParseLogMessage(args.Message ?? "");
var logType = logEntry.Type;
if (logType == "INFO" || logType == "ERROR" || logType == "IMPTNT")
Dispatcher.BeginInvoke((Action)(() => { _logentries.Insert(0, logEntry); }));
};
_client.Connected += (o, args) =>
{
Dispatcher.Invoke(() => LogBorder.Background = new SolidColorBrush(Colors.LightYellow));
};
_client.Disconnected += (o, args) =>
{
Dispatcher.Invoke(() => LogBorder.Background = new SolidColorBrush(Colors.WhiteSmoke));
if (RefreshTimer == null)
{
RefreshTimer = new Timer(1000);
RefreshTimer.Elapsed += RefreshTimer_Elapsed;
}
RefreshTimer.Start();
};
_client.ExceptionOccurred += (o, args) =>
{
};
if (!_client.IsConnecting)
{
_client.ConnectAsync();
}
if (!_monitoronly)
{
var timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 3) };
timer.Tick += (o, args) =>
{
timer.IsEnabled = false;
_service = new PRSService(ServiceName, null);
_service.Run(ServiceName);
};
timer.IsEnabled = true;
}
}
private void RefreshTimer_Elapsed(object? sender, ElapsedEventArgs e)
{
if(!_client.IsConnected)
{
if (!_client.IsConnecting)
{
_client.ConnectAsync();
}
}
else
{
RefreshTimer?.Stop();
}
}
private void Window_Closing(object sender, CancelEventArgs e)
{
if (_monitoronly)
{
_client.DisposeAsync().AsTask().Wait();
RefreshTimer?.Stop();
}
else
_service?.Halt();
}
private void Search_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter && UseRegEx.IsChecked == true)
{
try
{
searchRegex = new Regex(Search.Text, RegexOptions.Compiled, regexTimeOut);
}
catch (ArgumentException)
{
searchRegex = null;
}
_filtered.View.Refresh();
SetSearchStyleNormal();
}
}
private void SetSearchStyleChanged()
{
Search.Background = Brushes.White;
}
private void SetSearchStyleNormal()
{
Search.Background = Brushes.LightYellow;
}
private void Search_TextChanged(object sender, TextChangedEventArgs e)
{
if (UseRegEx.IsChecked != true)
{
_filtered.View.Refresh();
}
else
{
if (string.IsNullOrWhiteSpace(Search.Text))
{
searchRegex = null;
_filtered.View.Refresh();
SetSearchStyleNormal();
}
else
{
SetSearchStyleChanged();
}
}
}
private void UseRegEx_Checked(object sender, RoutedEventArgs e)
{
try
{
searchRegex = new Regex(Search.Text, RegexOptions.Compiled, regexTimeOut);
}
catch (ArgumentException ex)
{
searchRegex = null;
}
_filtered.View.Refresh();
}
private void UseRegEx_Unchecked(object sender, RoutedEventArgs e)
{
searchRegex = null;
_filtered.View.Refresh();
SetSearchStyleNormal();
}
private void SetErrorMessage(string? error)
{
if (string.IsNullOrWhiteSpace(error))
{
Error.Content = "";
Error.Visibility = Visibility.Collapsed;
}
else
{
Error.Content = error;
Error.Visibility = Visibility.Visible;
}
}
private void LoadLog_Click(object sender, RoutedEventArgs e)
{
var dialog = new OpenFileDialog();
dialog.InitialDirectory = DatabaseEngine.GetPath(ServiceName);
if (dialog.ShowDialog() == true)
{
var logEntries = new List();
var numberSkipped = 0;
var lines = File.ReadLines(dialog.FileName);
foreach (var line in lines)
{
var logEntry = ParseLogMessage(line ?? "");
var logType = logEntry.Type;
if (logType == "ERROR" || logType == "INFO" || logType == "IMPTNT")
logEntries.Add(logEntry);
else if (string.IsNullOrWhiteSpace(logType)) numberSkipped++;
}
if (numberSkipped > 0)
{
if (logEntries.Count == 0)
SetErrorMessage("File does not contain valid log information!");
else
SetErrorMessage(string.Format("Skipped {0} lines that did not contain valid log information", numberSkipped));
}
Title = dialog.FileName;
_filtered.Source = logEntries;
LoadLog.Visibility = Visibility.Collapsed;
CloseLog.Visibility = Visibility.Visible;
}
}
private void CloseLog_Click(object sender, RoutedEventArgs e)
{
_filtered.Source = _logentries;
CloseLog.Visibility = Visibility.Collapsed;
LoadLog.Visibility = Visibility.Visible;
Title = description;
}
private void ShowImportant_Checked(object sender, RoutedEventArgs e)
{
_filtered.View.Refresh();
}
private void ShowImportant_Unchecked(object sender, RoutedEventArgs e)
{
_filtered.View.Refresh();
}
}
}