Decompiled source of JustEnoughDrugs v2.0.0

JustEnoughDrugs.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using JustEnoughDrugs;
using JustEnoughDrugs.Models;
using JustEnoughDrugs.UI;
using JustEnoughDrugs.Utils;
using MelonLoader;
using MelonLoader.Preferences;
using ScheduleOne;
using ScheduleOne.DevUtilities;
using ScheduleOne.ItemFramework;
using ScheduleOne.Product;
using ScheduleOne.Properties;
using ScheduleOne.StationFramework;
using ScheduleOne.UI.Tooltips;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(MainMod), "JustEnoughDrugs", "2.0.0", "BrandSEPI", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("JustEnoughDrugs")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a9522fefe3db71d8ee971f558c14401226a2a0a7")]
[assembly: AssemblyProduct("JustEnoughDrugs")]
[assembly: AssemblyTitle("JustEnoughDrugs")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace JustEnoughDrugs
{
	public static class BuildInfo
	{
		public const string Name = "JustEnoughDrugs";

		public const string Description = "Filter drugs by name, ingredients or effects and sort them !";

		public const string Author = "BrandSEPI";

		public const string Company = null;

		public const string Version = "2.0.0";

		public const string DownloadLink = null;
	}
	public class MainMod : MelonMod
	{
		[HarmonyPatch(typeof(ProductDefinition), "AddRecipe")]
		public class ProductDefinition_AddRecipe_Patch
		{
			private static void Postfix(ProductDefinition __instance)
			{
				RecipeManager.ProcessNewRecipe(__instance);
			}
		}

		[HarmonyPatch(typeof(ProductEntry), "Clicked")]
		public class ProductEntry_Clicked_Patch
		{
			private static void Postfix(ProductEntry __instance)
			{
				uiManager.DetailClicked(__instance);
			}
		}

		[CompilerGenerated]
		private sealed class <InitAfterSceneLoaded>d__6 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public MainMod <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <InitAfterSceneLoaded>d__6(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					MelonLogger.Msg("Initializing JustEnoughDrugs...");
					uiManager = new UIManager();
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (!<>4__this.isInitialized)
				{
					<>4__this.isInitialized = uiManager.Initialize();
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private bool isInitialized = false;

		private static UIManager uiManager;

		public static Dictionary<ProductDefinition, float> ProductCosts = new Dictionary<ProductDefinition, float>();

		public static Dictionary<ProductDefinition, List<PropertyItemDefinition>> ExtendedRecipes = new Dictionary<ProductDefinition, List<PropertyItemDefinition>>();

		public override void OnInitializeMelon()
		{
			ModConfig.Setup();
		}

		public override void OnSceneWasInitialized(int buildIndex, string sceneName)
		{
			isInitialized = false;
			if (sceneName == "Main")
			{
				MelonCoroutines.Start(InitAfterSceneLoaded());
			}
		}

		[IteratorStateMachine(typeof(<InitAfterSceneLoaded>d__6))]
		private IEnumerator InitAfterSceneLoaded()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InitAfterSceneLoaded>d__6(0)
			{
				<>4__this = this
			};
		}

		public override void OnUpdate()
		{
			if (isInitialized)
			{
				uiManager.Update();
			}
		}
	}
	public static class ModConfig
	{
		private static MelonPreferences_Category category;

		private static MelonPreferences_Entry<bool> EnableDrugSortingEntry;

		private static MelonPreferences_Entry<bool> ShowFullRecipeEntry;

		public static bool EnableDrugSorting => EnableDrugSortingEntry.Value;

		public static bool ShowFullRecipe => ShowFullRecipeEntry.Value;

		public static void Setup()
		{
			category = MelonPreferences.CreateCategory("JustEnoughDrugs", "Just Enough Drugs Settings");
			EnableDrugSortingEntry = category.CreateEntry<bool>("EnableDrugSorting", true, "Enable Drug Sorting", "Enables the sorting functionality for drugs in the product manager.", false, false, (ValueValidator)null, (string)null);
			ShowFullRecipeEntry = category.CreateEntry<bool>("ShowFullRecipe", true, "Show Full Recipe", "Displays the full recursive recipe for products when selected.", false, false, (ValueValidator)null, (string)null);
			MelonPreferences.Save();
		}
	}
}
namespace JustEnoughDrugs.Utils
{
	public static class TransformExtensions
	{
		public static Transform FindChildByPath(Transform parent, string path)
		{
			Transform val = parent;
			string[] array = path.Split(new char[1] { '/' });
			foreach (string text in array)
			{
				val = val.Find(text);
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
			}
			return val;
		}
	}
}
namespace JustEnoughDrugs.UI
{
	public class DrugListUI
	{
		[CompilerGenerated]
		private sealed class <DelayedLayoutRebuild>d__7 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public DrugListUI <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedLayoutRebuild>d__7(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Expected O, but got Unknown
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if ((Object)(object)<>4__this.drugItems != (Object)null)
					{
						Canvas.ForceUpdateCanvases();
						LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)<>4__this.drugItems);
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private Transform drugItems;

		private DrugSearcher searcher;

		private DrugSorter sorter;

		public bool Initialize(Transform productManagerAppTransform)
		{
			try
			{
				drugItems = GetDrugListTransform(productManagerAppTransform);
				searcher = new DrugSearcher();
				sorter = new DrugSorter();
				if ((Object)(object)drugItems != (Object)null)
				{
					MelonLogger.Msg("Drug list found and initialized.");
					return true;
				}
				MelonLogger.Error("Failed to find drug list transform.");
				return false;
			}
			catch (Exception arg)
			{
				MelonLogger.Error($"Error initializing drug list: {arg}");
				return false;
			}
		}

		private Transform GetDrugListTransform(Transform productManagerAppTransform)
		{
			if ((Object)(object)productManagerAppTransform == (Object)null)
			{
				MelonLogger.Error("Product Manager App transform is null.");
				return null;
			}
			Transform val = TransformExtensions.FindChildByPath(productManagerAppTransform, "Container/Scroll View/Viewport/Content");
			if ((Object)(object)val == (Object)null)
			{
				MelonLogger.Error("Could not find drug list in hierarchy.");
				return null;
			}
			MelonLogger.Msg("Drug list component accessed successfully.");
			return val;
		}

		public void UpdateDrugDisplay(string searchText, string filterKey)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			if ((Object)(object)drugItems == (Object)null)
			{
				MelonLogger.Error("Cannot update drug display: drug items is null.");
				return;
			}
			HideOutline();
			foreach (Transform drugItem in drugItems)
			{
				Transform val = drugItem;
				bool flag = false;
				foreach (Transform item in val)
				{
					Transform val2 = item;
					foreach (Transform item2 in val2)
					{
						Transform val3 = item2;
						ProductEntry component = ((Component)val3).GetComponent<ProductEntry>();
						if ((Object)(object)component != (Object)null && (Object)(object)component.Definition != (Object)null)
						{
							bool flag2 = searcher.ShouldShowDrug(component, searchText, filterKey);
							if (((Component)val3).gameObject.activeSelf != flag2)
							{
								((Component)val3).gameObject.SetActive(flag2);
							}
							if (!flag)
							{
								flag = flag2;
							}
						}
						else
						{
							((Component)val3).gameObject.SetActive(false);
						}
					}
				}
				Transform val4 = val.Find("None");
				Transform val5 = val.Find("Entries");
				if ((Object)(object)val4 != (Object)null && (Object)(object)val5 != (Object)null)
				{
					((Component)val4).gameObject.SetActive(!flag);
					((Component)val5).gameObject.SetActive(flag);
				}
			}
			MelonLogger.Msg("updated drug display with search text: " + searchText + " and filter key: " + filterKey);
			MonoBehaviour obj = Object.FindObjectOfType<MonoBehaviour>();
			if (obj != null)
			{
				obj.StartCoroutine(DelayedLayoutRebuild());
			}
		}

		public void ReorderDrugs(string sorterType, string sortOrder)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			if ((Object)(object)drugItems == (Object)null || sorterType == "None")
			{
				return;
			}
			MelonLogger.Msg("Reordering drugs by " + sorterType + " in " + sortOrder + " order");
			DrugSorter.SorterType sorterType2 = (DrugSorter.SorterType)Enum.Parse(typeof(DrugSorter.SorterType), sorterType);
			DrugSorter.SortOrder sortOrder2 = (DrugSorter.SortOrder)Enum.Parse(typeof(DrugSorter.SortOrder), sortOrder);
			foreach (Transform drugItem in drugItems)
			{
				Transform val = drugItem;
				foreach (Transform item in val)
				{
					Transform val2 = item;
					List<ProductEntry> list = new List<ProductEntry>();
					Dictionary<ProductEntry, Transform> dictionary = new Dictionary<ProductEntry, Transform>();
					foreach (Transform item2 in val2)
					{
						Transform val3 = item2;
						if (((Component)val3).gameObject.activeSelf)
						{
							ProductEntry component = ((Component)val3).GetComponent<ProductEntry>();
							if ((Object)(object)component != (Object)null && (Object)(object)component.Definition != (Object)null)
							{
								list.Add(component);
								dictionary.Add(component, val3);
							}
						}
					}
					List<ProductEntry> list2 = DrugSorter.SortDrugs(list, sorterType2, sortOrder2);
					for (int i = 0; i < list2.Count; i++)
					{
						Transform val4 = dictionary[list2[i]];
						val4.SetSiblingIndex(i);
					}
				}
			}
			MonoBehaviour obj = Object.FindObjectOfType<MonoBehaviour>();
			if (obj != null)
			{
				obj.StartCoroutine(DelayedLayoutRebuild());
			}
		}

		[IteratorStateMachine(typeof(<DelayedLayoutRebuild>d__7))]
		private IEnumerator DelayedLayoutRebuild()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedLayoutRebuild>d__7(0)
			{
				<>4__this = this
			};
		}

		private void HideOutline()
		{
			Transform val = drugItems.Find("Outline");
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(false);
			}
		}
	}
	public class FilterDropdownUI
	{
		private Dropdown dropdown;

		private readonly List<string> filterOptions = new List<string> { "Any", "Name", "Effects", "Ingredients" };

		private readonly string GOName = "SearchDropdown";

		public string CurrentFilter => ((Object)(object)dropdown != (Object)null) ? filterOptions[dropdown.value] : "Any";

		public event Action<string> OnFilterChanged;

		public bool Initialize(Transform parent)
		{
			try
			{
				dropdown = SetupDropdown(parent);
				return (Object)(object)dropdown != (Object)null;
			}
			catch (Exception arg)
			{
				MelonLogger.Error($"Error initializing filter dropdown: {arg}");
				return false;
			}
		}

		private Dropdown SetupDropdown(Transform parent)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			GameObject val = GameObject.Find("DeliveryApp");
			if ((Object)(object)val == (Object)null)
			{
				throw new Exception("DeliveryApp not found.");
			}
			Dropdown component = ((Component)TransformExtensions.FindChildByPath(val.transform, "Container/Scroll View/Viewport/Content/Dan's Hardware/Contents/Panel/Destination/Dropdown (Legacy)")).GetComponent<Dropdown>();
			if ((Object)(object)component == (Object)null)
			{
				throw new Exception("Original dropdown not found.");
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)component).gameObject);
			if ((Object)(object)val2 == (Object)null)
			{
				throw new Exception("Failed to clone dropdown.");
			}
			((Object)val2).name = GOName;
			val2.transform.SetParent(parent, false);
			Dropdown component2 = val2.GetComponent<Dropdown>();
			RectTransform component3 = val2.GetComponent<RectTransform>();
			component3.sizeDelta = new Vector2(-1030f, 60f);
			component3.anchoredPosition = new Vector2(100f, 30f);
			component2.ClearOptions();
			foreach (string filterOption in filterOptions)
			{
				component2.options.Add(new OptionData(filterOption));
			}
			((UnityEvent<int>)(object)component2.onValueChanged).AddListener((UnityAction<int>)delegate(int index)
			{
				OnDropdownValueChanged(index);
			});
			return component2;
		}

		private void OnDropdownValueChanged(int index)
		{
			this.OnFilterChanged?.Invoke(filterOptions[index]);
			MelonLogger.Msg("Filter changed to: " + filterOptions[index]);
		}
	}
	public class RecipeUI
	{
		private const int ITEMS_PER_ROW = 5;

		private const float INGREDIENT_SIZE = 50f;

		private const float SEPARATOR_SIZE = 24f;

		private const float ROW_SPACING = 5f;

		private const float ITEM_SPACING = 10f;

		public void BuildFullRecipe(Transform parent, List<PropertyItemDefinition> recipe, PropertyItemDefinition definition)
		{
			GameObject val = CreateRecipeContainer(parent);
			for (int i = 0; i < recipe.Count; i++)
			{
				GameObject orCreateRow = GetOrCreateRow(val.transform, i);
				AddIngredientToLine(orCreateRow.transform, recipe[i]);
				bool flag = i == recipe.Count - 1;
				bool flag2 = (i + 1) % 5 == 0;
				if (!flag2 || flag)
				{
					AddSeparator(orCreateRow.transform, flag);
				}
				if (flag)
				{
					AddResultIcon(orCreateRow.transform, definition);
				}
			}
		}

		private GameObject CreateRecipeContainer(Transform parent)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			GameObject val = new GameObject("FullRecipeValue", new Type[2]
			{
				typeof(RectTransform),
				typeof(VerticalLayoutGroup)
			});
			val.transform.SetParent(parent, false);
			VerticalLayoutGroup component = val.GetComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)component).spacing = 5f;
			((LayoutGroup)component).childAlignment = (TextAnchor)3;
			((HorizontalOrVerticalLayoutGroup)component).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)component).childForceExpandWidth = false;
			return val;
		}

		private GameObject GetOrCreateRow(Transform parent, int itemIndex)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			int num = itemIndex / 5;
			string text = $"Line_{num}";
			Transform val = parent.Find(text);
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).gameObject;
			}
			GameObject val2 = new GameObject(text, new Type[2]
			{
				typeof(RectTransform),
				typeof(HorizontalLayoutGroup)
			});
			val2.transform.SetParent(parent, false);
			HorizontalLayoutGroup component = val2.GetComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)component).spacing = 10f;
			((LayoutGroup)component).childAlignment = (TextAnchor)3;
			((HorizontalOrVerticalLayoutGroup)component).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)component).childForceExpandWidth = false;
			return val2;
		}

		private void AddIngredientToLine(Transform lineParent, PropertyItemDefinition ingredient)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(((Object)ingredient).name, new Type[1] { typeof(Image) });
			val.transform.SetParent(lineParent, false);
			Tooltip val2 = val.AddComponent<Tooltip>();
			val2.text = ((ItemDefinition)ingredient).Name;
			Image component = val.GetComponent<Image>();
			component.sprite = ((ItemDefinition)ingredient).Icon;
			component.preserveAspect = true;
			((Graphic)component).rectTransform.sizeDelta = new Vector2(50f, 50f);
		}

		private void AddSeparator(Transform lineParent, bool isLastIngredient)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			string text = (isLastIngredient ? "Arrow" : "Plus");
			GameObject val = GameObject.Find("RecipesContainer");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform child = val.transform.GetChild(0);
			Transform val2 = child.Find(text);
			if (!((Object)(object)val2 == (Object)null))
			{
				Transform val3 = Object.Instantiate<Transform>(val2);
				((Component)val3).transform.SetParent(lineParent, false);
				RectTransform component = ((Component)val3).GetComponent<RectTransform>();
				if ((Object)(object)component != (Object)null)
				{
					component.sizeDelta = new Vector2(24f, 24f);
					((Transform)component).localScale = new Vector3(0.5f, 0.5f, 0.5f);
				}
			}
		}

		private void AddResultIcon(Transform lineParent, PropertyItemDefinition definition)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(((Object)definition).name + "_Result", new Type[1] { typeof(Image) });
			val.transform.SetParent(lineParent, false);
			Image component = val.GetComponent<Image>();
			Tooltip val2 = val.AddComponent<Tooltip>();
			val2.text = ((ItemDefinition)definition).Name;
			component.sprite = ((ItemDefinition)definition).Icon;
			component.preserveAspect = true;
			((Graphic)component).rectTransform.sizeDelta = new Vector2(50f, 50f);
		}
	}
	public class SearchBarUI
	{
		private InputField inputField;

		private bool wasFocusedLastFrame = false;

		public string SearchText
		{
			get
			{
				InputField obj = inputField;
				return ((obj != null) ? obj.text : null) ?? string.Empty;
			}
		}

		public event Action<string> OnSearchChanged;

		public event Action<bool> OnFocusChanged;

		public bool Initialize(Transform parent)
		{
			try
			{
				inputField = CreateSearchBar(parent);
				return (Object)(object)inputField != (Object)null;
			}
			catch (Exception arg)
			{
				MelonLogger.Error($"Error initializing search bar: {arg}");
				return false;
			}
		}

		public void Update()
		{
			if ((Object)(object)inputField == (Object)null)
			{
				return;
			}
			bool isFocused = inputField.isFocused;
			if (isFocused != wasFocusedLastFrame)
			{
				this.OnFocusChanged?.Invoke(isFocused);
				if (isFocused)
				{
					MelonLogger.Msg("Input field focused.");
				}
				else
				{
					MelonLogger.Msg("Input field lost focus.");
				}
			}
			wasFocusedLastFrame = isFocused;
		}

		private InputField CreateSearchBar(Transform parent)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("DrugSearchInput");
			val.transform.SetParent(parent, false);
			val.AddComponent<CanvasRenderer>();
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchorMin = new Vector2(1f, 1f);
			val2.anchorMax = new Vector2(1f, 1f);
			val2.pivot = new Vector2(1f, 1f);
			val2.sizeDelta = new Vector2(415f, 60f);
			Image val3 = val.AddComponent<Image>();
			((Graphic)val3).color = new Color(1f, 1f, 1f, 0.9f);
			InputField val4 = val.AddComponent<InputField>();
			CreatePlaceholder(val, val4);
			CreateTextComponent(val, val4);
			CreateClearButton(val);
			((UnityEvent<string>)(object)val4.onValueChanged).AddListener((UnityAction<string>)delegate(string value)
			{
				OnSearchTextChanged(value);
			});
			return val4;
		}

		private void CreatePlaceholder(GameObject parent, InputField inputField)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Placeholder");
			val.transform.SetParent(parent.transform, false);
			Text val2 = val.AddComponent<Text>();
			val2.text = "Search";
			val2.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			val2.fontSize = 30;
			((Graphic)val2).color = Color.gray;
			val2.alignment = (TextAnchor)3;
			RectTransform component = ((Component)val2).GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = new Vector2(10f, 5f);
			component.offsetMax = new Vector2(-10f, -5f);
			inputField.placeholder = (Graphic)(object)val2;
		}

		private void CreateTextComponent(GameObject parent, InputField inputField)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Text");
			val.transform.SetParent(parent.transform, false);
			Text val2 = val.AddComponent<Text>();
			val2.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			val2.fontSize = 22;
			((Graphic)val2).color = Color.black;
			val2.alignment = (TextAnchor)3;
			RectTransform component = ((Component)val2).GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = new Vector2(10f, 5f);
			component.offsetMax = new Vector2(-10f, -5f);
			inputField.textComponent = val2;
			inputField.text = "";
			inputField.ForceLabelUpdate();
		}

		private void CreateClearButton(GameObject parent)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			GameObject val = new GameObject("ClearButton");
			val.transform.SetParent(parent.transform, false);
			Text val2 = val.AddComponent<Text>();
			val2.text = "X";
			val2.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			val2.fontSize = 30;
			((Graphic)val2).color = Color.red;
			val2.alignment = (TextAnchor)4;
			RectTransform component = val.GetComponent<RectTransform>();
			component.sizeDelta = new Vector2(40f, 40f);
			component.anchorMin = new Vector2(1f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.anchoredPosition = new Vector2(-15f, -30f);
			Button val3 = val.AddComponent<Button>();
			((UnityEvent)val3.onClick).AddListener((UnityAction)delegate
			{
				ClearSearchText();
			});
		}

		private void ClearSearchText()
		{
			inputField.text = "";
		}

		private void OnSearchTextChanged(string value)
		{
			this.OnSearchChanged?.Invoke(value);
		}
	}
	public class SorterDropDownUI
	{
		private Dropdown sorterDropdown;

		private Dropdown orderDropdown;

		private readonly List<string> sorterOptions = new List<string> { "Newest", "Addictiveness", "Cost", "Price", "Profit" };

		private readonly List<string> sortOrderOptions = new List<string> { "Asc", "Desc" };

		private readonly string sorterDropdownName = "SorterDropdown";

		private readonly string orderDropdownName = "SortOrderDropdown";

		public string CurrentSorter => ((Object)(object)sorterDropdown != (Object)null) ? sorterOptions[sorterDropdown.value] : "Newest";

		public string CurrentOrder => ((Object)(object)orderDropdown != (Object)null) ? sortOrderOptions[orderDropdown.value] : "Asc";

		public event Action<string, string> OnSorterChanged;

		public bool Initialize(Transform parent)
		{
			try
			{
				(sorterDropdown, orderDropdown) = SetupDropdowns(parent);
				return (Object)(object)sorterDropdown != (Object)null && (Object)(object)orderDropdown != (Object)null;
			}
			catch (Exception arg)
			{
				MelonLogger.Error($"Error initializing sorter dropdowns: {arg}");
				return false;
			}
		}

		private (Dropdown, Dropdown) SetupDropdowns(Transform parent)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Expected O, but got Unknown
			GameObject val = GameObject.Find("DeliveryApp");
			if ((Object)(object)val == (Object)null)
			{
				throw new Exception("DeliveryApp not found.");
			}
			Dropdown component = ((Component)TransformExtensions.FindChildByPath(val.transform, "Container/Scroll View/Viewport/Content/Dan's Hardware/Contents/Panel/Destination/Dropdown (Legacy)")).GetComponent<Dropdown>();
			if ((Object)(object)component == (Object)null)
			{
				throw new Exception("Original dropdown not found.");
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)component).gameObject);
			if ((Object)(object)val2 == (Object)null)
			{
				throw new Exception("Failed to clone sorter dropdown.");
			}
			((Object)val2).name = sorterDropdownName;
			val2.transform.SetParent(parent, false);
			Dropdown component2 = val2.GetComponent<Dropdown>();
			RectTransform component3 = val2.GetComponent<RectTransform>();
			component3.sizeDelta = new Vector2(-1030f, 60f);
			component3.anchoredPosition = new Vector2(-285f, 30f);
			component2.ClearOptions();
			foreach (string sorterOption in sorterOptions)
			{
				component2.options.Add(new OptionData(sorterOption));
			}
			GameObject val3 = Object.Instantiate<GameObject>(((Component)component).gameObject);
			if ((Object)(object)val3 == (Object)null)
			{
				throw new Exception("Failed to clone order dropdown.");
			}
			((Object)val3).name = orderDropdownName;
			val3.transform.SetParent(parent, false);
			Dropdown component4 = val3.GetComponent<Dropdown>();
			RectTransform component5 = val3.GetComponent<RectTransform>();
			component5.sizeDelta = new Vector2(-1030f, 60f);
			component5.anchoredPosition = new Vector2(-115f, 30f);
			component5.offsetMax = new Vector2(-700f, 60f);
			component4.ClearOptions();
			foreach (string sortOrderOption in sortOrderOptions)
			{
				component4.options.Add(new OptionData(sortOrderOption));
			}
			((UnityEvent<int>)(object)component2.onValueChanged).AddListener((UnityAction<int>)delegate
			{
				OnDropdownValueChanged();
			});
			((UnityEvent<int>)(object)component4.onValueChanged).AddListener((UnityAction<int>)delegate
			{
				OnDropdownValueChanged();
			});
			return (component2, component4);
		}

		private void OnDropdownValueChanged()
		{
			string currentSorter = CurrentSorter;
			string currentOrder = CurrentOrder;
			this.OnSorterChanged?.Invoke(currentSorter, currentOrder);
			MelonLogger.Msg("Sort changed to: " + currentSorter + " (" + currentOrder + ")");
		}
	}
	public class UIManager
	{
		private SearchBarUI searchBar;

		private FilterDropdownUI filterDropdown;

		private SorterDropDownUI sorterDropdown;

		private DrugListUI drugList;

		private RecipeUI recipeUI;

		private List<InputAction> disabledActions = new List<InputAction>();

		public bool Initialize()
		{
			GameObject val = GameObject.Find("ProductManagerApp");
			if ((Object)(object)val == (Object)null || !val.activeInHierarchy)
			{
				return false;
			}
			Transform val2 = TransformExtensions.FindChildByPath(val.transform, "Container/Topbar");
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			searchBar = new SearchBarUI();
			filterDropdown = new FilterDropdownUI();
			sorterDropdown = new SorterDropDownUI();
			drugList = new DrugListUI();
			recipeUI = new RecipeUI();
			bool flag = searchBar.Initialize(val2);
			bool flag2 = filterDropdown.Initialize(val2);
			bool flag3 = false;
			if (ModConfig.EnableDrugSorting)
			{
				flag3 = sorterDropdown.Initialize(val2);
			}
			bool flag4 = drugList.Initialize(val.transform);
			if (flag && flag2 && flag4 && (flag3 || !ModConfig.EnableDrugSorting))
			{
				searchBar.OnSearchChanged += HandleSearchChanged;
				filterDropdown.OnFilterChanged += HandleFilterChanged;
				searchBar.OnFocusChanged += HandleSearchFocus;
				if (ModConfig.EnableDrugSorting)
				{
					sorterDropdown.OnSorterChanged += HandleSorterChanged;
				}
			}
			return flag && flag2 && flag4 && (flag3 || !ModConfig.EnableDrugSorting);
		}

		public void Update()
		{
			searchBar?.Update();
		}

		private void HandleSearchChanged(string searchText)
		{
			drugList.UpdateDrugDisplay(searchText, filterDropdown.CurrentFilter);
		}

		private void HandleFilterChanged(string filter)
		{
			drugList.UpdateDrugDisplay(searchBar.SearchText, filter);
		}

		private void HandleSorterChanged(string sorterType, string sortOrder)
		{
			drugList.ReorderDrugs(sorterType, sortOrder);
		}

		private void HandleSearchFocus(bool focused)
		{
			if (focused)
			{
				DisableShortcuts();
			}
			else
			{
				RestoreShortcuts();
			}
		}

		public GameObject AddTextElement(string name, string content, Transform parent, int siblingIndex, Color color, int fontSize)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			Text val2 = val.AddComponent<Text>();
			val2.text = content;
			val2.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			val2.fontSize = fontSize;
			((Graphic)val2).color = color;
			val2.alignment = (TextAnchor)0;
			RectTransform component = ((Component)val2).GetComponent<RectTransform>();
			component.sizeDelta = new Vector2(300f, 30f);
			val2.horizontalOverflow = (HorizontalWrapMode)0;
			val2.verticalOverflow = (VerticalWrapMode)1;
			if (siblingIndex >= 0)
			{
				val.transform.SetSiblingIndex(siblingIndex);
			}
			else
			{
				val.transform.SetAsLastSibling();
			}
			return val;
		}

		private void DisableShortcuts()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			GameInput instance = Singleton<GameInput>.Instance;
			PlayerInput playerInput = instance.PlayerInput;
			foreach (InputAction action in playerInput.actions)
			{
				string text = string.Join(",", ((IEnumerable<InputBinding>)(object)action.bindings).Select((InputBinding b) => ((InputBinding)(ref b)).path));
				if (!text.Contains("/keyboard/tab") && !text.Contains("/keyboard/escape") && !text.Contains("/mouse/rightButton") && action.enabled)
				{
					action.Disable();
					disabledActions.Add(action);
				}
			}
		}

		private void RestoreShortcuts()
		{
			foreach (InputAction disabledAction in disabledActions)
			{
				disabledAction.Enable();
			}
			disabledActions.Clear();
		}

		public void DetailClicked(ProductEntry product)
		{
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			MelonLogger.Msg(((ItemDefinition)product.Definition).Name + " clicked");
			if ((Object)(object)((product != null) ? product.Definition : null) == (Object)null)
			{
				return;
			}
			ProductDefinition definition = product.Definition;
			GameObject val = GameObject.Find("ProductManagerApp/Container/Details/Scroll View/Viewport/Content");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			string[] array = new string[4] { "CostDisplay", "FullRecipeTitle", "FullRecipeList", "FullRecipeValue" };
			string[] array2 = array;
			foreach (string text in array2)
			{
				Transform val2 = val.transform.Find(text);
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)val2).gameObject);
				}
			}
			if (MainMod.ProductCosts.TryGetValue(definition, out var value))
			{
				GameObject val3 = AddTextElement("CostDisplay", "ingredient costs:", val.transform, 3, Color.white, 16);
				GameObject val4 = AddTextElement("CostValue", $"${value}", val3.transform, 3, Color.white, 14);
				RectTransform component = val4.GetComponent<RectTransform>();
				component.anchoredPosition = new Vector2(78f, 0f);
			}
			if (ModConfig.ShowFullRecipe)
			{
				AddTextElement("FullRecipeTitle", "Full recipe(s) :", val.transform, -1, Color.white, 16);
				if (MainMod.ExtendedRecipes.TryGetValue(definition, out var value2) && value2.Count > 0)
				{
					recipeUI.BuildFullRecipe(val.transform, value2, (PropertyItemDefinition)(object)definition);
				}
			}
			Transform val5 = val.transform.Find("Space");
			if ((Object)(object)val5 != (Object)null)
			{
				val5.SetAsLastSibling();
			}
		}
	}
}
namespace JustEnoughDrugs.Models
{
	public class DrugSearcher
	{
		public enum SearchFilter
		{
			Any,
			Ingredients,
			Effects,
			Name
		}

