Skip to content
Snippets Groups Projects
JSONManager.cs 15.4 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 static readonly FieldInfo[] JsonSeperateFields =
             typeof(T)
            .GetFields(
                BindingFlags.Instance |
                BindingFlags.Public |
                BindingFlags.NonPublic |
                BindingFlags.Static )
            .Where((field)
                => field.GetCustomAttributes().Any((attribute) 
                    => attribute.GetType() == typeof(JSONManager.JsonSeparateAttribute))
                && field.FieldType.GetInterfaces().Any((inter) 
                    => inter.IsGenericType && inter.GetGenericTypeDefinition() == typeof(IJSONsavable<>)))
            .ToArray();
    
    
        // TODO: this?
        public string name { get; set; }
    
        public string path { get; set; }
        protected static List<Directories>
            hierarchie = new List<Directories> { Directories.misc };
    
    
        #region OverridableMethods
    
    
        public virtual string _IJGetName(string name) => name;
        public virtual List<Directories> _IJGetHierarchie(List<Directories> hierarchie_base)
    
            hierarchie_base ??= new List<Directories>();
            return hierarchie_base.Concat(hierarchie).ToList();
    
        public virtual bool _IJGetRawObject(out T payload, string path) => JSONManager.ReadFromJsonFile<T>(out payload, path);
        public virtual T _IJPreProcess(T payload) => payload;
        public virtual T _IJPostProcess(T payload) => payload;
    
    
        #endregion OverridableMethods
    
    
        #region MethodTemplates
    
    
        public bool store(List<Directories> hierarchie, string name, bool use_install_folder = false, bool overwrite = true, bool deep_store = true)
            => store(hierarchie, name, (T) this, use_install_folder, overwrite, deep_store);
    
        public static bool store(List<Directories> hierarchie, string name, T payload, bool use_install_folder = false, bool overwrite = true, bool deep_store = 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;
    
    
            // store fields decorated with JsonSeparateAttribute and implementing IJSONsavable<> separately
            if (deep_store
                && !store_children(hierarchie, name, payload, use_install_folder: false, overwrite, deep_store: true))
                    return false;
    
            // store this
    
            string path_o = payload.path;
            payload.path = path;
    
            var new_payload =
                Instance._IJPreProcess(payload);
    
            payload.path = path_o;
    
            JSONManager.WriteToJsonFile(path, new_payload);
    
            return true;
        }
    
        
        public bool store_children(List<Directories> hierarchie, string name, bool use_install_folder = false, bool overwrite = true, bool deep_store = true)
            => store_children(hierarchie, name, (T) this, use_install_folder, overwrite, deep_store);
    
        public static bool store_children(List<Directories> hierarchie, string name, T payload, bool use_install_folder = false, bool overwrite = true, bool deep_store = true)
        {
            var new_hierarchie =
                Instance._IJGetHierarchie(hierarchie);
            var new_name =
                Instance._IJGetName(name);
    
            for ((int max_i, bool success) = (0, true); max_i < JsonSeperateFields.Count(); max_i++)
            {
                var field = JsonSeperateFields[max_i];
                dynamic save_me = field.GetValue(payload); // is S:IJSONsavable<S>
    
                Type interface_type = typeof(IJSONsavable<>).MakeGenericType(field.FieldType);
                Type[] store_args_type = new Type[] { typeof(List<Directories>), typeof(string), field.FieldType, typeof(bool), typeof(bool), typeof(bool) };
                object[] store_args = new object[] { new_hierarchie, new_name, save_me, use_install_folder, overwrite, deep_store };
    
                var method = interface_type.GetMethod("store", store_args_type);
                success &= (bool)method.Invoke(null, store_args);
    
                // in case of no success: delete it again
                if (!success)
                {
                    delete_children(hierarchie, name, use_install_folder, JsonSeperateFields.Count() - max_i);
                    return false;
                }
            }
    
            return true;
        }
    
        public static bool load_children(List<Directories> hierarchie, string name, ref T raw_payload, bool use_install_folder = false, bool deep_load = true, bool post_process = true)
        {
            var new_hierarchie =
                Instance._IJGetHierarchie(hierarchie);
            var new_name =
                Instance._IJGetName(name);
    
            bool success = true;
            for (int max_i = 0; max_i < JsonSeperateFields.Count(); max_i++)
            {
                var field = JsonSeperateFields[max_i];
    
                Type interface_type = typeof(IJSONsavable<>).MakeGenericType(field.FieldType);
                Type[] load_args_type = new Type[] { typeof(List<Directories>), typeof(string), field.FieldType.MakeByRefType(), typeof(bool), typeof(bool), typeof(bool) };
                object[] load_args = new object[] { new_hierarchie, new_name, null, use_install_folder, deep_load, post_process };
    
                var method = interface_type.GetMethod("load", BindingFlags.Public | BindingFlags.Static, null, load_args_type, null);
                bool success_i = (bool)method.Invoke(null, load_args);
                
                field.SetValue(raw_payload, success_i ? load_args[2] : Activator.CreateInstance(field.FieldType));
                success &= success_i;
            }
    
            return success;
        }
    
        public static bool load(List<Directories> hierarchie, string name, out T payload, bool use_install_folder = false, bool deep_load = true, bool post_process = true)
    
        {
            payload = default(T);
    
            var new_hierarchie =
                Instance._IJGetHierarchie(hierarchie);
    
            string path = CreatePathToFile(out bool loadable, new_name, "JSON", new_hierarchie, use_install_folder);
    
            if (!loadable)
                return false;
    
    
            if (!Instance._IJGetRawObject(out T raw_payload, path))
                return false;
            raw_payload.name = new_name;
    
            // load fields decorated with JsonSeparateAttribute and implementing IJSONsavable<> separately
            if (deep_load
                && !load_children(hierarchie, name, ref raw_payload, false /*use_install_folder*/))
                success = false;
    
            payload = post_process
                ? Instance._IJPostProcess(raw_payload)
                : raw_payload;
    
            return success;
        }
    
        public static void delete_children(List<Directories> hierarchie, string name, bool use_install_folder = false, int skip_last_children = 0)
        {
            var new_hierarchie =
                Instance._IJGetHierarchie(hierarchie);
            var new_name =
                Instance._IJGetName(name);
    
            for(int i = 0; i < JsonSeperateFields.Count() - skip_last_children; i++) 
            {
                var field = JsonSeperateFields[i];
    
                Type interface_type = typeof(IJSONsavable<>).MakeGenericType(field.FieldType);
                Type[] delete_args_type = new Type[] { typeof(List<Directories>), typeof(string), typeof(bool) };
                object[] delete_args = new object[] { new_hierarchie, new_name, use_install_folder };
    
                var method = interface_type.GetMethod("delete", delete_args_type);
                method.Invoke(null, delete_args);
            }
    
        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);
    
            delete_children(hierarchie, name, use_install_folder);
            return true;
    
        // does not delete children!
        private static bool delete(string path)
    
        {
            if (!File.Exists(path))
                return false;
    
            File.Delete(path);
            return true;
        }
    
    
        // public bool delete() => delete(hierarchie, name);
    
    
        #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;
    
        [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
        public sealed class JsonSeparateAttribute : Attribute
        {
            public JsonSeparateAttribute() { }
        }
    
    
        // 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 bool WriteToJsonFile(string filePath, object objectToWrite, int max_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
            };
    
                string payload = JsonConvert.SerializeObject(objectToWrite, settings);
    
                writer = new StreamWriter(filePath);
                writer.Write(payload);
    
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError(e);
                return false;
    
            }
            finally
            {
                if (writer != null)
                    writer.Close();
            }
        }
    
        /// <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 bool ReadFromJsonFile<T>(out T payload, string filePath) where T : new()
    
            TextReader reader = null;
    
            try
            {
                reader = new StreamReader(filePath);
                var fileContents = reader.ReadToEnd();
    
                payload = JsonConvert.DeserializeObject<T>(fileContents);
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError(e);
                return false;
    
            }
            finally
            {
                if (reader != null)
                    reader.Close();
            }
        }