| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051 | using System;using System.Collections;using System.Collections.Generic;using System.Data;using System.Drawing;using System.IO;using System.Linq;using System.Linq.Expressions;using System.Reflection;using Newtonsoft.Json;using Newtonsoft.Json.Linq;namespace InABox.Core{    // Equivalent to DataColumn    [Serializable]    public class CoreColumn    {        public CoreColumn()        {            DataType = typeof(object);        }        public CoreColumn(string columnName) : this(typeof(object), columnName) { }        public CoreColumn(Type dataType, string columnName)        {            DataType = dataType;            ColumnName = columnName;        }        public Type DataType { get; set; }        public string ColumnName { get; set; }        public override string ToString()        {            return string.Format("{0} ({1})", ColumnName, DataType.EntityName().Split('.').Last());        }    }    [Serializable]    public class CoreRow : ICoreRow    {        #region Fields        [NonSerialized]        private static Dictionary<int, string> _accessedcolumns = new Dictionary<int, string>();        [NonSerialized]        private Dictionary<string, int> _columnindexes = new Dictionary<string, int>();        #endregion        #region Properties        [DoNotSerialize]        [field: NonSerialized]        public CoreTable Table { get; private set; }        public List<object?> Values { get; private set; }        [DoNotSerialize]        public int Index => Table.Rows.IndexOf(this);        #endregion        protected internal CoreRow(CoreTable owner)        {            Table = owner;            Values = new List<object?>();        }        public static CoreRow[] None        {            get { return new CoreRow[] { }; }        }        //private DynamicObject rowObject;        public Dictionary<string, object?> ToDictionary(string[] exclude)        {            var result = new Dictionary<string, object?>();            foreach (var column in Table.Columns.Where(x => !exclude.Contains(x.ColumnName)))                result[column.ColumnName] = this[column.ColumnName];            return result;        }        [DoNotSerialize]        public object? this[string columnName]        {            get =>                //return this.RowObject.GetValue<object>(columnName);                Get<object>(columnName);            set =>                //this.RowObject.SetValue(columnName, value);                Set(columnName, value);        }        public BaseObject ToObject(Type t)        {            var entity = (Activator.CreateInstance(t) as BaseObject)!;            entity.SetObserving(false);            if (!Table.Setters.TryGetValue("", out var setters))            {                setters = new List<Action<object, object>?>();                Table.Setters[""] = setters;            }                        var bFirst = !setters.Any();            for (var i = 0; i < Table.Columns.Count; i++)            {                var column = Table.Columns[i].ColumnName;                var value = this[column];                try                {                    if (bFirst)                    {                        var prop = DatabaseSchema.Property(t, column);                        setters.Add(prop?.Setter());                    }                    var setter = setters[i];                    if (setter != null && value != null)                        setter.Invoke(entity, value);                    else                        CoreUtils.SetPropertyValue(entity, column, value);                }                catch (Exception e)                {                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));                }            }            entity.CommitChanges();            entity.SetObserving(true);            return entity;        }        public T ToObject<T>() where T : BaseObject, new()        {            return (ToObject(typeof(T)) as T)!;        }        public T Get<T>(int col, bool usedefault = true)        {            if (col < 0 || col >= Values.Count)            {                if (usedefault)                    return CoreUtils.GetDefault<T>();                throw new Exception(string.Format("Column [{0}] does not exist!", col));            }            return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault<T>();        }                public T Get<T>(string columnname, bool usedefault = true)        {            var col = GetColumn(columnname);            if (col < 0 || col >= Values.Count)            {                if (usedefault)                    return CoreUtils.GetDefault<T>();                throw new Exception(string.Format("Column [{0}] does not exist!", columnname));            }            return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault<T>();        }        public TType Get<TSource, TType>(Expression<Func<TSource, TType>> expression, bool usedefault = true)        {            var colname = GetColName(expression);            //String colname = CoreUtils.GetFullPropertyName(expression, ".");            return Get<TType>(colname, usedefault);        }        public void Set<TSource, TType>(Expression<Func<TSource, TType>> expression, TType value)        {            var colname = GetColName(expression);            //String colname = CoreUtils.GetFullPropertyName(expression, ".");            Set(colname, value);        }        public void Set<T>(int col, T value)        {            while (Values.Count <= col)                Values.Add(Table.Columns[Values.Count].DataType.GetDefault());            Values[col] = value;        }                public void Set<T>(string columnname, T value)        {            var col = GetColumn(columnname);            if (col < 0)                throw new Exception("Column not found: " + columnname);            while (Values.Count <= col)                Values.Add(Table.Columns[Values.Count].DataType.GetDefault());            Values[col] = value;            //this.RowObject.SetValue(columnname, value);        }        public void LoadValues(IEnumerable<object?> values)        {            Values = values.ToList();        }        public T ToObject<TSource, TLink, T>(Expression<Func<TSource, TLink>> property)            where TLink : IEntityLink<T>            where T : BaseObject, new()        {            var entity = new T();            entity.SetObserving(false);            var prefix = CoreUtils.GetFullPropertyName(property, ".");            if (!Table.Setters.TryGetValue(prefix, out var setters))            {                setters = new List<Action<object, object>?>();                Table.Setters[prefix] = setters;            }            var bFirst = !setters.Any();            var cols = Table.Columns.Where(x => x.ColumnName.StartsWith(prefix + ".")).ToArray();            for (var i = 0; i < cols.Length; i++)            {                var column = cols[i].ColumnName;                var prop = column.Substring((prefix + ".").Length);                var value = this[column];                try                {                    if (bFirst)                    {                        var p2 = DatabaseSchema.Property(typeof(T), prop);                        setters.Add(p2?.Setter());                    }                    var setter = setters[i];                    if (setter != null && value != null)                        setter.Invoke(entity, value);                    else                        CoreUtils.SetPropertyValue(entity, prop, value);                }                catch (Exception e)                {                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));                }            }            entity.CommitChanges();            entity.SetObserving(true);            return entity;        }        private string GetColName<TSource, TType>(Expression<Func<TSource, TType>> expression)        {            //int hash = expression.GetHashCode();            //if (_accessedcolumns.ContainsKey(hash))            //    return _accessedcolumns[hash];            var colname = CoreUtils.GetFullPropertyName(expression, ".");            //_accessedcolumns[hash] = colname;            return colname;        }        private int GetColumn(string columnname)        {            if (_columnindexes.ContainsKey(columnname))                return _columnindexes[columnname];            for (var i = 0; i < Table.Columns.Count; i++)                if (Table.Columns[i].ColumnName.Equals(columnname))                {                    _columnindexes[columnname] = i;                    return i;                }            _columnindexes[columnname] = -1;            return -1;        }    }    public class CoreFieldMap<T1, T2>    {        private List<CoreFieldMapPair<T1, T2>> _fields = new List<CoreFieldMapPair<T1, T2>>();        public CoreFieldMapPair<T1, T2>[] Fields => _fields.ToArray();                public CoreFieldMap<T1, T2> Add(Expression<Func<T1, object>> from, Expression<Func<T2, object>> to)        {            _fields.Add(new CoreFieldMapPair<T1, T2>(from, to));            return this;        }    }        public class CoreFieldMapPair<T1, T2>    {                    public Expression<Func<T1, object>> From { get; private set; }        public Expression<Func<T2, object>> To { get; private set; }                    public CoreFieldMapPair(Expression<Func<T1, object>> from, Expression<Func<T2, object>> to)        {            From = from;            To = to;        }    }    [Serializable]    public class CoreTable : ICoreTable, ISerializeBinary //: IEnumerable, INotifyCollectionChanged    {        #region Fields        private List<CoreRow>? rows;        private List<CoreColumn> columns = new List<CoreColumn>();        private string tableName;        #endregion        #region Properties        public string TableName { get => tableName; }        public IList<CoreColumn> Columns { get => columns; }        public IList<CoreRow> Rows        {            get            {                rows ??= new List<CoreRow>();                //this.rows.CollectionChanged += OnRowsCollectionChanged;                return rows;            }        }        [field: NonSerialized]        public Dictionary<string, IList<Action<object, object>?>> Setters { get; } = new Dictionary<string, IList<Action<object, object>?>>();        #endregion        public CoreTable() : this("")        {        }        public CoreTable(string tableName): base()        {            this.tableName = tableName;        }        public CoreTable(Type type) : this()        {            LoadColumns(type);        }                public void AddColumn<T>(Expression<Func<T, object>> column)        {            Columns.Add(                new CoreColumn()                {                    ColumnName = CoreUtils.GetFullPropertyName(column, "."),                    DataType = column.ReturnType                }            );        }                public CoreRow NewRow(bool populate = false)        {            var result = new CoreRow(this);            if (populate)                foreach (var column in Columns)                    result[column.ColumnName] = column.DataType.GetDefault();            return result;        }        /*        private void OnRowsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)        {            switch (e.Action)            {                case NotifyCollectionChangedAction.Add:                    this.InternalView.Insert(e.NewStartingIndex, ((DataRow)e.NewItems[0]).RowObject);                    break;                case NotifyCollectionChangedAction.Remove:                    this.InternalView.RemoveAt(e.OldStartingIndex);                    break;                case NotifyCollectionChangedAction.Replace:                    this.InternalView.Remove(((DataRow)e.OldItems[0]).RowObject);                    this.InternalView.Insert(e.NewStartingIndex, ((DataRow)e.NewItems[0]).RowObject);                    break;                case NotifyCollectionChangedAction.Reset:                default:                    this.InternalView.Clear();                    this.Rows.Select(r => r.RowObject).ToList().ForEach(o => this.InternalView.Add(o));                    break;            }        }                private IList InternalView        {            get            {                if (this.internalView == null)                {                    this.CreateInternalView();                }                return this.internalView;            }        }        private void CreateInternalView()        {            this.internalView = (IList)Activator.CreateInstance(typeof(ObservableCollection<>).MakeGenericType(this.ElementType));            ((INotifyCollectionChanged)internalView).CollectionChanged += (s, e) => { this.OnCollectionChanged(e); };        }        internal Type ElementType        {            get            {                if (this.elementType == null)                {                    this.InitializeElementType();                }                return this.elementType;            }        }        private void InitializeElementType()        {            this.Seal();            this.elementType = DynamicObjectBuilder.GetDynamicObjectBuilderType(this.Columns);        }        private void Seal()        {            this.columns = new ReadOnlyCollection<DataColumn>(this.Columns);        }        public IEnumerator GetEnumerator()        {            return this.InternalView.GetEnumerator();        }        public IList ToList()        {            return this.InternalView;        }        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)        {            var handler = this.CollectionChanged;            if (handler != null)            {                handler(this, e);            }        }        */        public void LoadColumns(Type T)        {            var iprops = DatabaseSchema.Properties(T);            foreach (var iprop in iprops)                Columns.Add(new CoreColumn { ColumnName = iprop.Name, DataType = iprop.PropertyType });        }                public void LoadColumns(IColumns columns)        {            foreach (var col in columns.GetColumns())                Columns.Add(new CoreColumn { ColumnName = col.Property, DataType = col.Type });        }                public void LoadColumns(IEnumerable<CoreColumn> columns)        {            Columns.Clear();            foreach (var col in columns)                Columns.Add(new CoreColumn() { ColumnName = col.ColumnName, DataType = col.DataType });         }        public void LoadRows(IEnumerable<object> objects)        {            foreach (var obj in objects)            {                var row = NewRow();                LoadRow(row, obj);                Rows.Add(row);            }        }        public void LoadRows(CoreRow[] rows)        {            foreach (var row in rows)            {                var newrow = NewRow();                LoadRow(newrow, row);                Rows.Add(newrow);            }        }        public void LoadFrom<T1, T2>(CoreTable table, CoreFieldMap<T1, T2> mappings, Action<CoreRow>? customization = null)        {            foreach (var row in table.Rows)            {                var newrow = NewRow();                foreach (var map in mappings.Fields)                    newrow.Set(map.To, row.Get(map.From));                customization?.Invoke(newrow);                Rows.Add(newrow);            }        }        public void LoadRow(CoreRow row, object obj)        {            foreach (var col in Columns)                try                {                    //var prop = DataModel.Property(obj.GetType(), col.ColumnName);                    //if (prop is CustomProperty)                    //    prop is CustomProperty ? item.UserProperties[key] : CoreUtils.GetPropertyValue(item, key);                    var fieldvalue = CoreUtils.GetPropertyValue(obj, col.ColumnName);                    row[col.ColumnName] = fieldvalue;                }                catch (Exception e)                {                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));                }        }        public void LoadRow(CoreRow row, CoreRow from)        {            foreach (var col in Columns)                try                {                    if (from.Table.Columns.Any(x => x.ColumnName.Equals(col.ColumnName)))                        row[col.ColumnName] = from[col.ColumnName];                }                catch (Exception e)                {                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));                }        }        public void Filter(Func<CoreRow, bool> predicate)        {            for (var i = Rows.Count - 1; i > -1; i--)            {                var row = Rows[i];                var predresult = predicate.Invoke(row);                if (!predresult)                    Rows.Remove(row);            }        }        public IDictionary ToDictionary(string keycol, string displaycol, string sortcol = "")        {            var kc = Columns.FirstOrDefault(x => x.ColumnName.Equals(keycol));            var dc = Columns.FirstOrDefault(x => x.ColumnName.Equals(displaycol));            var dt = typeof(Dictionary<,>).MakeGenericType(kc.DataType, dc.DataType);            var id = (Activator.CreateInstance(dt) as IDictionary)!;            var sorted = string.IsNullOrWhiteSpace(sortcol) ? Rows : Rows.OrderBy(x => x.Get<object>(sortcol)).ToList();            foreach (var row in sorted)                id[row[keycol]] = row[displaycol];            return id;        }        public Dictionary<TKey, TValue> ToDictionary<T, TKey, TValue>(Expression<Func<T, TKey>> key, Expression<Func<T, TValue>> value,            Expression<Func<T, object>>? sort = null)        {            var result = new Dictionary<TKey, TValue>();            var sorted = sort == null ? Rows : Rows.OrderBy(x => x.Get(sort)).ToList();            foreach (var row in Rows)                result[row.Get(key)] = row.Get(value);            return result;        }        public Dictionary<TKey, string> ToDictionary<T, TKey>(Expression<Func<T, TKey>> key, Expression<Func<T, object>>[] values,            Expression<Func<T, object>>? sort = null)        {            var result = new Dictionary<TKey, string>();            var sorted = sort == null ? Rows : Rows.OrderBy(x => x.Get(sort)).ToList();            foreach (var row in Rows)            {                var display = new List<object>();                foreach (var value in values)                    display.Add(row.Get(value));                result[row.Get(key)] = string.Join(" : ", display);            }            return result;        }        public Dictionary<TKey, TValue> ToDictionary<T, TKey, TValue>(Expression<Func<T, TKey>> key, Func<CoreRow, TValue> value,            Expression<Func<T, object>>? sort = null)        {            var result = new Dictionary<TKey, TValue>();            var sorted = sort == null ? Rows : Rows.OrderBy(x => x.Get(sort)).ToList();            foreach (var row in Rows)                result[row.Get(key)] = value(row);            return result;        }        public void LoadDictionary<T, TKey, TValue>(Dictionary<TKey, TValue> dictionary, Expression<Func<T, TKey>> key,            Expression<Func<T, TValue>> value)        {            foreach (var row in Rows) dictionary[row.Get(key)] = row.Get(value);        }        public DataTable ToDataTable(string name = "", IColumns? additionalColumns = null)        {            var result = new DataTable(name);            foreach (var column in Columns)                result.Columns.Add(column.ColumnName.Replace('.', '_'), column.DataType);            if(additionalColumns != null)            {                foreach (var (column, type) in additionalColumns.AsDictionary())                    result.Columns.Add(column.Replace('.', '_'), type);            }            //result.Columns["ID"].Unique = true;            //result.PrimaryKey = new DataColumn[] { result.Columns["ID"] };            foreach (var row in Rows)            {                //result.Rows.Add(row.Values.ToArray());                var newrow = result.NewRow();                newrow.ItemArray = row.Values.ToArray();                result.Rows.Add(newrow);            }            return result;        }        public IEnumerable<BaseObject> ToObjects(Type T)            => Rows.Select(x => x.ToObject(T));        public IEnumerable<T> ToObjects<T>() where T : BaseObject, new()            => Rows.Select(x => x.ToObject<T>());        public List<T> ToList<T>() where T : BaseObject, new()            => ToObjects<T>().ToList();        public void CopyTo(DataTable table)        {            var columns = new List<string>();            foreach (var column in Columns)                columns.Add(column.ColumnName.Replace('.', '_'));            foreach (var row in Rows)            {                var newrow = table.NewRow();                for (var i = 0; i < columns.Count; i++)                    newrow[columns[i]] = row.Values[i];                table.Rows.Add(newrow);            }        }        public void CopyTo(CoreTable table)        {            var columns = new List<string>();            //foreach (var column in Columns)            //    columns.Add(column.ColumnName.Replace('.', '_'));            foreach (var row in Rows)            {                var newrow = table.NewRow();                foreach (var column in Columns)                    if (table.Columns.Any(x => x.ColumnName.Equals(column.ColumnName)))                        newrow[column.ColumnName] = row[column.ColumnName];                //for (int i = 0; i < columns.Count; i++)                //    newrow.Set(columns[i], row.Values[i]);                table.Rows.Add(newrow);            }        }        public IEnumerable<TValue> ExtractValues<TSource, TValue>(Expression<Func<TSource, TValue>> column, bool distinct = true)        {            var result = Rows.Select(r => r.Get(column));            if (distinct)                result = result.Distinct();            return result;        }        public IEnumerable<TValue> ExtractValues<TValue>(string column, bool distinct = true)        {            var result = Rows.Select(r => r.Get<TValue>(column));            if (distinct)                result = result.Distinct();            return result;        }        public CoreTable LoadRow(object obj)        {            var row = NewRow();            LoadRow(row, obj);            Rows.Add(row);            return this;        }        public Dictionary<TKey, string> IntoDictionary<T, TKey>(Dictionary<TKey, string> result, Expression<Func<T, TKey>> key,            params Expression<Func<T, object>>[] values)        {            foreach (var row in Rows)            {                var display = new List<object>();                foreach (var value in values)                    display.Add(row.Get(value));                result[row.Get(key)] = string.Join(" : ", display);            }            return result;        }        public Dictionary<TKey, TValue> IntoDictionary<T, TKey, TValue>(Dictionary<TKey, TValue> result, Expression<Func<T, TKey>> key,            Func<CoreRow, TValue> value)        {            foreach (var row in Rows)                result[row.Get(key)] = value(row);            return result;        }        public IMutableLookup<TKey, TValue> ToLookup<T, TKey, TValue>(Expression<Func<T, TKey>> key, Expression<Func<T, TValue>> value,            Expression<Func<T, object>>? sort = null)        {            IMutableLookup<TKey, TValue> result = new MutableLookup<TKey, TValue>(                Rows.ToLookup(                    r => r.Get(key),                    r => r.Get(value)                )            );            return result;        }        public IMutableLookup<TKey, TValue> ToLookup<T, TKey, TValue>(Expression<Func<T, TKey>> key, Func<CoreRow, TValue> value,            Expression<Func<T, object>>? sort = null)        {            IMutableLookup<TKey, TValue> result = new MutableLookup<TKey, TValue>(                Rows.ToLookup(                    r => r.Get(key),                    r => value(r)                )            );            return result;        }        #region Serialize Binary        public void WriteBinary(CoreBinaryWriter writer, bool includeColumns)        {            writer.Write(TableName);            if (includeColumns)            {                foreach (var column in Columns)                {                    writer.Write(true);                    writer.Write(column.ColumnName);                    writer.Write(column.DataType.EntityName());                }                writer.Write(false);            }            writer.Write(Rows.Count);            foreach (var row in Rows)            {                foreach (var col in Columns)                {                    var val = row[col.ColumnName];                    writer.WriteBinaryValue(col.DataType, val);                }            }        }        public void SerializeBinary(CoreBinaryWriter writer) => WriteBinary(writer, true);        public void ReadBinary(CoreBinaryReader reader, IList<CoreColumn>? columns)        {            tableName = reader.ReadString();            Columns.Clear();            if (columns is null)            {                while (reader.ReadBoolean())                {                    var columnName = reader.ReadString();                    var dataType = CoreUtils.GetEntity(reader.ReadString());                    Columns.Add(new CoreColumn(dataType, columnName));                }            }            else            {                foreach (var column in columns)                {                    Columns.Add(column);                }            }            Rows.Clear();            var nRows = reader.ReadInt32();            for (int i = 0; i < nRows; ++i)            {                var row = NewRow();                foreach (var column in Columns)                {                    var value = reader.ReadBinaryValue(column.DataType);                    row.Values.Add(value);                }                Rows.Add(row);            }        }        public void DeserializeBinary(CoreBinaryReader reader) => ReadBinary(reader, null);        #endregion    }    public class CoreTableAdapter<T> : IEnumerable<T> where T : BaseObject, new()    {        private List<T>? _objects;        private readonly CoreTable _table;        public CoreTableAdapter(CoreTable table)        {            _table = table;        }        private List<T> Objects        {            get => _objects ??= _table.Rows.Select(row => row.ToObject<T>()).ToList();        }        public T this[int index] => Objects[index];        public IEnumerator<T> GetEnumerator()        {            return GetObjects();        }        IEnumerator IEnumerable.GetEnumerator()        {            return GetObjects();        }        private IEnumerator<T> GetObjects()        {            return Objects.GetEnumerator();        }    }    public class DataTableJsonConverter : JsonConverter    {        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)        {            if(!(value is CoreTable table))            {                writer.WriteNull();                return;            }            writer.WriteStartObject();            writer.WritePropertyName("Columns");            var cols = new Dictionary<string, string>();            foreach (var column in table.Columns)                cols[column.ColumnName] = column.DataType.EntityName();            serializer.Serialize(writer, cols);            //writer.WriteEndObject();            //writer.WriteStartObject();            writer.WritePropertyName("Rows");            writer.WriteStartArray();            var size = 0;            foreach (var row in table.Rows)                //Console.WriteLine("- Serializing Row #"+row.Index.ToString());                try                {                    writer.WriteStartArray();                    foreach (var col in table.Columns)                    {                        var val = row[col.ColumnName];                        if (val != null) size += val.ToString().Length;                        //Console.WriteLine(String.Format("Serializing Row #{0} Column [{1}] Length={2}", row.Index.ToString(), col.ColumnName, val.ToString().Length));                        if (col.DataType.IsArray && val != null)                        {                            writer.WriteStartArray();                            foreach (var val1 in (Array)val)                                writer.WriteValue(val1);                            writer.WriteEndArray();                        }                        else if (col.DataType.GetInterfaces().Contains(typeof(IPackableList)))                        {                            writer.WriteStartArray();                            foreach (var val1 in (IList)val)                                writer.WriteValue(val1);                            writer.WriteEndArray();                        }                        else                        {                            writer.WriteValue(val ?? CoreUtils.GetDefault(col.DataType));                        }                    }                    writer.WriteEndArray();                    //Console.WriteLine(String.Format("[{0:D8}] Serializing Row #{1}", size, row.Index.ToString()));                }                catch (Exception e)                {                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));                }            writer.WriteEndArray();            writer.WriteEndObject();        }        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)        {            if (reader.TokenType == JsonToken.Null)                return null;            var result = new CoreTable();            try            {                var json = JObject.Load(reader);                if (json.TryGetValue("Columns", out var columns))                {                    foreach (JProperty column in columns.Children())                    {                        var name = column.Name;                        var type = column.Value.ToObject<string>();                        result.Columns.Add(new CoreColumn { ColumnName = name, DataType = CoreUtils.GetEntity(type ?? "") });                    }                }                if (json.TryGetValue("Rows", out var rows))                {                    foreach (JArray row in rows.Children())                        if (row.Children().ToArray().Length == result.Columns.Count)                        {                            var newrow = result.NewRow();                            var iCol = 0;                            foreach (var cell in row.Children())                            {                                var column = result.Columns[iCol];                                try                                {                                    if (column.DataType.IsArray)                                    {                                        newrow[column.ColumnName] = cell.ToObject(column.DataType);                                    }                                    else if (column.DataType.GetInterfaces().Contains(typeof(IPackableList)))                                    {                                    }                                    else                                    {                                        newrow[column.ColumnName] = cell.ToObject(column.DataType);                                    }                                    //if ((column.DataType == typeof(byte[])) && (value != null))                                    //    newrow[column.ColumnName] = Convert.FromBase64String(value.ToString());                                    //else if (cell is JValue)                                    //    value = ((JValue)cell).Value;                                    //else if (cell is JObject)                                    //    value = ((JObject)cell).ToObject(column.DataType);                                    //else if (cell is JArray)                                    //    value = ((JArray)cell).ToObject(column.DataType);                                    //else                                    //    value = null;                                }                                catch (Exception e)                                {                                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));                                }                                iCol++;                            }                            result.Rows.Add(newrow);                        }                }            }            catch (Exception e)            {                Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));            }            return result;            //String json = reader.Value.ToString();            //var table = new CoreTable();            //Dictionary<String, Object> dict = Serialization.Deserialize<Dictionary<String, Object>>(json);            //Dictionary<String, String> columns = Serialization.Deserialize<Dictionary<String, String>>(dict["Columns"].ToString());            //List<List<Object>> rows = Serialization.Deserialize<List<List<Object>>>(dict["Rows"].ToString());            //String[] keys = columns.Keys.ToArray();            //foreach (String key in keys)            //    table.Columns.Add(new CoreColumn() { ColumnName = key, DataType = CoreUtils.GetEntity(columns[key]) });            //foreach (List<Object> row in rows)            //{            //    CoreRow newrow = table.NewRow();            //    for (int i = 0; i < keys.Count(); i++)            //    {            //        if (row[i] is JObject)            //            newrow[keys[i]] = JsonConvert.DeserializeObject(row[i].ToString(), table.Columns[i].DataType);            //        else if (table.Columns[i].DataType == typeof(byte[]))            //        {            //            if (row[i] != null)            //                newrow.Set(keys[i], Convert.FromBase64String(row[i].ToString()));            //        }            //        else            //        {            //            try            //            {            //                object o = row[i];            //                if (table.Columns[i].DataType != null)            //                    o = CoreUtils.ChangeType(o, table.Columns[i].DataType);            //                newrow.Set(keys[i], o);            //            }            //            catch (Exception e)            //            {            //            }            //        }            //        //newrow[keys[i]] = row[i];            //    }            //    table.Rows.Add(newrow);            //}            //return table;        }        public override bool CanConvert(Type objectType)        {            return typeof(CoreTable).GetTypeInfo().IsAssignableFrom(objectType);        }    }}
 |