using InABox.Clients;
using InABox.Core;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using InABox.WPF;
namespace InABox.Wpf;
public enum MessageWindowButtonPosition
{
Left,
Right
}
public enum MessageWindowResult
{
None,
OK,
Cancel,
Yes,
No,
Other
}
public class MessageWindowButton : INotifyPropertyChanged
{
public delegate void MessageWindowButtonDelegate(MessageWindow window, MessageWindowButton button);
public MessageWindowButtonPosition Position { get; set; }
private string _content;
public string Content
{
get => _content;
[MemberNotNull(nameof(_content))]
set
{
_content = value;
OnPropertyChanged();
}
}
public MessageWindowButtonDelegate Action { get; set; }
public MessageWindowButton(string content, MessageWindowButtonDelegate action, MessageWindowButtonPosition position)
{
Content = content;
Action = action;
Position = position;
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
///
/// Interaction logic for MessageWindow.xaml
///
public partial class MessageWindow : Window, INotifyPropertyChanged
{
public ObservableCollection Buttons { get; private set; } = new();
public IEnumerable LeftButtons => Buttons.Where(x => x.Position == MessageWindowButtonPosition.Left);
public IEnumerable RightButtons => Buttons.Where(x => x.Position == MessageWindowButtonPosition.Right);
private string _message = "";
public string Message
{
get => _message;
set
{
_message = value;
OnPropertyChanged();
}
}
public ImageSource? _image = null;
public ImageSource? Image
{
get => _image;
set
{
_image = value;
OnPropertyChanged();
}
}
private string _details = "";
public string Details
{
get => _details;
set
{
_details = value;
OnPropertyChanged();
}
}
public static readonly DependencyProperty ShowDetailsProperty = DependencyProperty.Register(nameof(ShowDetails), typeof(bool), typeof(MessageWindow));
public bool ShowDetails
{
get => (bool)GetValue(ShowDetailsProperty);
set => SetValue(ShowDetailsProperty, value);
}
public MessageWindowResult Result { get; set; } = MessageWindowResult.None;
public object? OtherResult { get; set; }
public MessageWindow()
{
InitializeComponent();
Buttons.CollectionChanged += Buttons_CollectionChanged;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (sender is not Button button || button.Tag is not MessageWindowButton winButton) return;
winButton.Action(this, winButton);
}
private void Buttons_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged(nameof(LeftButtons));
OnPropertyChanged(nameof(RightButtons));
}
public MessageWindow AddButton(MessageWindowButton button)
{
Buttons.Add(button);
return this;
}
public MessageWindow AddOKButton(string content = "OK")
{
Buttons.Add(new MessageWindowButton(content, OKButton_Click, MessageWindowButtonPosition.Right));
return this;
}
public MessageWindow AddCancelButton(string content = "Cancel")
{
Buttons.Add(new MessageWindowButton(content, CancelButton_Click, MessageWindowButtonPosition.Right));
return this;
}
public MessageWindow AddYesButton(string content = "Yes")
{
Buttons.Add(new MessageWindowButton(content, YesButton_Click, MessageWindowButtonPosition.Right));
return this;
}
public MessageWindow AddNoButton(string content = "No")
{
Buttons.Add(new MessageWindowButton(content, NoButton_Click, MessageWindowButtonPosition.Right));
return this;
}
private void YesButton_Click(MessageWindow window, MessageWindowButton button)
{
Result = MessageWindowResult.Yes;
Close();
}
private void NoButton_Click(MessageWindow window, MessageWindowButton button)
{
Result = MessageWindowResult.No;
Close();
}
private void CancelButton_Click(MessageWindow window, MessageWindowButton button)
{
Result = MessageWindowResult.Cancel;
Close();
}
private void OKButton_Click(MessageWindow window, MessageWindowButton button)
{
Result = MessageWindowResult.OK;
Close();
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#region Static Constructors
public static readonly BitmapImage _warning = InABox.Wpf.Resources.warning.AsBitmapImage();
public static BitmapImage WarningImage => _warning;
public static readonly BitmapImage _question = InABox.Wpf.Resources.help.AsBitmapImage();
public static BitmapImage QuestionImage => _question;
public static MessageWindow New()
{
return new MessageWindow();
}
public static MessageWindow NewMessage(string message, string title, ImageSource? image = null)
{
return new MessageWindow()
.Title(title)
.Message(message)
.Image(image)
.AddOKButton();
}
public static void ShowMessage(string message, string title, ImageSource? image = null)
{
NewMessage(message, title, image).Display();
}
public static MessageWindow NewOKCancel(string message, string title, ImageSource? image = null)
{
return new MessageWindow()
.Title(title)
.Message(message)
.Image(image)
.AddOKButton()
.AddCancelButton();
}
public static bool ShowOKCancel(string message, string title, ImageSource? image = null)
{
return NewOKCancel(message, title, image)
.Display()
.Result == MessageWindowResult.OK;
}
public static MessageWindow NewYesNo(string message, string title, ImageSource? image = null)
{
return new MessageWindow()
.Title(title)
.Message(message)
.Image(image)
.AddYesButton()
.AddNoButton();
}
public static bool ShowYesNo(string message, string title, ImageSource? image = null)
{
return NewYesNo(message, title, image)
.Display()
.Result == MessageWindowResult.Yes;
}
public static MessageWindow NewYesNoCancel(string message, string title, ImageSource? image = null)
{
return new MessageWindow()
.Title(title)
.Message(message)
.Image(image)
.AddYesButton()
.AddNoButton()
.AddCancelButton();
}
public static MessageWindowResult ShowYesNoCancel(string message, string title, ImageSource? image = null)
{
return NewYesNoCancel(message, title, image)
.Display().Result;
}
///
/// Display a message box for an exception, giving options to view the logs.
///
/// The message to display. Set to to default to the exception message.
///
///
/// If , also logs the exception.
public static MessageWindow NewError(string? message, Exception exception, string title = "Error", bool shouldLog = true, ImageSource? image = null)
{
if (shouldLog)
{
CoreUtils.LogException(ClientFactory.UserID, exception);
}
var window = new MessageWindow()
.Message(message ?? exception.Message)
.Title(title)
.Details(CoreUtils.FormatException(exception))
.Image(image ?? _warning)
.AddButton(new MessageWindowButton("Email Logs", (window, button) =>
{
EmailLogs_Click(exception);
}, MessageWindowButtonPosition.Left));
var showDetailsButton = new MessageWindowButton("Show Details", (win, button) =>
{
win.ShowDetails = !win.ShowDetails;
button.Content = win.ShowDetails
? "Hide Details"
: "Show Details";
}, MessageWindowButtonPosition.Left);
return window.AddButton(showDetailsButton)
.AddOKButton();
}
private static void EmailLogs_Click(Exception e)
{
var logFile = Path.Combine(CoreUtils.GetPath(), string.Format("{0:yyyy-MM-dd}.log", DateTime.Today));
const int nRead = 1024 * 1024;
byte[] data;
using (var stream = File.OpenRead(logFile))
{
if (stream.Length > nRead)
{
stream.Seek(-nRead, SeekOrigin.End);
}
data = new BinaryReader(stream).ReadBytes(Math.Min(nRead, (int)stream.Length));
}
var message = EmailUtils.CreateMessage(
subject: "Error logs",
to: "support@prsdigital.com.au",
body: $"Error logs for PRS:\n\nException: {CoreUtils.FormatException(e)}");
message.AddAttachment("Error Logs.txt", data);
EmailUtils.OpenEmail(message);
}
///
/// Display a message box for a non-exception error, giving options to view the logs.
///
/// The message to display. Set to to default to the exception message.
///
///
/// If , also logs the exception.
public static MessageWindow NewError(string message, string? details = null, string title = "Error", bool shouldLog = true, ImageSource? image = null)
{
if (shouldLog)
{
Logger.Send(LogType.Error, ClientFactory.UserID, details ?? message);
}
var window = new MessageWindow()
.Message(message)
.Title(title);
if(details is not null)
{
window.Details(details);
}
window.Image(image ?? _warning)
.AddButton(new MessageWindowButton(
"Email Logs",
(window, button) => EmailLogs_Click(new Exception(details ?? message)),
MessageWindowButtonPosition.Left));
if(details is not null)
{
var showDetailsButton = new MessageWindowButton("Show Details", (win, button) =>
{
win.ShowDetails = !win.ShowDetails;
button.Content = win.ShowDetails
? "Hide Details"
: "Show Details";
}, MessageWindowButtonPosition.Left);
window.AddButton(showDetailsButton);
}
return window.AddOKButton();
}
public static void ShowError(string? message, Exception exception, string title = "Error", bool shouldLog = true, ImageSource? image = null)
{
NewError(message, exception, title, shouldLog, image).Display();
}
public static void ShowError(string message, string details, string title = "Error", bool shouldLog = true, ImageSource? image = null)
{
NewError(message, details, title, shouldLog, image).Display();
}
private static void ShowLogs_Click(MessageWindow window, MessageWindowButton button)
{
var console = new MessageWindowConsole("Logs", Path.Combine(CoreUtils.GetPath(), string.Format("{0:yyyy-MM-dd}.log", DateTime.Today)));
console.ShowDialog();
}
#endregion
}
public static class MessageWindowBuilder
{
public static MessageWindow Title(this MessageWindow window, string title)
{
window.Title = title;
return window;
}
public static MessageWindow Message(this MessageWindow window, string message)
{
window.Message = message;
return window;
}
public static MessageWindow Image(this MessageWindow window, ImageSource? image)
{
window.Image = image;
return window;
}
public static MessageWindow Icon(this MessageWindow window, ImageSource image)
{
window.Icon = image;
return window;
}
public static MessageWindow Details(this MessageWindow window, string details)
{
window.Details = details;
return window;
}
public static MessageWindow Display(this MessageWindow window)
{
window.ShowDialog();
return window;
}
}
public class MessageWindowConsole : Console.Console
{
public string FileName { get; set; }
public MessageWindowConsole(string description, string file) : base(description)
{
FileName = file;
ConsoleControl.AllowLoadLogButton = false;
}
protected override void OnLoaded()
{
base.OnLoaded();
if (File.Exists(FileName))
{
var lines = File.ReadLines(FileName);
ConsoleControl.LoadLogEntries(lines);
}
}
protected override string GetLogDirectory()
{
return CoreUtils.GetPath();
}
}