From e7ac1ce0ebb5d223c8588e063cee5bbbb6da6b5b Mon Sep 17 00:00:00 2001
From: MaZiFAU <63099053+MaZiFAU@users.noreply.github.com>
Date: Wed, 5 Jul 2023 23:43:34 +0200
Subject: [PATCH] HotFix; Bug Fix; +ListFact;
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

ListFact:
+Intrduction, needed for lists on MMT server side
+Incomplete
+-> see SOMDocManager.MMT_OMS_URI.FactRef
Bug Fix:
+Fact Ordering was broken
+ScrollFactContainer marked as IsSet wrongly
+Angle Hint showed up with 0°
HotFix;
+Game Crash when Scrolls not loaded
+-> patched with guard clausel (pls find better way)
---
 Assets/Scripts/GenerateDemoFiles.cs           |  5 ++
 .../FactWrapper/RenderedScrollFact.cs         |  3 +-
 .../FactHandling/Facts/AbstractAngleFact.cs   |  6 +-
 .../FactHandling/Facts/Fact.cs                | 71 +++++++++++++++---
 .../FactHandling/Facts/FunctionFact.cs        | 45 +++++++++---
 Assets/Scripts/InventoryStuff/DisplayFacts.cs | 73 ++++++++++++++++---
 .../Scripts/InventoryStuff/ScrollDetails.cs   |  5 ++
 Assets/Scripts/Loading/Loader.cs              |  6 ++
 Assets/Scripts/SOMDocManager.cs               |  4 +
 .../Extensions/GameObjectExtensions.cs        |  8 +-
 10 files changed, 189 insertions(+), 37 deletions(-)

diff --git a/Assets/Scripts/GenerateDemoFiles.cs b/Assets/Scripts/GenerateDemoFiles.cs
index 07330d68..84f24afd 100644
--- a/Assets/Scripts/GenerateDemoFiles.cs
+++ b/Assets/Scripts/GenerateDemoFiles.cs
@@ -234,6 +234,11 @@ public static void GenerateCanonBallStage()
         }
 
         // Set Solution
+        StageStatic.stage.solution.Add( // for CannonBallScroll
+            new ListFact(Walls.Select(w => w.Topology.Id).ToArray(), StageStatic.stage.solution),
+            out bool _, true, null, null
+        );
+
         string BallURI = StageStatic.stage.solution.Add(
             new PointFact(StartPos, Vector3.up, StageStatic.stage.solution),
             out _, false, null, null);
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs
index d7bec163..c73c0ceb 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs
@@ -46,12 +46,11 @@ public string ScrollFactLabel
 
     protected override void FactUpdated()
     {
+        _URI ??= ScrollFactURI;
         Destroy(_Payload);
 
         NewAssignmentEvent.Invoke();
 
-        _URI ??= ScrollFactURI;
-
         if (VerboseURI)
             Debug.Log(nameof(RenderedScrollFact) + " recieved Fact: " + URI);
     }
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractAngleFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractAngleFact.cs
index 47915699..8f22fec1 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractAngleFact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractAngleFact.cs
@@ -54,7 +54,9 @@ protected AbstractAngleFact(string pid1, string pid2, string pid3, FactOrganizer
     protected AbstractAngleFact(string pid1, string pid2, string pid3, float angle, string backendURI, FactOrganizer organizer)
         : this(pid1, pid2, pid3, organizer)
     {
-        this.angle = angle;
+        this.angle = angle == -0f
+            ? Vector3.Angle((Point1.Point - Point2.Point), (Point3.Point - Point2.Point))
+            : angle;
         this._URI = backendURI;
     }
 
@@ -175,7 +177,7 @@ public override MMTDeclaration MakeMMTDeclaration()
             return null;
 
         float angle = value_fact.value == null
-            ? 0f
+            ? -0f
             : ((OMF)value_fact.value).@float;
 
         string pointAUri = ((OMS)lhs.arguments[0]).uri;
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs
index a52e837f..36764b94 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs
@@ -6,7 +6,6 @@
 using JsonSubTypes;
 using System.Linq;
 using static SOMDocManager;
-using System.Collections;
 using static Scroll;
 
 public static class ParsingDictionary
@@ -57,6 +56,8 @@ public static class ParsingDictionary
             EqualCirclesFact.parseFact },
         { MMT_OMS_URI.UnEqualityCircles,
             UnEqualCirclesFact.parseFact },
