Skip to content
Snippets Groups Projects
JSONManager.cs 13.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • using System.Collections.Generic;
    using System.Reflection;
    using System.IO;
    using System;
    using System.Linq;
    
    using Newtonsoft.Json;
    
    using JsonSubTypes;
    
    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)
    
        {
            payload = default(T);
    
            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);
    
    
            return delete(path);
        }
    
    
        public static bool delete(string path)
    
        {
            if (!File.Exists(path))
                return false;
    
            File.Delete(path);
            return true;
        }
    
    
        public bool delete()
    
            return delete(path);
    
    
        #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";
    
        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)
    
                this.s = s;
    
            }
        }
    
        public class OMF : MMTTerm
        {
            [JsonProperty("float")]
    
            public float f;
    
            public string kind = "OMF";
    
            public OMF(float f)
            {
    
                this.f = f;
    
            }
        }
    
        public class MMTDeclaration
    
            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";
    
            public MMTTerm lhs;
    
            public MMTTerm valueTp;
            public MMTTerm value;
    
            /**
             * Constructor used for sending new declarations to mmt
             */
    
            public MMTValueDeclaration(string label, MMTTerm lhs, MMTTerm valueTp, MMTTerm value)
    
            {
                this.label = label;
                this.lhs = lhs;
    
                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.
    
    Marco Zimmer's avatar
    Marco Zimmer committed
            var settings = new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            };
    
    
            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();
            }
        }