using System.Collections; using System.Collections.Generic; using UnityEngine; using TMPro; using UnityEngine.Networking; using Newtonsoft.Json; using System.Linq; using static CommunicationEvents; using static SOMDocManager; using System; using static Scroll; public class ScrollDetails : MonoBehaviour { public static ScrollDetails Instance { get => _Instance; set { if (_Instance == null) _Instance = value; else Destroy(value); } } private static ScrollDetails _Instance; public WorldCursor cursor; public GameObject parameterDisplayPrefab; public Scroll ActiveScroll; public GameObject mmtAnswerPopUp; private PopupBehavior Popup; public static List<RenderedScrollFact> ParameterDisplays; private static List<ScrollAssignment> LatestCompletions; private static List<Fact> LatestRenderedHints; public string currentMmtAnswer; public bool DynamicScrollDescriptionsActive = true; public bool AutomaticHintGenerationActive = true; private bool DynamicScrollDone = true; void Awake() { Instance = this; if (cursor == null) cursor = FindObjectOfType<WorldCursor>(); Popup = mmtAnswerPopUp.GetComponent<PopupBehavior>(); Popup.gameObject.SetActive(true); // force Awake } private void OnEnable() { ScrollFactHintEvent.AddListener(animateHint); NewAssignmentEvent.AddListener(NewAssignmentTrigger); } private void OnDisable() { ScrollFactHintEvent.RemoveListener(animateHint); NewAssignmentEvent.RemoveListener(NewAssignmentTrigger); } private void OnDestroy() { _Instance = null; } public void SetScroll(Scroll scroll_to_set) { ActiveScroll = scroll_to_set; Transform originalScroll = gameObject.transform.GetChild(1); Transform originalScrollView = originalScroll.GetChild(1); Transform originalViewport = originalScrollView.GetChild(0); //Clear all current ScrollFacts originalViewport.GetChild(0).gameObject.DestroyAllChildren(); originalScroll.GetChild(0).GetComponent<TextMeshProUGUI>().text = ActiveScroll.description; //ParameterDisplays.ForEach(gameObj => Destroy(gameObj)); ParameterDisplays = new(); for (int i = 0; i < ActiveScroll.requiredFacts.Count; i++) { GameObject originalObj = Instantiate(parameterDisplayPrefab, originalViewport.GetChild(0)); RenderedScrollFact originalRSF = originalObj.GetComponentInChildren<RenderedScrollFact>(); ParameterDisplays.Add(originalRSF); originalRSF.Populate(ActiveScroll, i); } foreach (int i in PrePopulateActiveScroll()) ParameterDisplays[i].gameObject.SetActive(false); //set active scroll for ErrorMessagePopup Popup.ActiveScroll = ActiveScroll; Popup.ParameterDisplays = ParameterDisplays; } public bool SetNextEmptyTo(FactObjectUI activator) { RenderedScrollFact check = ParameterDisplays .Find(RSF => RSF != null && RSF.Payload != null && RSF.Payload.Equals(activator) ); if (check != null) { check.URI = null; return false; } RenderedScrollFact empty = ParameterDisplays .Find(RSF => !RSF.IsSet); if (empty == null) return false; empty.SetByFactObject(activator); return true; } /// <summary> /// Secretly populates <see cref="Scroll"/>s /// </summary> /// <returns><c>Array</c> containing indicis of <see cref="Scroll.requiredFacts"/> to be hidden.</returns> private int[] PrePopulateActiveScroll() { switch (ActiveScroll.@ref) { case MMT_OMS_URI.ScrollCannonBall: return new int[] { 2 }; default: return new int[0]; } } public void MagicButtonTrigger() { StartCoroutine(_MagicButton()); IEnumerator _MagicButton() { while (!DynamicScrollDone) yield return null; // Wait for last assignment DynamicScrollDone = false; yield return SendView("/scroll/apply"); DynamicScrollDone = true; if (currentMmtAnswer == null) { Debug.LogError("Magic FAILED"); ScrollApplicationCheckingErrorEvent.Invoke(null); } else { if (VerboseURI) Debug.Log("Magic answers:\n" + currentMmtAnswer); ScrollApplicationInfo pushout = JsonConvert.DeserializeObject<ScrollApplicationInfo>(currentMmtAnswer); if (pushout.acquiredFacts.Count == 0 || pushout.errors.Length > 0) { ScrollApplicationCheckingErrorEvent.Invoke(pushout.errors); PushoutFactFailEvent.Invoke(); } ReadPushout(pushout.acquiredFacts); } } } public void NewAssignmentTrigger() { if (AutomaticHintGenerationActive || DynamicScrollDescriptionsActive) StartCoroutine(_NewAssignment()); IEnumerator _NewAssignment() { while (!DynamicScrollDone) yield return null; // if we dont wait => server will crash DynamicScrollDone = false; yield return SendView("/scroll/dynamic"); DynamicScrollDone = true; if (currentMmtAnswer == null) { Debug.LogError("Dynamic Scroll FAILED"); } else { ScrollDynamicInfo scrollDynamicInfo; try { scrollDynamicInfo = JsonConvert.DeserializeObject<ScrollDynamicInfo>(currentMmtAnswer); } catch (JsonSerializationException ex) { Debug.LogException(ex); Debug.LogError("Could not Deserialize MMT aswer for /scroll/dynamic\n" + currentMmtAnswer); yield break; } ScrollApplicationCheckingError[] errors = scrollDynamicInfo.errors .Where(err => err.kind != "nonTotal") // expected .ToArray(); if (errors.Length > 0) ScrollApplicationCheckingErrorEvent.Invoke(errors); processScrollDynamicInfo(scrollDynamicInfo); } } } private IEnumerator SendView(string endpoint) { while (ParameterDisplays == null) // Wait for server yield return null; string body = prepareScrollAssignments(); using UnityWebRequest www = UnityWebRequest.Put(ServerAdress + endpoint, body); www.method = UnityWebRequest.kHttpVerbPOST; www.SetRequestHeader("Content-Type", "application/json"); System.DateTime sendTime = System.DateTime.UtcNow; yield return www.SendWebRequest(); if (VerboseURI) Debug.LogFormat("Server answerd in : {0}ms" , (System.DateTime.UtcNow - sendTime).TotalMilliseconds); if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError) { Debug.Log(www.error); currentMmtAnswer = null; } else { string answer = www.downloadHandler.text; currentMmtAnswer = answer; } string prepareScrollAssignments() { List<ScrollAssignment> assignmentList = new(); for (int i = 0; i < ParameterDisplays.Count; i++) { Fact tempFact = ParameterDisplays[i].Fact; if (tempFact != null) assignmentList.Add(new ScrollAssignment(ActiveScroll.requiredFacts[i].@ref.uri, tempFact.Id)); } return JsonConvert.SerializeObject(new FilledScroll(ActiveScroll.@ref, assignmentList)); } } private void ReadPushout(List<MMTDeclaration> pushoutFacts) { Popup.HidePopUp(); //close error Window bool samestep = false; for (int i = 0; i < pushoutFacts.Count; i++) { Fact newFact = ParsingDictionary.parseFactDictionary[pushoutFacts[i].getType()].Invoke(pushoutFacts[i]); if (newFact != null) { AnimateExistingFactEvent.Invoke (FactManager.AddFactIfNotFound(newFact, out _, samestep, null, ActiveScroll.label).Id , FactWrapper.FactMaterials.Solution); samestep = true; } else Debug.Log("Parsing on pushout-fact returned null -> One of the dependent facts does not exist"); } } private void processScrollDynamicInfo(ScrollDynamicInfo scrollDynamicInfo) { LatestCompletions = scrollDynamicInfo.completions.Count > 0 ? scrollDynamicInfo.completions[0] : new List<ScrollAssignment>(); List<string> hintUris = LatestCompletions .Select(completion => completion.fact.uri) .ToList(); //Update Scroll, process data for later hints and update Uri-List for which hints are available _processRenderedScroll(scrollDynamicInfo.rendered, hintUris); if (AutomaticHintGenerationActive) //Show that Hint is available for ScrollParameter HintAvailableEvent.Invoke(hintUris); return; void _processRenderedScroll(Scroll rendered, List<string> hintUris) { if (DynamicScrollDescriptionsActive) { // Update scroll-description Transform scroll = gameObject.transform.GetChild(1).transform; scroll.GetChild(0).GetComponent<TextMeshProUGUI>().text = rendered.description; } LatestRenderedHints = new(); for (int i = 0; i < rendered.requiredFacts.Count; i++) { RenderedScrollFact RenderedScrollFact = ParameterDisplays .Find(RSF => RSF.ScrollFactURI == rendered.requiredFacts[i].@ref.uri); if (DynamicScrollDescriptionsActive) //Update ScrollParameter label RenderedScrollFact.Scroll = rendered; //If ScrollFact is assigned -> No Hint if (!RenderedScrollFact.IsSet) { Fact HintFact = ParsingDictionary.parseFactDictionary[rendered.requiredFacts[i].getType()] .Invoke(rendered.requiredFacts[i]); //If the fact could not be parsed -> Therefore not all dependent Facts exist -> No Hint if (HintFact != null) { hintUris.Add(HintFact.Id); LatestRenderedHints.Add(HintFact); } } } return; } } public void animateHint(string scrollParameterUri) { if (FactOrganizer.AllFacts.ContainsKey(scrollParameterUri)) AnimateExistingFactEvent.Invoke( scrollParameterUri, FactWrapper.FactMaterials.Hint ); Fact hintFact = LatestRenderedHints.Find(x => x.Id == scrollParameterUri); ScrollAssignment suitableCompletion = LatestCompletions.Find(x => x.fact.uri == scrollParameterUri); if (suitableCompletion != null) { if (FactOrganizer.AllFacts.ContainsKey(suitableCompletion.assignment.uri)) { AnimateExistingFactEvent.Invoke( suitableCompletion.assignment.uri, FactWrapper.FactMaterials.Hint ); } } else if (hintFact != null) { if (FactOrganizer.FindEquivalent(StageStatic.stage.factState.MyFactSpace, hintFact, out string found_key, out Fact _, out bool _, false)) // existing fact -> Animate that AnimateExistingFactEvent.Invoke( found_key, FactWrapper.FactMaterials.Hint ); else { // Generate new FactRepresentation and animate it AnimateNonExistingFactEvent.Invoke(hintFact); AnimateExistingFactEvent.Invoke( scrollParameterUri, FactWrapper.FactMaterials.Hint ); } } } }