		public bool ShouldShowDrug(ProductEntry productEntry, string searchText, string filterKey)
		{
			if (string.IsNullOrEmpty(searchText))
			{
				return true;
			}
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			if (filterKey == SearchFilter.Effects.ToString() || filterKey == SearchFilter.Any.ToString())
			{
				flag = MatchesEffects(productEntry, searchText);
			}
			if (filterKey == SearchFilter.Ingredients.ToString() || filterKey == SearchFilter.Any.ToString())
			{
				flag3 = MatchesIngredients(productEntry, searchText);
			}
			if (filterKey == SearchFilter.Name.ToString() || filterKey == SearchFilter.Any.ToString())
			{
				flag2 = MatchesName(productEntry, searchText);
			}
			return flag2 || flag || flag3;
		}

		private bool MatchesName(ProductEntry entry, string searchText)
		{
			string item = ((object)entry.Definition).ToString().ToLowerInvariant();
			return MatchesSearch(new List<string> { item }, searchText);
		}

		private bool MatchesEffects(ProductEntry entry, string searchText)
		{
			List<string> effectList = new List<string>();
			((PropertyItemDefinition)entry.Definition).Properties.ForEach(delegate(Property p)
			{
				effectList.Add(((object)p).ToString().ToLowerInvariant());
			});
			return MatchesSearch(effectList, searchText);
		}

