using System; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Threading; using InABox.Clients; using InABox.Core; using System.Diagnostics.CodeAnalysis; namespace comal.timesheets { public abstract class DetailModel : Model, IDetailModel where TParent : DetailModel, IModel where TEntity : Entity, IRemotable, IPersistent, new() where TItem : DetailShell, new() { protected DetailModel(IModelHost host, Func> filter, bool transient = false) : base(host, filter, transient) { } protected DetailModel(IModelHost host, Func> filter, [NotNull] String filename) : base(host, filter, filename) { } protected override void Initialize() { Filter = null; Item = null; } private TItem _item; public TItem Item { get => _item; set => SetProperty(ref _item, value); } protected virtual Expression> ImageColumn { get; } private void DoBeforeLoad(MultiQuery query) { if (ImageColumn != null) query.Add( new Filter(x => x.ID).InQuery(Filter(),ImageColumn), new Columns(x=>x.ID).Add(x=>x.Data) ); BeforeLoad(query); } public override void BeforeLoad(MultiQuery query) { } private void DoAfterLoad(MultiQuery query, Action loaded = null) { if (ImageColumn != null) { Images.Clear(); query.Get().IntoDictionary(Images, x => x.ID, r => r.Get(x => x.Data)); } AfterLoad(query); Loaded = true; loaded?.Invoke(); } public override void AfterLoad(MultiQuery query) { } private TItem CreateItemFromEntity(TEntity entity) { CoreTable table = new CoreTable(); table.LoadColumns(Columns); CoreRow row = table.NewRow(); if (entity != null) table.LoadRow(row, entity); var item = new TItem() { Row = row, Parent = this as TParent }; item.PropertyChanged += DoPropertyChanged; return item; } private TItem CreateItemFromRow(CoreRow row) { var item = (row != null) ? new TItem() { Row = row, Parent = this as TParent } : CreateItemFromEntity(null); item.PropertyChanged += DoPropertyChanged; return item; } public void Load(TEntity entity, Action loaded = null) { Filter = () => new Filter(x => x.ID).IsEqualTo(entity.ID); MultiQuery query = new MultiQuery(); DoBeforeLoad(query); Item = CreateItemFromEntity(entity); if (loaded != null) query.Query((q) => DoAfterLoad(q, loaded)); else { query.Query(); DoAfterLoad(query); } } public override void Load(Action loaded = null) { MultiQuery query = new MultiQuery(); query.Add( Filter(), Columns ); DoBeforeLoad(query); if (Host.IsConnected()) { if (loaded != null) query.Query((q) => { if (Type == ModelType.Persistent) SaveToStorage(query); Item = CreateItemFromRow(q.Get().Rows.FirstOrDefault()); DoAfterLoad(q, loaded); }); else { query.Query(); if (Type == ModelType.Persistent) SaveToStorage(query); Item = CreateItemFromRow(query.Get().Rows.FirstOrDefault()); DoAfterLoad(query); } } else { if (Type == ModelType.Transient) { InitializeTables(query); } else if (Type == ModelType.Normal) { // Only load if (_item == null) InitializeTables(query); } else if (Type == ModelType.Persistent) { // Treat it as normal, unless its the first time through // in which case try to load it from storage, if the // data has been previously cached if (_item == null) LoadFromStorage(query); } Item = CreateItemFromRow(query.Get().Rows.FirstOrDefault()); DoAfterLoad(query, loaded); } } protected virtual void BeforeSave(TItem item) { } protected virtual void AfterSave(TItem item) { } public void Save(String auditmessage) { BeforeSave(Item); new Client().Save(Item.Entity,auditmessage); AfterSave(Item); } public override void Refresh(bool force, Action loaded = null) { if (!Loaded || force) Load(loaded); else loaded?.Invoke(); } } }