Newer
Older
using System.Collections.Generic;
using System.Reflection;
using System.IO;
using System;
using System.Linq;
using System.Collections;
using UnityEngine;
using Newtonsoft.Json.Linq;
using static CommunicationEvents;
// I would go for static virtual methods, but C#9 does not allow me...
// static methods cannot be overwritten -> virtual
public interface IJSONsavable<T> where T : IJSONsavable<T>, new()
{
// stand in for non static methods
public static readonly IJSONsavable<T> Instance = new T();
public string path { get; set; }
protected static List<Directories>
hierarchie = new List<Directories> { Directories.misc };
#region OverridableMethods
protected virtual string _IJGetName(string name) => name;
protected virtual List<Directories> _IJGetHierarchie(List<Directories> hierarchie_base)
hierarchie_base ??= new List<Directories>();
return hierarchie_base.Concat(hierarchie).ToList();
protected virtual T _IJGetRawObject(string path) => JSONManager.ReadFromJsonFile<T>(path);
protected virtual T _IJPreProcess(T payload) => payload;
protected virtual T _IJPstProcess(T payload) => payload;
#endregion OverridableMethods
#region MethodTemplates
public bool store(List<Directories> hierarchie, string name, bool use_install_folder = false, bool overwrite = true)
return store(hierarchie, name, (T) this, use_install_folder, overwrite);
}
public static bool store(List<Directories> hierarchie, string name, T payload, bool use_install_folder = false, bool overwrite = true)
{
var new_hierarchie =
Instance._IJGetHierarchie(hierarchie);
var new_name =
Instance._IJGetName(name);
string path = CreatePathToFile(out bool exists, new_name, "JSON", new_hierarchie, use_install_folder);
if (exists && !overwrite)
return false;
string path_o = payload.path;
payload.path = path;
var new_payload =
Instance._IJPreProcess(payload);
payload.path = path_o;
JSONManager.WriteToJsonFile(path, new_payload);
public static bool load(List<Directories> hierarchie, string name, out T payload, bool use_install_folder = false)
var new_hierarchie =
Instance._IJGetHierarchie(hierarchie);
string path = CreatePathToFile(out bool loadable, name, "JSON", new_hierarchie, use_install_folder);
if (!loadable)
return false;
var raw_payload =
Instance._IJGetRawObject(path);
payload =
Instance._IJPstProcess(raw_payload);
public static bool delete(List<Directories> hierarchie, string name, bool use_install_folder = false)
var new_hierarchie =
Instance._IJGetHierarchie(hierarchie);
var new_name =
Instance._IJGetName(name);
string path = CreatePathToFile(out bool _, new_name, "JSON", new_hierarchie, use_install_folder);
public static bool delete(string path)
{
if (!File.Exists(path))
return false;
File.Delete(path);
return true;
}
#endregion MethodTemplates
public class MMTURICollection
{
public string Point = "http://mathhub.info/MitM/core/geometry?3DGeometry?point";
public string Tuple = "http://gl.mathhub.info/MMT/LFX/Sigma?Symbols?Tuple";
public string LineType = "http://mathhub.info/MitM/core/geometry?Geometry/Common?line_type";
public string LineOf = "http://mathhub.info/MitM/core/geometry?Geometry/Common?lineOf";
public string OnLine = "http://mathhub.info/MitM/core/geometry?Geometry/Common?onLine";
public string Ded = "http://mathhub.info/MitM/Foundation?Logic?ded";
public string Eq = "http://mathhub.info/MitM/Foundation?Logic?eq";
public string Metric = "http://mathhub.info/MitM/core/geometry?Geometry/Common?metric";
public string Angle = "http://mathhub.info/MitM/core/geometry?Geometry/Common?angle_between";
public string Sketch = "http://mathhub.info/MitM/Foundation?InformalProofs?proofsketch";
John Schihada
committed
public string RealLit = "http://mathhub.info/MitM/Foundation?RealLiterals?real_lit";
public static class JSONManager
{
//could init the strings of MMTURIs with JSON or other settings file instead
public static MMTURICollection MMTURIs = new MMTURICollection();
public class URI
{
public string uri;
public URI(string uri)
{
this.uri = uri;
}
}
[JsonConverter(typeof(JsonSubtypes), "kind")]
public class MMTTerm
{
string kind;
}
public class OMA : MMTTerm
{
public MMTTerm applicant;
public List<MMTTerm> arguments;
public string kind = "OMA";
public OMA(MMTTerm applicant, List<MMTTerm> arguments)
{
this.applicant = applicant;
this.arguments = arguments;
}
}
public class OMS : MMTTerm
{
public string uri;
public string kind = "OMS";
public OMS(string uri)
{
this.uri = uri;
}
}
public class OMSTR : MMTTerm
{
[JsonProperty("float")]
public string s;
public string kind = "OMSTR";
public OMSTR(string s)
}
}
public class OMF : MMTTerm
{
[JsonProperty("float")]
public string kind = "OMF";
public OMF(float f)
{
}
}
public class MMTDeclaration
public string label;
public static MMTDeclaration FromJson(string json)
{
MMTDeclaration mmtDecl = JsonConvert.DeserializeObject<MMTDeclaration>(json);
if (mmtDecl.label == null)
mmtDecl.label = string.Empty;
return mmtDecl;
}
public static string ToJson(MMTDeclaration mmtDecl)
{
if (mmtDecl.label == null)
mmtDecl.label = string.Empty;
string json = JsonConvert.SerializeObject(mmtDecl);
return json;
}
}
/**
* MMTSymbolDeclaration: Class for facts without values, e.g. Points
public class MMTSymbolDeclaration : MMTDeclaration
public string kind = "general";
public MMTTerm tp;
public MMTTerm df;
/**
* Constructor used for sending new declarations to mmt
*/
public MMTSymbolDeclaration(string label, MMTTerm tp, MMTTerm df)
{
this.label = label;
this.tp = tp;
this.df = df;
}
/**
* MMTValueDeclaration: Class for facts with values, e.g. Distances or Angles
public class MMTValueDeclaration : MMTDeclaration
public string kind = "veq";
John Schihada
committed
public MMTTerm valueTp;
public MMTTerm value;
/**
* Constructor used for sending new declarations to mmt
*/
John Schihada
committed
public MMTValueDeclaration(string label, MMTTerm lhs, MMTTerm valueTp, MMTTerm value)
{
this.label = label;
this.lhs = lhs;
John Schihada
committed
this.valueTp = valueTp;
this.value = value;
// TODO? /// <para>If there are public properties/variables that you do not want written to the file, decorate them with the [JsonIgnore] attribute.</para>
/// <summary>
/// Writes the given object instance to a Json file, recursively to set depth, including all members.
/// <para>Object type must have a parameterless constructor.</para>
/// <para>Only All properties and variables will be written to the file. These can be any type though, even other non-abstract classes.</para>
/// </summary>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the file.</param>
/// <param name="max_depth">The depth recursion will occur. Default = 0.</param>
public static void WriteToJsonFile(string filePath, object objectToWrite, int max_depth = 0)
{
int current_depth = 0;
// This tells your serializer that multiple references are okay.
var settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
BindingFlags bindFlags =
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Static;
TextWriter writer = null;
try
{
string payload = RecursiveStep(objectToWrite);
writer = new StreamWriter(filePath);
writer.Write(payload);
}
finally
{
if (writer != null)
writer.Close();
}
// ======= local methods =======
// TODO? more stable depths (see next todo)
// TODO? respect IgnoreJson tags
string RecursiveStep<S>(S objectToWrite) where S : new()
{
string json;
if (current_depth >= max_depth
|| Type.GetTypeCode(objectToWrite.GetType()) != TypeCode.Object
|| objectToWrite == null)
json = JsonConvert.SerializeObject(objectToWrite, settings/*, new JsonInheritenceConverter<object>()*/);
else
{
current_depth++;
json = IntrusiveRecursiveJsonGenerator(objectToWrite);
current_depth--;
}
return json;
}
string IntrusiveRecursiveJsonGenerator<S>(S objectToWrite) where S : new()
// private convention? more like private suggestion!
{
bool is_enum = IsEnumerableType(objectToWrite.GetType());
string json = is_enum ? "[" : "{";
foreach (object field in is_enum ? (objectToWrite as IEnumerable) : objectToWrite.GetType().GetFields(bindFlags))
{
object not_so_private;
if (is_enum)
{
not_so_private = field;
}
else
{
not_so_private = ((FieldInfo)field).GetValue(objectToWrite);
json += ((FieldInfo)field).Name + ":";
}
json += RecursiveStep(not_so_private);
json += ",";
}
json = json.TrimEnd(',') + (is_enum ? "]" : "}");
return json;
// ======= local methods =======
bool IsEnumerableType(Type type)
{
if (type.IsInterface && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
return true;
foreach (Type intType in type.GetInterfaces())
{
if (intType.IsGenericType
&& intType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
return true;
}
}
return false;
}
}
}
/// <summary>
/// Reads an object instance from an Json file.
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object to read from the file.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the Json file.</returns>
public static T ReadFromJsonFile<T>(string filePath) where T : new()
{
TextReader reader = null;
try
{
reader = new StreamReader(filePath);
var fileContents = reader.ReadToEnd();
return JsonConvert.DeserializeObject<T>(fileContents/*, new JsonInheritenceConverter<object>()*/);
}
finally
{
if (reader != null)
reader.Close();
}
}
// tutorial @https://www.codeproject.com/Articles/1201466/Working-with-JSON-in-Csharp-VB#data_structure_types
// unused
// TODO: check for actual type in ReadJson
// TODO: avoid self-referencing-loop-error in WriteJson
public sealed class JsonInheritenceConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
var element = jo.Properties().First();
return element.Value.ToObject(Type.GetType(element.Name));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
serializer.Serialize(writer, null);
return;
}
writer.WriteStartObject();
writer.WritePropertyName(value.GetType().FullName);
serializer.Serialize(writer, value);
writer.WriteEndObject();
}
}