using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using InABox.Clients;
using InABox.Core;
using InABox.Wpf;
using InABox.Wpf.Reports;
using InABox.WPF;
namespace InABox.DynamicGrid;
public class DynamicFormEditButton : INotifyPropertyChanged
{
public delegate void DynamicFormEditButtonDelegate(DynamicFormEditWindow window, DynamicFormEditButton button);
private object? _content;
public object? Content
{
get => _content;
set
{
_content = value;
OnPropertyChanged();
}
}
public DynamicFormEditButtonDelegate Action { get; set; }
public DynamicFormEditButton(object? content, DynamicFormEditButtonDelegate action)
{
Content = content;
Action = action;
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
///
/// Interaction logic for FormDesigner.xaml
///
public partial class DynamicFormEditWindow : Window, IDynamicFormWindow
{
public delegate void CustomiseDynamicFormEditWindow(DynamicFormEditWindow window);
public enum FormResult
{
None,
Cancel,
Save,
Complete
}
public DynamicFormEditWindow()
{
InitializeComponent();
Grid.OnChanged += Grid_OnChanged;
//Complete.IsEnabled = Security.IsAllowed();
}
public DynamicFormDesignGrid Grid => Preview;
public FormMode Mode
{
get => Grid.Mode;
private set => Grid.Mode = value;
}
public FormResult Result = FormResult.None;
public IDigitalFormDataModel? DataModel
{
get => Grid.DataModel;
set
{
Grid.DataModel = value;
RefreshEnabled();
}
}
public ObservableCollection CustomButtons { get; set; } = new ObservableCollection();
private bool IsReopening = false;
private bool HasChanged = false;
private bool HasUnsavedChanges => Grid.IsChanged || HasChanged || DataModel!.Instance.ID == Guid.Empty;
private DFLayoutType _type;
public DFLayoutType Type
{
get => _type;
set
{
_type = value;
Width = _type == DFLayoutType.Mobile ? 600 : 1000;
Height = 800;
}
}
public DFSaveStorage SaveValues() => Grid.SaveValues();
public void LoadValues(DFLoadStorage storage)
{
Grid.LoadValues(storage);
RefreshEnabled();
}
private void RefreshEnabled()
{
var formInstance = DataModel!.Instance;
var completed = formInstance.FormCompleted;
CompletedDate.Content = !completed.IsEmpty() ? $"Completed {completed:d MMM yyyy} at {completed:hh:mm tt}" : "Not completed yet";
if (completed.IsEmpty()
&& DFUtils.CanEditForm(formInstance.GetType(), formInstance, DataModel.Entity))
{
Mode = FormMode.Filling;
}
else
{
Mode = Security.IsAllowed()
? FormMode.Editing
: FormMode.ReadOnly;
}
if (Mode == FormMode.Editing || Mode == FormMode.Filling || Mode == FormMode.Preview)
{
SaveForm.IsEnabled = HasUnsavedChanges;
if(Mode == FormMode.Editing)
{
SaveForm.Content = "Save Form";
}
else
{
SaveForm.Content = "Save Progress";
}
}
else
{
if (Security.IsAllowed())
{
SaveForm.IsEnabled = HasUnsavedChanges;
SaveForm.Content = "Save Form";
}
else
{
SaveForm.IsEnabled = false;
SaveForm.Content = "Save Progress";
}
}
if (!completed.IsEmpty() && Security.IsAllowed())
{
CompleteForm.Content = "Re-open form";
CompleteForm.IsEnabled = true;
IsReopening = true;
}
else
{
CompleteForm.Content = "Complete form";
CompleteForm.IsEnabled = (Mode == FormMode.Filling || Security.IsAllowed()) && DataModel?.Instance.FormCompleted == DateTime.MinValue;
IsReopening = false;
}
}
private void Grid_OnChanged(DynamicFormDesignGrid sender, string fieldName)
{
if (Mode == FormMode.Editing || Mode == FormMode.Filling || Mode == FormMode.Preview)
{
SaveForm.IsEnabled = true;
}
}
protected override void OnClosing(CancelEventArgs e)
{
if (DialogResult == null)
{
Result = FormResult.Cancel;
DialogResult = false;
}
base.OnClosing(e);
}
private void Complete()
{
if (!Grid.Validate(out var messages))
{
MessageBox.Show(string.Join('\n', messages));
return;
}
if (MessageBox.Show("Are you sure you want to complete this form?", "Confirm Completion", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
Result = FormResult.Complete;
DialogResult = true;
}
}
private void Reopen()
{
HasChanged = true;
DataModel!.Instance.FormCompleted = DateTime.MinValue;
DataModel!.Instance.FormCompletedBy.Clear();
RefreshEnabled();
}
private void CompleteForm_Click(object sender, RoutedEventArgs e)
{
if (IsReopening)
Reopen();
else
Complete();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (sender is not Button btn || btn.Tag is not DynamicFormEditButton button) return;
button.Action(this, button);
}
private DataModel? GetReportDataModel()
{
var dataModel = DataModel;
if (dataModel is null) return null;
var formType = dataModel.Instance.GetType();
var filter = Filter.Create(formType, x => x.ID).IsEqualTo(dataModel.Instance.ID);
return (Activator.CreateInstance(typeof(DigitalFormReportDataModel<>)!
.MakeGenericType(formType), new object?[] { filter, dataModel.Instance.Form.ID }) as DataModel)!;
}
private void PrintForm_Click(object sender, RoutedEventArgs e)
{
var model = GetReportDataModel();
var dataModel = DataModel;
if (model is null || dataModel is null) return;
(model as IDigitalFormReportDataModel)!.AddFormData(dataModel.Instance.ID, SaveValues().ToLoadStorage());
var menu = new ContextMenu();
ReportUtils.PopulateMenu(menu, dataModel.Instance.Form.ID.ToString(), model, false);
if(menu.Items.Count == 0)
{
menu.AddItem("No reports", null, null, enabled: false);
}
menu.IsOpen = true;
}
private void SaveForm_Click(object sender, RoutedEventArgs e)
{
if (DataModel?.Instance.FormCompleted.IsEmpty() == false && !Grid.Validate(out var messages))
{
MessageBox.Show(string.Join('\n', messages));
return;
}
if (MessageBox.Show("Are you sure you want to save this form?", "Confirm Save", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
Result = FormResult.Save;
DialogResult = true;
}
}
public static Columns FormColumns() where TForm : IDigitalFormInstance
{
return (FormColumns(typeof(TForm)) as Columns)!;
}
public static IColumns FormColumns(Type TForm)
{
return Columns.Create(TForm, ColumnTypeFlags.None)
.Add(x => x.ID)
.Add(x=>x.Number)
.Add(x=>x.Description)
.Add(x => x.FormCompleted)
.Add(x => x.FormData)
.Add(x => x.BlobData)
.Add(x => x.Form.ID)
.Add(x => x.Form.Description)
.Add(x => x.Form.DescriptionExpression)
.Add("Parent.ID");
}
public static bool EditDigitalForm(
IDigitalFormInstance formInstance,
[NotNullWhen(true)] out IDigitalFormDataModel? dataModel,
Entity? parent = null,
CustomiseDynamicFormEditWindow? customise = null)
{
dataModel = null;
DigitalFormLayout layout = null;
DigitalFormVariable[] variables = null;
DFLoadStorage? values = null;
String error = "";
Progress.ShowModal("Loading Form", (progress) =>
{
var formid = formInstance.Form.ID;
values = DigitalForm.DeserializeFormData(formInstance);
var results = Client.QueryMultiple(
new KeyedQueryDef(new Filter(x => x.Form.ID).IsEqualTo(formid)),
new KeyedQueryDef(
new Filter(x => x.Form.ID).IsEqualTo(formid)
.And(x => x.Active).IsEqualTo(true)
.And(x => x.Layout).IsNotEqualTo("")));
variables = results[nameof(DigitalFormVariable)].Rows.Select(x => x.ToObject()).ToArray();
var desktopLayout = results[nameof(DigitalFormLayout)]
.Rows.FirstOrDefault(x => x.Get(x => x.Type) == DFLayoutType.Desktop)
?.ToObject();
layout = desktopLayout ?? results[nameof(DigitalFormLayout)].ToObjects().FirstOrDefault();
if (layout != null)
{
if (parent is null)
{
var parentlink = CoreUtils.HasProperty(formInstance.GetType(), "Parent")
? CoreUtils.GetPropertyValue(formInstance, "Parent") as IEntityLink
: null;
var parenttype = parentlink?.GetType().BaseType?.GetGenericArguments().FirstOrDefault();
if (parenttype != null && parentlink != null)
{
var parentid = parentlink.ID;
var filter = Filter.Create(parenttype);
filter.Expression = CoreUtils.GetMemberExpression(parenttype, "ID");
filter.Operator = Operator.IsEqualTo;
filter.Value = parentid;
var client = (Activator.CreateInstance(typeof(Client<>).MakeGenericType(parenttype)) as Client)!;
parent = client.Query(filter, null, null).Rows.FirstOrDefault()?.ToObject(parenttype) as Entity;
}
if (parent == null)
{
Logger.Send(LogType.Error, "",
$"Form parent is null; Form Type: {formInstance.GetType()}; Parent Type: {parenttype}; Form ID: {formInstance.ID}");
error = "An error occurred while loading the form: Form Entity is null";
}
}
}
else
error = "No layout found for form!";
});
if (!String.IsNullOrWhiteSpace(error))
{
MessageBox.Show(error);
return false;
}
var form = new DynamicFormEditWindow
{
Type = layout.Type,
Title = string.Format("Viewing {0}", formInstance.Form.Description)
};
form.LoadLayout(layout, variables);
try
{
dataModel = formInstance.CreateDataModel(parent!);
dataModel.Variables = variables;
dataModel.OnModelSaved += (model) =>
{
DFUtils.OnSave(formInstance.GetType(), formInstance, parent!);
};
form.DataModel = dataModel;
}
catch (Exception e)
{
Logger.Send(LogType.Error, ClientFactory.UserID, $"Error during Edit Form / CreateDataModel: {CoreUtils.FormatException(e)}");
}
form.Initialize();
if (values is not null)
form.LoadValues(values);
customise?.Invoke(form);
if (form.ShowDialog() == true)
{
if (form.Result == FormResult.Complete)
{
formInstance.FormCompleted = DateTime.Now;
formInstance.FormCompletedBy.ID = ClientFactory.UserGuid;
formInstance.FormCompletedBy.UserID = ClientFactory.UserID;
/*formInstance.FormCompleted = form.Completed
? formInstance.FormCompleted.IsEmpty()
? DateTime.Now
: formInstance.FormCompleted
: DateTime.MinValue;
formInstance.FormCompletedBy.ID = form.Completed
? !formInstance.FormCompletedBy.IsValid()
? ClientFactory.UserGuid
: formInstance.FormCompletedBy.ID
: Guid.Empty;
formInstance.FormCompletedBy.UserID = form.Completed
? string.IsNullOrWhiteSpace(formInstance.FormCompletedBy.UserID)
? ClientFactory.UserID
: formInstance.FormCompletedBy.UserID
: "";*/
}
DigitalForm.SerializeFormData(formInstance, variables, form.SaveValues());
}
return form.Result == FormResult.Save || form.Result == FormResult.Complete;
}
public static bool EditDigitalForm(Guid formID, [NotNullWhen(true)] out IDigitalFormDataModel? dataModel)
where TForm : Entity, IDigitalFormInstance, IRemotable, IPersistent, new()
{
var form = (new Client()
.Query(
new Filter(x => x.ID).IsEqualTo(formID),
FormColumns())
.Rows.FirstOrDefault()?.ToObject())
?? throw new Exception($"{typeof(TForm)} {formID} does not exist");
return EditDigitalForm(form, out dataModel);
}
private void DynamicFormWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (DialogResult != true && HasUnsavedChanges)
{
if (MessageBox.Show("This form has unsaved changes. Do you wish to discard them?", "Discard Changes?", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
{
e.Cancel = true;
}
}
}
}