using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using InABox.Clients; namespace InABox.Core { public class DigitalFormDataModel : IDigitalFormDataModel where TEntity : Entity, IRemotable, IPersistent, new() where TEntityLink : EntityLink where TInstance : Entity, IRemotable, IPersistent, IDigitalFormInstance, new() { private readonly bool bRequiresLoad = true; public DigitalFormDataModel(Guid entityid, Guid instanceid) { Entity = new TEntity(); Entity.ID = entityid; Entity.CommitChanges(); Instance = new TInstance(); Instance.ID = instanceid; Variables = new DigitalFormVariable[] { }; bRequiresLoad = true; } public DigitalFormDataModel(TEntity entity, TInstance instance) { Entity = entity; Instance = instance; Variables = new DigitalFormVariable[] { }; bRequiresLoad = false; } public Entity Entity { get; set; } public object? GetEntityValue(string name) { try { return CoreUtils.GetPropertyValue(Entity, name); } catch { return null; } } public void SetEntityValue(string name, object? value) { try { CoreUtils.SetPropertyValue(Entity, name, value); } catch (Exception e) { Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace)); } } IDigitalFormInstance IDigitalFormDataModel.Instance { get => Instance; set { Instance = (TInstance)value; } } public TInstance Instance { get; set; } public DigitalFormVariable[] Variables { get; set; } public event DigitalFormUpdateHandler OnModelSaved; public event DigitalFormBeforeUpdateHandler BeforeModelSaved; public void Load(Action? callback = null) { if (!bRequiresLoad) { callback?.Invoke(this); return; } var client = new MultiQuery(); DoAddQueries(client); if (callback == null) { if (client.Count > 0) { client.Query(); DoParseQueries(client); } } else { if (client.Count > 0) client.Query(c => { DoParseQueries(client); callback.Invoke(this); }); else callback.Invoke(this); } } public void Update(Action? callback = null) { //this never get used and causes a crash in the app for Job ITP forms - maybe time for a rebuild? //if (!bRequiresLoad) //{ // callback.Invoke(this); // return; //} if (callback == null) DoUpdate(); else Task.Run(() => { DoUpdate(); callback.Invoke(this); }); } public virtual void AddQueries(MultiQuery client) { } private void DoAddQueries(MultiQuery client) { if (Entity.ID != Guid.Empty) client.Add( new QueryDef( new Filter(x => x.ID).IsEqualTo(Entity.ID), Columns.None().Add(x => x.ID), null ), typeof(TEntity) ); if (Instance.ID != Guid.Empty) client.Add( new QueryDef( new Filter(x => x.ID).IsEqualTo(Instance.ID), Columns.None().Add ( x => x.ID, x => x.Number, x => x.FormData, x => x.Form.ID, x => x.Form.Description, x => x.Form.DescriptionExpression, x => x.FormCompleted, x => x.FormCompletedBy.ID, x => x.Created, x => x.FormOpen, x => x.BlobData ), null ), typeof(TInstance) ); AddQueries(client); } public virtual void ParseQueries(MultiQuery client) { } private void DoParseQueries(MultiQuery client) { if (client.Contains(typeof(TEntity))) { var table = client.Get(typeof(TEntity)); if (table.Rows.Any()) Entity = table.Rows.First().ToObject(); } if (client.Contains(typeof(TInstance))) { var table = client.Get(typeof(TInstance)); if (table.Rows.Any()) Instance = table.Rows.First().ToObject(); } ParseQueries(client); } protected virtual void AddPrimaryUpdates(MultiSave client) { } protected virtual void AddSecondaryUpdates(MultiSave client) { } public void DuplicateInstance() { var formid = Instance.Form.ID; Instance = new TInstance(); Instance.Parent.ID = Entity.ID; Instance.Form.ID = formid; } public string? EvaluateExpression(string expression) { if (string.IsNullOrWhiteSpace(expression)) return null; Dictionary variables = new Dictionary(); var formData = DigitalForm.DeserializeFormData(Instance); if(formData != null) { foreach (var item in formData.Items()) variables[$"Data.{item.Key}"] = item.Value; } foreach (var property in DatabaseSchema.Properties(Instance.GetType()).Where(x => !x.Name.StartsWith("Parent."))) variables[$"Form.{property.Name}"] = property.Getter()(Instance); foreach (var property in DatabaseSchema.Properties(Entity.GetType())) variables[$"{typeof(TEntity).Name}.{property.Name}"] = property.Getter()(Entity); var exp = new CoreExpression(expression); return exp.Evaluate(variables)?.ToString(); } private void DoUpdate() { var result = EvaluateExpression(Instance.Form.DescriptionExpression); Instance.Description = !String.IsNullOrWhiteSpace(result) ? result : Instance.Form.Description; BeforeModelSaved?.Invoke(this); var entityaudittrail = ""; var instanceaudittrail = ""; var parents = new MultiSave(); if (Entity.IsChanged()) { parents.Add(typeof(TEntity), Entity); entityaudittrail = "Updated from App - Digital Forms Module"; } else if (Entity.ID == Guid.Empty) { parents.Add(typeof(TEntity), Entity); entityaudittrail = "Created from App - Digital Forms Module"; } AddPrimaryUpdates(parents); parents.Save(null, entityaudittrail); ((IDigitalFormInstance)Instance).Parent.ID = Entity.ID; //be careful of bug here in future due to cast var children = new MultiSave(); if (Instance.IsChanged()) { children.Add(typeof(TInstance), (TInstance)Instance); instanceaudittrail = "Updated from App - Digital Forms Module"; } else if (Entity.ID == Guid.Empty) { children.Add(typeof(TInstance), (TInstance)Instance); instanceaudittrail = "Created from App - Digital Forms Module"; } AddSecondaryUpdates(children); children.Save(null, instanceaudittrail); OnModelSaved?.Invoke(this); } } }