+        { MMT_OMS_URI.ListLiteral,
+            ListFact.parseFact },
     };
 
     // TODO: get rid of this
@@ -90,6 +91,7 @@ public static class ParsingDictionary
 [JsonSubtypes.KnownSubType(typeof(AttachedPositionFunction), nameof(AttachedPositionFunction))]
 [JsonSubtypes.KnownSubType(typeof(FunctionFact), nameof(FunctionFact))]
 [JsonSubtypes.KnownSubType(typeof(FunctionCallFact), nameof(FunctionCallFact))]
+[JsonSubtypes.KnownSubType(typeof(ListFact), nameof(ListFact))]
 //[JsonSubtypes.KnownSubType(typeof(FunctionFact<T0, TResult>), "FunctionFact<T0, TResult>")] //TODO: generics? => nameof does not work (generic agnostic)
 //[JsonSubtypes.KnownSubType(typeof(FunctionFactFloat<Vector3>), "FunctionFact<System.Single, UnityEngine.Vector3>")]
 public abstract class Fact
@@ -2296,20 +2298,38 @@ protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, F
 /// <summary>
 /// 
 /// </summary>
-/// <remarks>Hopefully not needed <see cref="SOMDoc.MakeList(string[], string)"/></remarks>
+/// <seealso cref="SOMDoc.MakeList(string[], string)"/>
+/// <remarks>Needed to refere to lists serverside</remarks>
 public class ListFact : FactWrappedCRTP<ListFact>
 {
-    public string[] lids = new string[0];
+    public string[] lids;
 
-    public string typeURI;
+    //public string typeURI;
+    //[JsonIgnore]
+    //public Type type => MMT_OMS_URI.OMS_TO_TYPE[typeURI];
 
-    [JsonIgnore]
-    public Type type => MMT_OMS_URI.OMS_TO_TYPE[typeURI];
+
+    public ListFact() : base()
+    {
+        lids = new string[0];
+    }
+
+    public ListFact(string[] lids, FactOrganizer organizer) : base(organizer)
+    {
+        this.lids = lids;
+        SendToMMT();
+    }
+
+    public ListFact(string[] lids, string backendURI, FactOrganizer organizer) : base(organizer)
+    {
+        this.lids = lids;
+        _URI = backendURI;
+    }
 
 
     protected override bool EquivalentWrapped(ListFact f1, ListFact f2)
-        => f1.typeURI == f2.typeURI
-        && DependentFactsEquivalent(f1, f2);
+        => //f1.typeURI == f2.typeURI &&
+           DependentFactsEquivalent(f1, f2);
 
     public override bool HasDependentFacts
         => true;
@@ -2319,10 +2339,43 @@ protected override string[] GetGetDependentFactIds()
 
     public override MMTDeclaration MakeMMTDeclaration()
     {
-        OMA List = SOMDoc.MakeList(lids, typeURI);
+        OMA List = SOMDoc.MakeList(lids, typeof(OMS));
         return new MMTSymbolDeclaration(Label, List.applicant, List.applicant);
     }
 
+    public static new ListFact parseFact(MMTDeclaration fact)
+        => new(parseFactList(fact).ToArray(), fact.@ref.uri, StageStatic.stage.factState);
+
+    public static List<string> parseFactList(MMTDeclaration decl)
+    {
+        if (decl is not MMTSymbolDeclaration mMTSymbol)
+            return null;
+
+        List<string> ret = new();
+        SOMDoc next_element = mMTSymbol.defines;
+        while (true)
+        {
+            if (next_element is not OMA current_element)
+                return ret;
+
+            switch (current_element.arguments.Count)
+            {
+                case 2:
+                    if (current_element.arguments[1] is not OMS oMS)
+                        return ret;
+
+                    ret.Add(oMS.uri);
+                    next_element = current_element.arguments[0];
+                    break;
+
+                case 0:
+                case 1:
+                default:
+                    return ret;
+            }
+        }
+    }
+
     public static List<T> parseFactList<T>(MMTDeclaration decl)
     {
         if (decl is not MMTSymbolDeclaration mMTSymbol)
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs
index dfe302ee..fda444e3 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs
@@ -183,14 +183,20 @@ public class AttachedPositionFunction : FactWrappedCRTP<AttachedPositionFunction
 {
     public string fid;
 
-    public string[] func_call_ids;
+    public string func_calls_list_id;
+
+    [JsonIgnore]
+    public string[] FuncCallIds => FunctionCallFactsList.lids;
 
     [JsonIgnore]
     public Fact Fact => FactOrganizer.AllFacts[fid];
 
+    [JsonIgnore]
+    public ListFact FunctionCallFactsList => (ListFact) FactOrganizer.AllFacts[func_calls_list_id];
+
     [JsonIgnore]
     public FunctionCallFact[] FunctionCallFacts
-        => func_call_ids.Select(f => FactOrganizer.AllFacts[f] as FunctionCallFact).ToArray();
+        => FuncCallIds.Select(f => FactOrganizer.AllFacts[f] as FunctionCallFact).ToArray();
 
     /// <summary>\copydoc Fact.Fact()</summary>
     public AttachedPositionFunction() : base() { }
@@ -198,21 +204,40 @@ public AttachedPositionFunction() : base() { }
     /// <summary>\copydoc Fact.Fact(FactOrganizer)</summary>
     public AttachedPositionFunction(string fid, string[] funcids, FactOrganizer organizer) : base(organizer)
     {
-        init(fid, funcids);
+        init(fid, funcids, organizer);
+        //TODO: call MMT, set URI
+        _URI = Fact.Id + "{" + string.Join(", ", FunctionCallFacts.Select(f => f.Id)) + "}";
+    }    
+    
+    /// <summary>\copydoc Fact.Fact(FactOrganizer)</summary>
+    public AttachedPositionFunction(string fid, string func_calls_list_id, FactOrganizer organizer) : base(organizer)
+    {
+        init(fid, func_calls_list_id);
         //TODO: call MMT, set URI
         _URI = Fact.Id + "{" + string.Join(", ", FunctionCallFacts.Select(f => f.Id)) + "}";
     }
 
-    private void init(string fid, string[] funcids)
+    private void init(string fid, string[] funcids, FactOrganizer organizer)
     {
         this.fid = fid;
-        this.func_call_ids = funcids;
+        func_calls_list_id = organizer.Add(new ListFact(funcids, organizer), out bool _, false, null, null);
+    }
+
+    private void init(string fid, string func_calls_list_id)
+    {
+        this.fid = fid;
+        this.func_calls_list_id = func_calls_list_id;
     }
 
     protected AttachedPositionFunction(string fid, string[] funcids, string uri, FactOrganizer organizer) : base(organizer)
     {
-        init(fid, funcids);
+        init(fid, funcids, organizer);
+        _URI = uri;
+    }
 
+    protected AttachedPositionFunction(string fid, string func_calls_list_id, string uri, FactOrganizer organizer) : base(organizer)
+    {
+        init(fid, func_calls_list_id);
         _URI = uri;
     }
 
@@ -223,14 +248,15 @@ protected AttachedPositionFunction(string fid, string[] funcids, string uri, Fac
 
         ParsingDictionary.parseTermsToId.TryAdd(defines.ToString(), fact.@ref.uri);
 
-        return new AttachedPositionFunction(default, default, fact.@ref.uri, StageStatic.stage.factState);
+        return new AttachedPositionFunction(default, default(string), fact.@ref.uri, StageStatic.stage.factState);
     }
 
+
     public override bool HasDependentFacts
         => true;
 
     protected override string[] GetGetDependentFactIds()
-        => new string[] { fid }.ShallowCloneAppend(func_call_ids);
+        => new string[] { fid, func_calls_list_id };
 
     public override int GetHashCode()
         => Fact.GetHashCode() ^ FunctionCallFacts.GetHashCode();
@@ -246,7 +272,8 @@ protected override void RecalculateTransform()
     }
 
     protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactOrganizer organizer)
-        => new AttachedPositionFunction(old_to_new[this.fid], this.func_call_ids.Select(id => old_to_new[id]).ToArray(), organizer);
+        => new AttachedPositionFunction(old_to_new[this.fid], old_to_new[func_calls_list_id], organizer);
+        // => new AttachedPositionFunction(old_to_new[this.fid], this.FuncCallIds.Select(id => old_to_new[id]).ToArray(), organizer);
 
     public override MMTDeclaration MakeMMTDeclaration()
     {
diff --git a/Assets/Scripts/InventoryStuff/DisplayFacts.cs b/Assets/Scripts/InventoryStuff/DisplayFacts.cs
index 129aa3b0..c5034a2a 100644
--- a/Assets/Scripts/InventoryStuff/DisplayFacts.cs
+++ b/Assets/Scripts/InventoryStuff/DisplayFacts.cs
@@ -154,7 +154,7 @@ public static GameObject InstantiateDisplay(Fact fact, Transform transform)
     #region AscDesc
     public void AscDescChanged(Toggle t)
     {
-        sortDescending = !sortDescending;
+        sortDescending = !sortDescending; // t.isOn
         factscreenContent.gameObject.ForAllChildren(child => child.transform.SetAsFirstSibling());
     }
     #endregion AscDesc
@@ -165,9 +165,14 @@ public void GroupingChanged(Toggle t)
         showGrouped = t.isOn;
 
         var vals = factscreenContent.gameObject.GetDirectChildren();
+
         var ordered = showGrouped
-            ? vals.OrderBy(tr => tr.GetComponent<FactObject>().Fact, new FactTypeComparer()).ToList()
-            : vals.OrderBy(tr => displayedFacts.Keys.ToList().IndexOf(tr.GetComponent<FactObject>().Fact.Id)).ToList();
+            ? vals.OrderBy(tr => tr.GetComponent<FactWrapper>().Fact, new FactTypeComparer()).ToList()
+            : vals.OrderBy(tr =>
+                displayedFacts.Keys.ToList()
+                    .IndexOf(
+                          tr.GetComponent<FactWrapper>().URI
+                )).ToList();
 
         if (sortDescending)
             ordered.Reverse();
@@ -183,7 +188,7 @@ private int GetIndexInSortedList(Fact f, List<Fact> toCheck)
         return index;
     }
 
-    internal class FactTypeComparer : IComparer<Fact>
+    private class FactTypeComparer : IComparer<Fact>
     {
         /// <summary>
         /// Compare two facts by type and label
@@ -193,11 +198,58 @@ internal class FactTypeComparer : IComparer<Fact>
         /// <returns></returns>
         public int Compare(Fact x, Fact y)
         {
-            if (x.GetType() == y.GetType()) // same type: compare labels
-                return string.Compare(x.Label, y.Label);
-            else // different types: compare type
-                return string.Compare(x.GetType().ToString(), y.GetType().ToString());
+            int ret, index_x;
+
+#pragma warning disable CS0642 // Möglicherweise falsche leere Anweisung
+
+            if (0 != (ret = (index_x = TypeRank.IndexOf(x.GetType())) - TypeRank.IndexOf(y.GetType()))) ;
+            else
+            if (index_x < 0) // Types not in List and same
+                if (0 != (ret = x.DependentFactIds.Length - y.DependentFactIds.Length)) ;
+                else
+                if (0 != (ret = string.Compare(x.GetType().ToString(), y.GetType().ToString()))) ;
+                else;
+            else if (true) // keep auto format // Types in List and same
+                if (0 != (ret = x.DependentFactIds.Zip(y.DependentFactIds, (x, y) => string.Compare(x, y)).Aggregate(0, (r1, r2) => r1 + r2))) ;
+                else
+                if (0 != (ret = string.Compare(x.Label, y.Label))) ;
+
+#pragma warning restore CS0642 // Möglicherweise falsche leere Anweisung
+
+            return ret;
         }
+
+        private List<Type> TypeRank = new()
+        {
+            typeof(PointFact),
+
+            typeof(OnLineFact),
+            typeof(LineFact),
+            typeof(RayFact),
+            typeof(ParallelLineFact),
+
+            typeof(RightAngleFact),
+            typeof(AngleFact),
+
+            typeof(CircleFact),
+            typeof(RadiusFact),
+            typeof(AreaCircleFact),
+            typeof(EqualCirclesFact),
+            typeof(UnEqualCirclesFact),
+            typeof(OnCircleFact),
+            typeof(AngleCircleLineFact),
+            typeof(OrthogonalCircleLineFact),
+
+            typeof(CylinderVolumeFact),
+            typeof(ConeVolumeFact),
+            typeof(TruncatedConeVolumeFact),
+
+            typeof(FunctionFact),
+            typeof(FunctionCallFact),
+            typeof(AttachedPositionFunction),
+
+            typeof(TestFact),
+        };
     }
     #endregion Grouping
     #endregion Sorting
@@ -222,9 +274,8 @@ private void OnFavoriteChange(Fact changedFact, bool isFavourite)
         if (!showOnlyFavorites)
             return;
 
-        var id = changedFact.Id;
-        if (displayedFacts.ContainsKey(id))
-            displayedFacts[id].transform.parent.gameObject.SetActive(isFavourite);
+        if (displayedFacts.TryGetValue(changedFact.Id, out GameObject display))
+            display.transform.parent.gameObject.SetActive(isFavourite);
     }
     #endregion Favorites
 