		private bool MatchesIngredients(ProductEntry entry, string searchText)
		{
			List<string> ingredientList = new List<string>();
			entry.Definition.Recipes.ForEach(delegate(StationRecipe r)
			{
				r.Ingredients.ForEach(delegate(IngredientQuantity i)
				{
					ingredientList.Add(((object)i.Item).ToString().ToLowerInvariant());
				});
			});
			return MatchesSearch(ingredientList, searchText);
		}

		private bool MatchesSearch(List<string> targetList, string searchText)
		{
			string AndChar = ",";
			string OrChar = "|";
			searchText = searchText.ToLowerInvariant();
			if (searchText.Contains(AndChar) && searchText.Split(AndChar.ToCharArray())[1] != "")
			{
				string[] source = searchText.Split(AndChar.ToCharArray());
				return source.All((string term) => targetList.Any((string target) => target.Contains(term.Trim())));
			}
			if (searchText.Contains(OrChar) && searchText.Split(OrChar.ToCharArray())[1] != "")
			{
				string[] source2 = searchText.Split(OrChar.ToCharArray());
				return source2.Any((string term) => targetList.Any((string target) => target.Contains(term.Trim())));
			}
			return targetList.Any((string target) => target.Contains(searchText.Replace(OrChar, "").Replace(AndChar, "").Trim()));
		}
	}
	public class DrugSorter
	{
		public enum SortOrder
		{
			Asc,
			Desc
		}

