using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using InABox.Clients; using InABox.Core; using InABox.Mobile; using Xamarin.Forms; namespace comal.timesheets { public abstract class Model : BindableObject, IModel where TParent : Model, IModel where TEntity : Entity, IRemotable, IPersistent, new() where TItem : Shell, new() { public Model(IModelHost host, Func> filter, bool transient = false) { Reset(); new TItem(); Host = host; Filter = filter; Type = transient ? ModelType.Transient : ModelType.Normal; } public Model(IModelHost host, Func> filter, [NotNull] String filename) { Reset(); new TItem(); Host = host; Type = ModelType.Persistent; Filter = filter; FileName = filename; } #region INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; protected void DoPropertyChanged(object sender, PropertyChangedEventArgs args) { PropertyChanged?.Invoke(sender, args); } protected bool SetProperty(ref T field, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) return false; field = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); return true; } #endregion public bool Loaded { get; protected set; } public abstract void BeforeLoad(MultiQuery query); public abstract void AfterLoad(MultiQuery query); public abstract void Load(Action loaded = null); public abstract void Refresh(bool force, Action loaded = null); protected abstract void Initialize(); public void Reset() { Loaded = false; Images.Clear(); Initialize(); } protected Func> Filter { get; set; } // Use "new" to replace this with your actual columns public Columns Columns { get { var prop = typeof(TItem).GetProperty("Columns", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); var cols = prop?.GetValue(null) as IShellColumns; return cols?.Columns; } } public IColumns GetColumns() => Columns; public Dictionary Images { get; private set; } = new Dictionary(); public ImageSource GetImage(Guid id) { ImageSource result = null; if (Images.TryGetValue(id, out byte[] data)) result = ImageSource.FromStream(() => new MemoryStream(data)); return result; } public bool HasImages() => Images.Any(); public IModelHost Host { get; private set; } public ModelType Type { get; private set; } public String FileName { get; private set; } protected void InitializeTables(MultiQuery query) { var defs = query.Definitions(); foreach (var def in defs) { var table = InitializeTable(def.Value); query.Set(def.Key, table); } } protected CoreTable InitializeTable(IQueryDef def) { var table = new CoreTable(); if (def.Columns != null) table.LoadColumns(def.Columns); else table.LoadColumns(def.Type); return table; } protected class QueryStorage : ISerializeBinary { private Dictionary _data = new Dictionary(); public CoreTable Get([NotNull] String key) => _data[key]; public void Set([NotNull] String key, CoreTable table) => _data[key] = table; public bool Contains([NotNull] String key) => _data.ContainsKey(key); public void SerializeBinary(CoreBinaryWriter writer) { writer.Write(_data.Count); foreach (var key in _data.Keys) { writer.Write(key); _data[key].SerializeBinary(writer); } } public void DeserializeBinary(CoreBinaryReader reader) { int count = reader.ReadInt32(); for (int i = 0; i < count; i++) { String key = reader.ReadString(); CoreTable table = new CoreTable(); table.DeserializeBinary(reader); _data[key] = table; } } } protected void LoadFromStorage(MultiQuery query) { QueryStorage storage = new QueryStorage(); var file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), FileName); if (File.Exists(file)) { using (var stream = new FileStream(file, FileMode.Open)) storage = Serialization.ReadBinary(stream, BinarySerializationSettings.Latest); var defs = query.Definitions(); foreach (var key in defs.Keys) { var table = storage.Contains(key.ToString()) ? storage.Get(key.ToString()) : InitializeTable(defs[key]); query.Set(key, table); } } else InitializeTables(query); } protected void SaveToStorage(MultiQuery query) { QueryStorage storage = new QueryStorage(); var results = query.Results(); foreach (var key in results.Keys) storage.Set(key.ToString(),results[key]); var data = storage.WriteBinary(BinarySerializationSettings.Latest); try { var file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), FileName); File.WriteAllBytes(file,data); } catch (Exception e) { MobileLogging.Log(e); } } } }