diff --git a/Assets/Scripts/InventoryStuff/ScrollDetails.cs b/Assets/Scripts/InventoryStuff/ScrollDetails.cs
index d9ae92cb..eda160c8 100644
--- a/Assets/Scripts/InventoryStuff/ScrollDetails.cs
+++ b/Assets/Scripts/InventoryStuff/ScrollDetails.cs
@@ -140,6 +140,11 @@ private int[] PrePopulateActiveScroll()
         switch (ActiveScroll.@ref)
         {
             case MMT_OMS_URI.ScrollCannonBall:
+                string lid_override = StageStatic.stage.solution.MyFactSpace.Values.FirstOrDefault(sol => sol is ListFact)?.Id;
+                if (lid_override == null)
+                    goto default;
+
+                ParameterDisplays[2].URI = lid_override;
                 return new int[] { 2 };
 
             default:
diff --git a/Assets/Scripts/Loading/Loader.cs b/Assets/Scripts/Loading/Loader.cs
index 840e7d64..32de2b14 100644
--- a/Assets/Scripts/Loading/Loader.cs
+++ b/Assets/Scripts/Loading/Loader.cs
@@ -41,6 +41,12 @@ public static bool LoadStage(string name, bool local, bool restore_session)
     /// <param name="scene">sets <see cref="nextscene"/></param>
     public static void LoadScene(string scene)
     {
+        if(GlobalBehaviour.AvailableScrolls == null) // Game crashes otherwise
+        {
+            Debug.LogWarning("Wait for Server to finish Scroll/all!\nFind a better Way than this guard clause.,,");
+            return;
+        }
+
         nextscene = scene;
         SceneManager.LoadScene("LoadingScene");
         // loads LoadingScreen, which will call LoaderCallback() in LoadingScreenPercentage
diff --git a/Assets/Scripts/SOMDocManager.cs b/Assets/Scripts/SOMDocManager.cs
index a6b8c986..117fb661 100644
--- a/Assets/Scripts/SOMDocManager.cs
+++ b/Assets/Scripts/SOMDocManager.cs
@@ -59,6 +59,8 @@ public static class MMT_OMS_URI
         public static readonly string ListLiteral = "http://gl.mathhub.info/MMT/LFX/Datatypes?ListSymbols?cons";
         public static readonly string ListEnd = "http://gl.mathhub.info/MMT/LFX/Datatypes?ListSymbols?nil_constant";
 
+        public static readonly string FactRef = "SET_IN_SOMDocManager!";
+
         public static readonly string Sin = "Sin";
         public static readonly string Cos = "Cos";
         public static readonly string Add = "Add";
@@ -130,6 +132,8 @@ public static class MMT_OMS_URI
             { UnEqualityCircles,
                 typeof(UnEqualCirclesFact) },
 
+            { FactRef,
+                typeof(OMS) },
             { RealLit,
                 typeof(float) },
             { Tuple,
diff --git a/Assets/Scripts/Utility/Extensions/GameObjectExtensions.cs b/Assets/Scripts/Utility/Extensions/GameObjectExtensions.cs
index 86b5c77a..015d5919 100644
--- a/Assets/Scripts/Utility/Extensions/GameObjectExtensions.cs
+++ b/Assets/Scripts/Utility/Extensions/GameObjectExtensions.cs
@@ -24,15 +24,15 @@ public static void SetActiveAllChildren(this GameObject root, bool active)
 
     public static void ForAllChildren(this GameObject root, Action<GameObject> func_on_child)
     {
-        for (int i = 0; i < root.transform.childCount; i++)
-            func_on_child(root.transform.GetChild(i).gameObject);
+        foreach (Transform transform in root.transform)
+            func_on_child(transform.gameObject);
     }
 
     public static List<GameObject> GetDirectChildren(this GameObject root)
     {
         List<GameObject> ret = new (capacity: root.transform.childCount);
-        foreach (GameObject child in root.transform)
-            ret.Add(child);
+        foreach (Transform transform in root.transform)
+            ret.Add(transform.gameObject);
 
         return ret;
     }
-- 
GitLab