		public enum SorterType
		{
			Newest,
			Addictiveness,
			Cost,
			Price,
			Profit
		}

		public static List<ProductEntry> SortDrugs(List<ProductEntry> drugs, SorterType sorterType, SortOrder sortOrder)
		{
			return sorterType switch
			{
				SorterType.Addictiveness => SortByAddictiveness(drugs, sortOrder), 
				SorterType.Cost => SortByCost(drugs, sortOrder), 
				SorterType.Price => SortByPrice(drugs, sortOrder), 
				SorterType.Profit => SortByProfit(drugs, sortOrder), 
				SorterType.Newest => SortByNewest(drugs, sortOrder), 
				_ => drugs, 
			};
		}

		private static List<ProductEntry> SortByAddictiveness(List<ProductEntry> drugs, SortOrder sortOrder)
		{
			return (sortOrder == SortOrder.Asc) ? drugs.OrderBy((ProductEntry d) => d.Definition.GetAddictiveness()).ToList() : drugs.OrderByDescending((ProductEntry d) => d.Definition.GetAddictiveness()).ToList();
		}

		private static List<ProductEntry> SortByCost(List<ProductEntry> drugs, SortOrder sortOrder)
		{
			return (sortOrder == SortOrder.Asc) ? drugs.OrderBy(delegate(ProductEntry d)
			{
				MainMod.ProductCosts.TryGetValue(d.Definition, out var value2);
				return value2;
			}).ToList() : drugs.OrderByDescending(delegate(ProductEntry d)
			{
				MainMod.ProductCosts.TryGetValue(d.Definition, out var value);
				return value;
			}).ToList();
		}

		private static List<ProductEntry> SortByPrice(List<ProductEntry> drugs, SortOrder sortOrder)
		{
			return (sortOrder == SortOrder.Asc) ? drugs.OrderBy((ProductEntry d) => d.Definition.Price).ToList() : drugs.OrderByDescending((ProductEntry d) => d.Definition.Price).ToList();
		}

		private static List<ProductEntry> SortByProfit(List<ProductEntry> drugs, SortOrder sortOrder)
		{
			return (sortOrder == SortOrder.Asc) ? drugs.OrderBy(delegate(ProductEntry d)
			{
				MainMod.ProductCosts.TryGetValue(d.Definition, out var value2);
				return d.Definition.Price - value2;
			}).ToList() : drugs.OrderByDescending(delegate(ProductEntry d)
			{
				MainMod.ProductCosts.TryGetValue(d.Definition, out var value);
				return d.Definition.Price - value;
			}).ToList();
		}

		private static List<ProductEntry> SortByNewest(List<ProductEntry> drugs, SortOrder sortOrder)
		{
			List<ProductDefinition> allProducts = NetworkSingleton<ProductManager>.Instance.AllProducts;
			return (sortOrder == SortOrder.Asc) ? drugs.OrderBy((ProductEntry d) => allProducts.IndexOf(d.Definition)).ToList() : drugs.OrderByDescending((ProductEntry d) => allProducts.IndexOf(d.Definition)).ToList();
		}
	}
	public static class RecipeManager
	{
		public static void ProcessNewRecipe(ProductDefinition product)
		{
			if (!((Object)(object)product == (Object)null))
			{
				List<PropertyItemDefinition> list = DeepSearchRecipe(product);
				float value = CalculateTotalCost(list);
				MainMod.ProductCosts[product] = value;
				MainMod.ExtendedRecipes[product] = list;
			}
		}

		private static float CalculateTotalCost(List<PropertyItemDefinition> ingredients)
		{
			float num = 0f;
			foreach (PropertyItemDefinition ingredient in ingredients)
			{
				if (!(ingredient is ProductDefinition))
				{
					num += ((StorableItemDefinition)ingredient).BasePurchasePrice;
				}
			}
			return num;
		}

		public static List<PropertyItemDefinition> DeepSearchRecipe(ProductDefinition product)
		{
			List<PropertyItemDefinition> result = new List<PropertyItemDefinition>();
			DeepSearchRecursive(product, result, new List<ProductDefinition>());
			return result;
		}

		private static void DeepSearchRecursive(ProductDefinition product, List<PropertyItemDefinition> result, List<ProductDefinition> visited)
		{
			if ((Object)(object)product == (Object)null || visited.Contains(product))
			{
				return;
			}
			visited.Add(product);
			if (product.Recipes.Count == 0)
			{
				result.Insert(0, (PropertyItemDefinition)(object)product);
				return;
			}
			foreach (IngredientQuantity ingredient in product.Recipes[0].Ingredients)
			{
				ItemDefinition obj = ((ingredient != null) ? ingredient.Item : null);
				ProductDefinition val = (ProductDefinition)(object)((obj is ProductDefinition) ? obj : null);
				if (val != null)
				{
					DeepSearchRecursive(val, result, visited);
					continue;
				}
				ItemDefinition obj2 = ((ingredient != null) ? ingredient.Item : null);
				PropertyItemDefinition val2 = (PropertyItemDefinition)(object)((obj2 is PropertyItemDefinition) ? obj2 : null);
				if (val2 != null)
				{
					result.Add(val2);
				}
			}
		}
	}
}