Decompiled source of OrderAndOrganize v0.5.0

plugins\OrderAndOrganize\OrderAndOrganize.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using OrderAndOrganize.Configuration;
using OrderAndOrganize.Diagnostics;
using OrderAndOrganize.Game;
using OrderAndOrganize.Models;
using OrderAndOrganize.Patches;
using OrderAndOrganize.Services;
using OrderAndOrganize.UI;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("OrderAndOrganize")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a0eb83a8da5c37e61bc0621f5b234821dacba945")]
[assembly: AssemblyProduct("OrderAndOrganize")]
[assembly: AssemblyTitle("OrderAndOrganize")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace OrderAndOrganize
{
	[BepInPlugin("com.ddqminik.supermarkettogether.orderandorganize", "Order & Organize", "0.5.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.ddqminik.supermarkettogether.orderandorganize";

		public const string PluginName = "Order & Organize";

		public const string PluginVersion = "0.5.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		private ModConfiguration _config;

		private Harmony _harmony;

		private GameInventoryAdapter _inventoryAdapter;

		private GameProductCatalogAdapter _catalogAdapter;

		private GameShoppingListAdapter _shoppingListAdapter;

		private GamePurchaseAdapter _purchaseAdapter;

		private GameMoneyAdapter _moneyAdapter;

		private GameNotificationAdapter _notificationAdapter;

		private GameAuthorityAdapter _authorityAdapter;

		private GameUiAdapter _uiAdapter;

		private PendingOrderTracker _pendingTracker;

		private AutomationController _automationController;

		private OrderButtonController _buttonController;

		private GameApiDiagnostics _diagnostics;

		private ConfigWindow _configWindow;

		private CategoryMapper _categoryMapper;

		private CategoryShelfManager _categoryShelfManager;

		private CategoryPickerUI _categoryPickerUI;

		private bool _hasLoggedApiOnce;

		private float _storeLoadedTime;

		private const float DiagnosticsDelaySeconds = 5f;

		private bool _categoryMapperRebuilt;

		private float _lastStalePurgeTime;

		private float _sceneLoadedTime;

		private const float PurgeGracePeriodSeconds = 120f;

		private void Awake()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Order & Organize v0.5.0 loading...");
			MigrateFromOldVersion();
			_config = new ModConfiguration();
			_config.Bind(((BaseUnityPlugin)this).Config);
			if (!_config.Enabled.Value)
			{
				Log.LogInfo((object)"Plugin is disabled via configuration.");
				return;
			}
			InitializeAdapters();
			InitializeServices();
			InitializeCategoryShelves();
			CoroutineRunner.Initialize();
			_harmony = new Harmony("com.ddqminik.supermarkettogether.orderandorganize");
			_harmony.PatchAll();
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			Log.LogInfo((object)"Order & Organize v0.5.0 loaded successfully.");
		}

		private void InitializeAdapters()
		{
			_inventoryAdapter = new GameInventoryAdapter(Log);
			_catalogAdapter = new GameProductCatalogAdapter(Log);
			_shoppingListAdapter = new GameShoppingListAdapter(Log);
			_moneyAdapter = new GameMoneyAdapter(Log);
			_notificationAdapter = new GameNotificationAdapter(Log);
			_authorityAdapter = new GameAuthorityAdapter(Log);
			_uiAdapter = new GameUiAdapter(Log);
			_purchaseAdapter = new GamePurchaseAdapter(Log, _shoppingListAdapter, _moneyAdapter);
		}

		private void InitializeServices()
		{
			_pendingTracker = new PendingOrderTracker(Log);
			_automationController = new AutomationController(Log, _config, _authorityAdapter, _moneyAdapter, _purchaseAdapter, _catalogAdapter, _inventoryAdapter, _shoppingListAdapter, _notificationAdapter, _pendingTracker);
			_buttonController = new OrderButtonController(Log, _config, _catalogAdapter, _inventoryAdapter, _shoppingListAdapter, _notificationAdapter, _pendingTracker, () => _automationController.IsEnabled);
			_diagnostics = new GameApiDiagnostics(Log, _inventoryAdapter, _catalogAdapter, _shoppingListAdapter);
			_configWindow = new ConfigWindow(_config, () => _automationController.IsEnabled, delegate
			{
				_automationController.Toggle((MonoBehaviour)(object)this);
				_buttonController.UpdateAutoLabel();
			});
		}

		private void InitializeCategoryShelves()
		{
			_categoryMapper = new CategoryMapper(Log);
			string savePath = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), "OrderAndOrganize_CategoryShelves.json");
			_categoryShelfManager = new CategoryShelfManager(Log, _categoryMapper, savePath);
			_categoryPickerUI = new CategoryPickerUI(Log, _categoryShelfManager, _categoryMapper);
			_categoryPickerUI.LabelsVisible = _config.CategoryLabelsVisible.Value;
			CategoryStoragePatches.ShelfManager = _categoryShelfManager;
			CategoryStoragePatches.CategoryMapper = _categoryMapper;
			CategoryStoragePatches.Enabled = _config.CategoryShelvesEnabled.Value;
			_config.CategoryShelvesEnabled.SettingChanged += delegate
			{
				CategoryStoragePatches.Enabled = _config.CategoryShelvesEnabled.Value;
				Log.LogInfo((object)("Category shelves " + (_config.CategoryShelvesEnabled.Value ? "enabled" : "disabled") + "."));
			};
			_config.CategoryLabelsVisible.SettingChanged += delegate
			{
				_categoryPickerUI.LabelsVisible = _config.CategoryLabelsVisible.Value;
			};
			Log.LogInfo((object)"Category storage shelves initialized.");
		}

		private void Update()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			if (!_config.Enabled.Value)
			{
				return;
			}
			if (_categoryPickerUI != null && _categoryPickerUI.IsPickerVisible)
			{
				_categoryPickerUI.UpdateInput();
				return;
			}
			if (Input.GetKeyDown(_config.ToggleHotkey.Value))
			{
				_automationController.Toggle((MonoBehaviour)(object)this);
				_buttonController.UpdateAutoLabel();
			}
			if (Input.GetKeyDown(_config.ConfigWindowHotkey.Value))
			{
				_configWindow?.Toggle();
			}
			if (_config.CategoryShelvesEnabled.Value && Input.GetKeyDown(_config.CategoryHotkey.Value))
			{
				_categoryPickerUI?.OnHotkeyPressed();
			}
			if (_config.CategoryShelvesEnabled.Value && Input.GetKeyDown(_config.CategoryLabelsToggleHotkey.Value) && _categoryPickerUI != null)
			{
				_categoryPickerUI.ToggleLabels();
				_config.CategoryLabelsVisible.Value = _categoryPickerUI.LabelsVisible;
			}
			if (!_categoryMapperRebuilt && (Object)(object)ProductListing.Instance != (Object)null && ProductListing.Instance.tiers != null && ProductListing.Instance.tiers.Length != 0)
			{
				_categoryMapperRebuilt = true;
				_categoryMapper.Rebuild();
			}
			if (_categoryShelfManager != null && _categoryShelfManager.AssignmentCount > 0 && (Object)(object)GameData.Instance != (Object)null && _sceneLoadedTime > 0f && Time.time - _sceneLoadedTime > 120f && Time.time - _lastStalePurgeTime > 60f)
			{
				_lastStalePurgeTime = Time.time;
				try
				{
					_categoryShelfManager.PurgeStaleAssignments();
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("Stale purge failed: " + ex.Message));
				}
			}
			HandleDiagnostics();
		}

		private void HandleDiagnostics()
		{
			if (_hasLoggedApiOnce || !_authorityAdapter.IsStoreLoaded())
			{
				return;
			}
			if (_storeLoadedTime <= 0f)
			{
				_storeLoadedTime = Time.time;
				_sceneLoadedTime = Time.time;
			}
			else if (!(Time.time - _storeLoadedTime < 5f))
			{
				_hasLoggedApiOnce = true;
				try
				{
					_diagnostics.LogResolvedApi();
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("API diagnostics failed: " + ex.Message));
				}
			}
		}

		private void OnGUI()
		{
			_configWindow?.Draw();
			if (_config.CategoryShelvesEnabled.Value)
			{
				_categoryPickerUI?.Draw();
			}
		}

		private void OnSceneUnloaded(Scene scene)
		{
			Log.LogInfo((object)("Scene unloaded: " + ((Scene)(ref scene)).name));
			_automationController.OnSceneUnload();
			_hasLoggedApiOnce = false;
			_storeLoadedTime = 0f;
			_sceneLoadedTime = 0f;
			_lastStalePurgeTime = 0f;
			_categoryMapperRebuilt = false;
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			SceneManager.sceneUnloaded -= OnSceneUnloaded;
			_pendingTracker?.ClearAll();
			Log.LogInfo((object)"Order & Organize unloaded.");
		}

		private void MigrateFromOldVersion()
		{
			try
			{
				string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath);
				if (!string.IsNullOrEmpty(directoryName))
				{
					string text = Path.Combine(directoryName, "com.dominik.supermarkettogether.smartrestock.cfg");
					string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
					if (File.Exists(text) && !File.Exists(configFilePath))
					{
						File.Copy(text, configFilePath);
						Log.LogInfo((object)("Migrated config from " + Path.GetFileName(text)));
					}
					string text2 = Path.Combine(directoryName, "SmartRestock_CategoryShelves.json");
					string text3 = Path.Combine(directoryName, "OrderAndOrganize_CategoryShelves.json");
					if (File.Exists(text2) && !File.Exists(text3))
					{
						File.Copy(text2, text3);
						Log.LogInfo((object)("Migrated category data from " + Path.GetFileName(text2)));
					}
					string text4 = text2 + ".backup";
					string text5 = text3 + ".backup";
					if (File.Exists(text4) && !File.Exists(text5))
					{
						File.Copy(text4, text5);
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Migration from old version failed: " + ex.Message));
			}
		}

		internal void OnOrderingUIInitialized()
		{
			_buttonController?.TryCreateButton();
		}

		internal void OnAutoStartup()
		{
			if (_config.AutoOrderAtStartup.Value)
			{
				_automationController.SetEnabled(enabled: true, (MonoBehaviour)(object)this);
				Log.LogInfo((object)"Automation auto-started per configuration.");
			}
		}
	}
	[HarmonyPatch]
	internal static class GamePatches
	{
		[HarmonyPatch(typeof(ProductListing), "OnStartClient")]
		[HarmonyPostfix]
		private static void OnProductListingStartClient()
		{
			try
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"ProductListing.OnStartClient fired - initializing Order & Organize UI.");
				}
				Plugin.Instance?.OnOrderingUIInitialized();
				Plugin.Instance?.OnAutoStartup();
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"Error in OnStartClient patch: {arg}");
				}
			}
		}

		[HarmonyPatch(typeof(ManagerBlackboard), "UpdateUnlockedFranchises")]
		[HarmonyPostfix]
		private static void OnUpdateUnlockedFranchises()
		{
			try
			{
				Plugin.Instance?.OnOrderingUIInitialized();
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"Error in UpdateUnlockedFranchises patch: {arg}");
				}
			}
		}

		[HarmonyPatch(typeof(LocalizationManager), "GetLocalizationString")]
		[HarmonyPrefix]
		private static bool OnGetLocalizationString(ref string key, ref string __result)
		{
			if (key != null && key.Length > 0 && key[0] == '`')
			{
				__result = key.Substring(1);
				return false;
			}
			return true;
		}
	}
}
namespace OrderAndOrganize.UI
{
	public class CategoryPickerUI
	{
		private readonly ManualLogSource _log;

		private readonly CategoryShelfManager _shelfManager;

		private readonly CategoryMapper _categoryMapper;

		private bool _pickerVisible;

		private Data_Container _targetContainer;

		private List<KeyValuePair<int, string>> _sortedGroups;

		private int _selectedIndex;

		private CursorLockMode _savedLockState;

		private bool _savedCursorVisible;

		private MonoBehaviour _frozenController;

		private static Type _fpcType;

		private static bool _fpcTypeResolved;

		private static MonoBehaviour _cachedFpc;

		private bool _labelsVisible = true;

		private bool _skipNextFrame;

		private GUIStyle _panelBgStyle;

		private GUIStyle _titleStyle;

		private GUIStyle _itemStyle;

		private GUIStyle _selectedItemStyle;

		private GUIStyle _footerStyle;

		private bool _stylesInitialized;

		private const float PanelWidth = 320f;

		private const float PanelHeight = 360f;

		private const float ItemHeight = 30f;

		private const int VisibleItemCount = 7;

		private const float LabelMaxDistance = 20f;

		private static Dictionary<Color, Texture2D> _texCache = new Dictionary<Color, Texture2D>();

		public bool IsPickerVisible => _pickerVisible;

		public bool LabelsVisible
		{
			get
			{
				return _labelsVisible;
			}
			set
			{
				_labelsVisible = value;
			}
		}

		public CategoryPickerUI(ManualLogSource log, CategoryShelfManager shelfManager, CategoryMapper categoryMapper)
		{
			_log = log;
			_shelfManager = shelfManager;
			_categoryMapper = categoryMapper;
		}

		public void UpdateInput()
		{
			if (!_pickerVisible)
			{
				return;
			}
			if (_skipNextFrame)
			{
				_skipNextFrame = false;
				Input.ResetInputAxes();
				return;
			}
			if (Input.GetKeyDown((KeyCode)103))
			{
				ClosePicker(apply: false);
				Input.ResetInputAxes();
				return;
			}
			if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271))
			{
				ClosePicker(apply: true);
				Input.ResetInputAxes();
				return;
			}
			if (Input.GetKeyDown((KeyCode)8) || Input.GetKeyDown((KeyCode)127))
			{
				ClearAndClose();
				Input.ResetInputAxes();
				return;
			}
			if (_sortedGroups != null)
			{
				float axis = Input.GetAxis("Mouse ScrollWheel");
				if (axis > 0.01f)
				{
					_selectedIndex = (_selectedIndex - 1 + _sortedGroups.Count) % _sortedGroups.Count;
				}
				else if (axis < -0.01f)
				{
					_selectedIndex = (_selectedIndex + 1) % _sortedGroups.Count;
				}
				if (Input.GetKeyDown((KeyCode)273))
				{
					_selectedIndex = (_selectedIndex - 1 + _sortedGroups.Count) % _sortedGroups.Count;
				}
				if (Input.GetKeyDown((KeyCode)274))
				{
					_selectedIndex = (_selectedIndex + 1) % _sortedGroups.Count;
				}
			}
			Input.ResetInputAxes();
		}

		public void OnHotkeyPressed()
		{
			if (_pickerVisible)
			{
				ClosePicker(apply: false);
				return;
			}
			Data_Container val = RaycastForStorageShelf();
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)"CategoryPicker: No storage shelf found in crosshair.");
				}
			}
			else
			{
				OpenPicker(val);
			}
		}

		public void ToggleLabels()
		{
			_labelsVisible = !_labelsVisible;
			try
			{
				string text = (_labelsVisible ? "ON" : "OFF");
				GameCanvas instance = GameCanvas.Instance;
				if (instance != null)
				{
					instance.CreateCanvasNotification("`Category labels: " + text);
				}
			}
			catch
			{
			}
		}

		private void OpenPicker(Data_Container container)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			_targetContainer = container;
			_sortedGroups = new List<KeyValuePair<int, string>>(_categoryMapper.GetAllGroups());
			_sortedGroups.Sort((KeyValuePair<int, string> a, KeyValuePair<int, string> b) => a.Key.CompareTo(b.Key));
			if (_sortedGroups.Count == 0)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)"CategoryPicker: No category groups available.");
				}
				return;
			}
			int? category = _shelfManager.GetCategory(container);
			_selectedIndex = 0;
			if (category.HasValue)
			{
				for (int num = 0; num < _sortedGroups.Count; num++)
				{
					if (_sortedGroups[num].Key == category.Value)
					{
						_selectedIndex = num;
						break;
					}
				}
			}
			_pickerVisible = true;
			_skipNextFrame = true;
			_savedLockState = Cursor.lockState;
			_savedCursorVisible = Cursor.visible;
			Cursor.lockState = (CursorLockMode)1;
			Cursor.visible = false;
			FreezePlayerController();
			ManualLogSource log2 = _log;
			if (log2 != null)
			{
				log2.LogDebug((object)$"CategoryPicker: Opened for shelf at {((Component)container).transform.position}");
			}
		}

		private void ClosePicker(bool apply)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (apply && (Object)(object)_targetContainer != (Object)null && _sortedGroups != null && _selectedIndex >= 0 && _selectedIndex < _sortedGroups.Count)
			{
				KeyValuePair<int, string> keyValuePair = _sortedGroups[_selectedIndex];
				_shelfManager.SetCategory(_targetContainer, keyValuePair.Key);
				try
				{
					GameCanvas instance = GameCanvas.Instance;
					if (instance != null)
					{
						instance.CreateCanvasNotification("`Shelf tagged: " + keyValuePair.Value);
					}
				}
				catch
				{
				}
			}
			_pickerVisible = false;
			_targetContainer = null;
			_sortedGroups = null;
			UnfreezePlayerController();
			Cursor.lockState = _savedLockState;
			Cursor.visible = _savedCursorVisible;
		}

		private void ClearAndClose()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_targetContainer != (Object)null)
			{
				_shelfManager.ClearCategory(_targetContainer);
				try
				{
					GameCanvas instance = GameCanvas.Instance;
					if (instance != null)
					{
						instance.CreateCanvasNotification("`Shelf category cleared");
					}
				}
				catch
				{
				}
			}
			_pickerVisible = false;
			_targetContainer = null;
			_sortedGroups = null;
			UnfreezePlayerController();
			Cursor.lockState = _savedLockState;
			Cursor.visible = _savedCursorVisible;
		}

		public void Draw()
		{
			InitStyles();
			if (_labelsVisible)
			{
				DrawFloatingLabels();
			}
			if (_pickerVisible && _sortedGroups != null && _sortedGroups.Count != 0)
			{
				DrawPickerOverlay();
			}
		}

		private void DrawPickerOverlay()
		{
			//IL_0032: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Expected O, but got Unknown
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: 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_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Expected O, but got Unknown
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			float num = ((float)Screen.width - 320f) / 2f;
			float num2 = ((float)Screen.height - 360f) / 2f;
			GUI.Box(new Rect(num, num2, 320f, 360f), "", _panelBgStyle);
			GUILayout.BeginArea(new Rect(num + 12f, num2 + 10f, 296f, 340f));
			GUILayout.Label("Assign Category", _titleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			int? category = _shelfManager.GetCategory(_targetContainer);
			string text = (category.HasValue ? _categoryMapper.GetGroupName(category.Value) : "None");
			GUIStyle val = new GUIStyle(_footerStyle)
			{
				alignment = (TextAnchor)4
			};
			val.normal.textColor = (Color)(category.HasValue ? _categoryMapper.GetGroupColor(category.Value) : new Color(0.6f, 0.6f, 0.6f));
			GUILayout.Label("Current: " + text, val, Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			DrawSeparator(296f);
			GUILayout.Space(6f);
			int num3 = 3;
			int num4 = _selectedIndex - num3;
			for (int i = 0; i < 7; i++)
			{
				int num5 = num4 + i;
				num5 = (num5 % _sortedGroups.Count + _sortedGroups.Count) % _sortedGroups.Count;
				KeyValuePair<int, string> keyValuePair = _sortedGroups[num5];
				bool num6 = num5 == _selectedIndex;
				Color val2 = EnsureReadable(_categoryMapper.GetGroupColor(keyValuePair.Key));
				if (num6)
				{
					Rect rect = GUILayoutUtility.GetRect(296f, 30f);
					Color col = val2 * 0.4f;
					col.a = 0.9f;
					GUI.DrawTexture(rect, (Texture)(object)MakeTex(1, 1, col));
					GUIStyle val3 = new GUIStyle(_selectedItemStyle);
					val3.normal.textColor = Color.white;
					GUI.Label(rect, "  > " + keyValuePair.Value, val3);
				}
				else
				{
					Rect rect2 = GUILayoutUtility.GetRect(296f, 30f);
					float num7 = Mathf.Abs(i - num3);
					float a = Mathf.Lerp(1f, 0.45f, num7 / ((float)num3 + 1f));
					GUIStyle val4 = new GUIStyle(_itemStyle);
					Color textColor = val2;
					textColor.a = a;
					val4.normal.textColor = textColor;
					GUI.Label(rect2, "    " + keyValuePair.Value, val4);
				}
			}
			GUILayout.Space(6f);
			DrawSeparator(296f);
			GUILayout.Space(8f);
			GUILayout.Label("[Scroll/Arrows] Browse   [Enter] Apply", _footerStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label("[G] Cancel   [Backspace] Clear", _footerStyle, Array.Empty<GUILayoutOption>());
			GUILayout.EndArea();
		}

		private void DrawFloatingLabels()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return;
			}
			IReadOnlyDictionary<string, int> allAssignments = _shelfManager.GetAllAssignments();
			if (allAssignments.Count == 0)
			{
				return;
			}
			Vector3 position = ((Component)main).transform.position;
			foreach (KeyValuePair<string, int> item in allAssignments)
			{
				Vector3 val = CategoryShelfManager.ParsePositionKey(item.Key);
				float num = Vector3.Distance(position, val);
				if (!(num > 20f))
				{
					Vector3 val2 = val + Vector3.up * 2.2f;
					Vector3 val3 = main.WorldToScreenPoint(val2);
					if (!(val3.z <= 0f))
					{
						float num2 = (float)Screen.height - val3.y;
						string groupName = _categoryMapper.GetGroupName(item.Value);
						Color groupColor = _categoryMapper.GetGroupColor(item.Value);
						float num3 = Mathf.Clamp01(1f - num / 20f);
						int fontSize = Mathf.RoundToInt(Mathf.Lerp(10f, 16f, num3));
						GUIStyle val4 = new GUIStyle(GUI.skin.label)
						{
							fontSize = fontSize,
							fontStyle = (FontStyle)1,
							alignment = (TextAnchor)4
						};
						groupColor.a = 0.7f + 0.3f * num3;
						val4.normal.textColor = groupColor;
						Vector2 val5 = val4.CalcSize(new GUIContent(groupName));
						Rect val6 = new Rect(val3.x - val5.x / 2f, num2 - val5.y / 2f, val5.x + 8f, val5.y + 2f);
						GUI.DrawTexture(val6, (Texture)(object)MakeTex(1, 1, new Color(0f, 0f, 0f, 0.4f * num3)));
						GUI.Label(val6, groupName, val4);
					}
				}
			}
		}

		private Data_Container RaycastForStorageShelf()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return null;
			}
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(main.ScreenPointToRay(new Vector3((float)Screen.width / 2f, (float)Screen.height / 2f, 0f)), ref val, 8f))
			{
				return null;
			}
			Transform val2 = ((RaycastHit)(ref val)).transform;
			int num = 6;
			while ((Object)(object)val2 != (Object)null && num-- > 0)
			{
				Data_Container component = ((Component)val2).GetComponent<Data_Container>();
				if ((Object)(object)component != (Object)null)
				{
					if (component.containerClass == 69)
					{
						return component;
					}
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogDebug((object)$"CategoryPicker: Found Data_Container but containerClass={component.containerClass} (not storage)");
					}
					return null;
				}
				InteractableContainer component2 = ((Component)val2).GetComponent<InteractableContainer>();
				if ((Object)(object)component2 != (Object)null && component2.isStorageShelf)
				{
					Transform parent = val2.parent;
					object obj;
					if (parent == null)
					{
						obj = null;
					}
					else
					{
						Transform parent2 = parent.parent;
						obj = ((parent2 != null) ? ((Component)parent2).GetComponent<Data_Container>() : null);
					}
					Data_Container val3 = (Data_Container)obj;
					if ((Object)(object)val3 != (Object)null && val3.containerClass == 69)
					{
						return val3;
					}
				}
				val2 = val2.parent;
			}
			return null;
		}

		private void FreezePlayerController()
		{
			try
			{
				MonoBehaviour val = FindFirstPersonController();
				if ((Object)(object)val != (Object)null && ((Behaviour)val).enabled)
				{
					((Behaviour)val).enabled = false;
					_frozenController = val;
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogDebug((object)"CategoryPicker: Disabled FirstPersonController.");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("CategoryPicker: Failed to freeze player controller: " + ex.Message));
				}
			}
		}

		private void UnfreezePlayerController()
		{
			try
			{
				if ((Object)(object)_frozenController != (Object)null)
				{
					((Behaviour)_frozenController).enabled = true;
					_frozenController = null;
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogDebug((object)"CategoryPicker: Re-enabled FirstPersonController.");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("CategoryPicker: Failed to unfreeze player controller: " + ex.Message));
				}
			}
		}

		internal static MonoBehaviour FindFirstPersonController()
		{
			if ((Object)(object)_cachedFpc != (Object)null)
			{
				return _cachedFpc;
			}
			if (!_fpcTypeResolved)
			{
				_fpcTypeResolved = true;
				_fpcType = AccessTools.TypeByName("StarterAssets.FirstPersonController") ?? AccessTools.TypeByName("FirstPersonController");
			}
			if (_fpcType == null)
			{
				return null;
			}
			Object obj = Object.FindFirstObjectByType(_fpcType);
			_cachedFpc = (MonoBehaviour)(object)((obj is MonoBehaviour) ? obj : null);
			return _cachedFpc;
		}

		private void InitStyles()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0080: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			if (!_stylesInitialized)
			{
				_stylesInitialized = true;
				_panelBgStyle = new GUIStyle(GUI.skin.box);
				_panelBgStyle.normal.background = MakeTex(2, 2, new Color(0.08f, 0.08f, 0.12f, 0.95f));
				_titleStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 18,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				_titleStyle.normal.textColor = new Color(0.92f, 0.92f, 0.92f);
				_itemStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 14,
					alignment = (TextAnchor)3
				};
				_selectedItemStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 15,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
				_footerStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 11,
					alignment = (TextAnchor)4
				};
				_footerStyle.normal.textColor = new Color(0.55f, 0.55f, 0.55f);
			}
		}

		private void DrawSeparator(float width)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			GUI.DrawTexture(GUILayoutUtility.GetRect(width, 1f), (Texture)(object)MakeTex(1, 1, new Color(0.4f, 0.4f, 0.4f, 0.6f)));
		}

		private static Color EnsureReadable(Color c)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			float num = 0.299f * c.r + 0.587f * c.g + 0.114f * c.b;
			if (num < 0.35f)
			{
				float num2 = 0.35f / Mathf.Max(num, 0.01f);
				c.r = Mathf.Clamp01(c.r * num2);
				c.g = Mathf.Clamp01(c.g * num2);
				c.b = Mathf.Clamp01(c.b * num2);
			}
			return c;
		}

		private static Texture2D MakeTex(int width, int height, Color col)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if (_texCache.TryGetValue(col, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Color[] array = (Color[])(object)new Color[width * height];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = col;
			}
			Texture2D val = new Texture2D(width, height);
			val.SetPixels(array);
			val.Apply();
			_texCache[col] = val;
			return val;
		}
	}
	public class ConfigWindow
	{
		private readonly ModConfiguration _config;

		private readonly Func<bool> _getAutoEnabled;

		private readonly Action _toggleAuto;

		private bool _visible;

		private Rect _windowRect = new Rect(20f, 20f, 420f, 620f);

		private int _windowId;

		private int _thresholdInput;

		private float _cashReserveInput;

		private int _scanIntervalInput;

		private int _pendingTimeoutInput;

		private string _buttonTextInput;

		private Vector2 _scrollPos;

		private GUIStyle _headerStyle;

		private GUIStyle _sectionStyle;

		private GUIStyle _labelStyle;

		private GUIStyle _valueStyle;

		private GUIStyle _toggleStyle;

		private GUIStyle _windowStyle;

		private bool _stylesInitialized;

		private static Texture2D _lineTex;

		public bool IsVisible => _visible;

		public ConfigWindow(ModConfiguration config, Func<bool> getAutoEnabled, Action toggleAuto)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			_config = config;
			_getAutoEnabled = getAutoEnabled;
			_toggleAuto = toggleAuto;
			_windowId = "OAOConfig".GetHashCode();
			SyncFromConfig();
		}

		public void Toggle()
		{
			_visible = !_visible;
			if (_visible)
			{
				SyncFromConfig();
			}
		}

		private void SyncFromConfig()
		{
			_thresholdInput = _config.ThresholdUnits.Value;
			_cashReserveInput = _config.CashReserve.Value;
			_scanIntervalInput = _config.ScanIntervalSeconds.Value;
			_pendingTimeoutInput = _config.PendingOrderTimeoutSeconds.Value;
			_buttonTextInput = _config.ButtonText.Value;
		}

		public void Draw()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (_visible)
			{
				InitStyles();
				_windowRect = GUI.Window(_windowId, _windowRect, new WindowFunction(DrawWindowContents), "", _windowStyle);
			}
		}

		private void InitStyles()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Expected O, but got Unknown
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Expected O, but got Unknown
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			if (!_stylesInitialized)
			{
				_stylesInitialized = true;
				_windowStyle = new GUIStyle(GUI.skin.window);
				_windowStyle.normal.background = MakeTex(2, 2, new Color(0.1f, 0.1f, 0.12f, 0.95f));
				_windowStyle.onNormal.background = _windowStyle.normal.background;
				_windowStyle.padding = new RectOffset(12, 12, 8, 8);
				_headerStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 18,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				_headerStyle.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
				_sectionStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 14,
					fontStyle = (FontStyle)1
				};
				_sectionStyle.normal.textColor = new Color(0.7f, 0.85f, 1f);
				_labelStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 13
				};
				_labelStyle.normal.textColor = new Color(0.85f, 0.85f, 0.85f);
				_valueStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 13,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)5
				};
				_valueStyle.normal.textColor = Color.white;
				_toggleStyle = new GUIStyle(GUI.skin.toggle)
				{
					fontSize = 13
				};
				_toggleStyle.normal.textColor = new Color(0.85f, 0.85f, 0.85f);
				_toggleStyle.onNormal.textColor = Color.white;
			}
		}

		private void DrawWindowContents(int id)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_0680: Unknown result type (might be due to invalid IL or missing references)
			//IL_0687: Expected O, but got Unknown
			//IL_06a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a7: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.Space(4f);
			GUILayout.Label("Order & Organize Settings", _headerStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			float num = ((Rect)(ref _windowRect)).height - 70f;
			_scrollPos = GUILayout.BeginScrollView(_scrollPos, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num) });
			DrawLine();
			GUILayout.Space(4f);
			GUILayout.Label("General", _sectionStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			bool flag = GUILayout.Toggle(_config.Enabled.Value, "  Mod Enabled", _toggleStyle, Array.Empty<GUILayoutOption>());
			if (flag != _config.Enabled.Value)
			{
				_config.Enabled.Value = flag;
			}
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Threshold:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			GUILayout.Label(_thresholdInput.ToString(), _valueStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			GUILayout.EndHorizontal();
			float num2 = GUILayout.HorizontalSlider((float)_thresholdInput, 0f, 500f, Array.Empty<GUILayoutOption>());
			_thresholdInput = Mathf.RoundToInt(num2);
			if (_thresholdInput != _config.ThresholdUnits.Value)
			{
				_config.ThresholdUnits.Value = _thresholdInput;
			}
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Button Text:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			_buttonTextInput = GUILayout.TextField(_buttonTextInput, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) });
			GUILayout.EndHorizontal();
			if (_buttonTextInput != _config.ButtonText.Value)
			{
				_config.ButtonText.Value = _buttonTextInput;
			}
			GUILayout.Space(2f);
			bool flag2 = GUILayout.Toggle(_config.ShowNotifications.Value, "  Show Notifications", _toggleStyle, Array.Empty<GUILayoutOption>());
			if (flag2 != _config.ShowNotifications.Value)
			{
				_config.ShowNotifications.Value = flag2;
			}
			bool flag3 = GUILayout.Toggle(_config.VerboseLogging.Value, "  Verbose Logging", _toggleStyle, Array.Empty<GUILayoutOption>());
			if (flag3 != _config.VerboseLogging.Value)
			{
				_config.VerboseLogging.Value = flag3;
			}
			GUILayout.Space(8f);
			DrawLine();
			GUILayout.Space(4f);
			GUILayout.Label("Automation", _sectionStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			bool flag4 = GUILayout.Toggle(_config.AutoOrderAtStartup.Value, "  Auto Order at Startup", _toggleStyle, Array.Empty<GUILayoutOption>());
			if (flag4 != _config.AutoOrderAtStartup.Value)
			{
				_config.AutoOrderAtStartup.Value = flag4;
			}
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Toggle Hotkey:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			GUILayout.Label(((object)_config.ToggleHotkey.Value/*cast due to .constrained prefix*/).ToString(), _valueStyle, Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Scan Interval:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			GUILayout.Label($"{_scanIntervalInput}s", _valueStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			GUILayout.EndHorizontal();
			float num3 = GUILayout.HorizontalSlider((float)_scanIntervalInput, 2f, 300f, Array.Empty<GUILayoutOption>());
			_scanIntervalInput = Mathf.RoundToInt(num3);
			if (_scanIntervalInput != _config.ScanIntervalSeconds.Value)
			{
				_config.ScanIntervalSeconds.Value = _scanIntervalInput;
			}
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Cash Reserve:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			GUILayout.Label($"${_cashReserveInput:F0}", _valueStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
			GUILayout.EndHorizontal();
			float num4 = GUILayout.HorizontalSlider(_cashReserveInput, 0f, 100000f, Array.Empty<GUILayoutOption>());
			_cashReserveInput = Mathf.Round(num4 / 100f) * 100f;
			if (Mathf.Abs(_cashReserveInput - _config.CashReserve.Value) > 1f)
			{
				_config.CashReserve.Value = _cashReserveInput;
			}
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Pending Timeout:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			GUILayout.Label($"{_pendingTimeoutInput}s", _valueStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			GUILayout.EndHorizontal();
			float num5 = GUILayout.HorizontalSlider((float)_pendingTimeoutInput, 10f, 600f, Array.Empty<GUILayoutOption>());
			_pendingTimeoutInput = Mathf.RoundToInt(num5);
			if (_pendingTimeoutInput != _config.PendingOrderTimeoutSeconds.Value)
			{
				_config.PendingOrderTimeoutSeconds.Value = _pendingTimeoutInput;
			}
			GUILayout.Space(8f);
			DrawLine();
			GUILayout.Space(4f);
			bool flag5 = _getAutoEnabled?.Invoke() ?? false;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Auto Order:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			GUIStyle val = new GUIStyle(_valueStyle);
			val.normal.textColor = (Color)(flag5 ? Color.green : new Color(1f, 0.4f, 0.4f));
			GUILayout.Label(flag5 ? "ACTIVE" : "OFF", val, Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			GUILayout.Space(4f);
			if (GUILayout.Button(flag5 ? "Disable Auto Order" : "Enable Auto Order", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				_toggleAuto?.Invoke();
			}
			GUILayout.Space(8f);
			DrawLine();
			GUILayout.Space(4f);
			GUILayout.Label("Category Shelves", _sectionStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			bool flag6 = GUILayout.Toggle(_config.CategoryShelvesEnabled.Value, "  Category Shelves Enabled", _toggleStyle, Array.Empty<GUILayoutOption>());
			if (flag6 != _config.CategoryShelvesEnabled.Value)
			{
				_config.CategoryShelvesEnabled.Value = flag6;
			}
			GUILayout.Space(2f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Category Hotkey:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			GUILayout.Label(((object)_config.CategoryHotkey.Value/*cast due to .constrained prefix*/).ToString(), _valueStyle, Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			GUILayout.Space(2f);
			bool flag7 = GUILayout.Toggle(_config.CategoryLabelsVisible.Value, "  Show Floating Labels", _toggleStyle, Array.Empty<GUILayoutOption>());
			if (flag7 != _config.CategoryLabelsVisible.Value)
			{
				_config.CategoryLabelsVisible.Value = flag7;
			}
			GUILayout.Space(2f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Labels Hotkey:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			GUILayout.Label(((object)_config.CategoryLabelsToggleHotkey.Value/*cast due to .constrained prefix*/).ToString(), _valueStyle, Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			GUILayout.Space(4f);
			GUILayout.EndScrollView();
			GUILayout.Space(4f);
			if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }))
			{
				_visible = false;
			}
			GUI.DragWindow();
		}

		private void DrawLine()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			GUI.DrawTexture(GUILayoutUtility.GetRect(1f, 1f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }), (Texture)(object)MakeLineTex(), (ScaleMode)0);
		}

		private static Texture2D MakeLineTex()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_lineTex == (Object)null)
			{
				_lineTex = MakeTex(1, 1, new Color(0.4f, 0.4f, 0.4f, 0.8f));
			}
			return _lineTex;
		}

		private static Texture2D MakeTex(int width, int height, Color col)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			Color[] array = (Color[])(object)new Color[width * height];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = col;
			}
			Texture2D val = new Texture2D(width, height);
			val.SetPixels(array);
			val.Apply();
			return val;
		}
	}
	public class OrderButtonController
	{
		private const string ButtonObjectName = "OAO_AddLowStockButton";

		private const string AutoLabelObjectName = "OAO_AutoLabel";

		private readonly ManualLogSource _log;

		private readonly ModConfiguration _config;

		private readonly GameProductCatalogAdapter _catalog;

		private readonly GameInventoryAdapter _inventory;

		private readonly GameShoppingListAdapter _shoppingList;

		private readonly GameNotificationAdapter _notification;

		private readonly PendingOrderTracker _pendingTracker;

		private readonly Func<bool> _isAutoEnabled;

		private GameObject _buttonObj;

		private GameObject _autoLabelObj;

		private bool _isRunning;

		private bool _hasLoggedHierarchy;

		public OrderButtonController(ManualLogSource log, ModConfiguration config, GameProductCatalogAdapter catalog, GameInventoryAdapter inventory, GameShoppingListAdapter shoppingList, GameNotificationAdapter notification, PendingOrderTracker pendingTracker, Func<bool> isAutoEnabled)
		{
			_log = log;
			_config = config;
			_catalog = catalog;
			_inventory = inventory;
			_shoppingList = shoppingList;
			_notification = notification;
			_pendingTracker = pendingTracker;
			_isAutoEnabled = isAutoEnabled;
		}

		public void TryCreateButton()
		{
			try
			{
				ManagerBlackboard managerBlackboard = _catalog.GetManagerBlackboard();
				if ((Object)(object)managerBlackboard == (Object)null)
				{
					return;
				}
				if (!_hasLoggedHierarchy)
				{
					_hasLoggedHierarchy = true;
					LogUiHierarchy(managerBlackboard);
				}
				Transform val = FindButtonParent(managerBlackboard);
				if ((Object)(object)val == (Object)null)
				{
					_log.LogWarning((object)"Could not find a suitable parent for button placement.");
					return;
				}
				if ((Object)(object)val.Find("OAO_AddLowStockButton") != (Object)null)
				{
					_log.LogDebug((object)"Button already exists; skipping creation.");
					UpdateAutoLabel();
					return;
				}
				CreateButtonByCloning(managerBlackboard, val);
				if ((Object)(object)_buttonObj == (Object)null)
				{
					CreateButtonFallback(val);
				}
				CreateAutoLabel(val);
				_log.LogInfo((object)("Order & Organize button created. Parent: " + ((Object)val).name));
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Failed to create button: {arg}");
			}
		}

		private Transform FindButtonParent(ManagerBlackboard blackboard)
		{
			if ((Object)(object)blackboard.shoppingListParent != (Object)null)
			{
				Transform parent = blackboard.shoppingListParent.transform.parent;
				if ((Object)(object)parent != (Object)null)
				{
					_log.LogDebug((object)("Using shopping list grandparent: " + ((Object)parent).name));
					return parent;
				}
			}
			if ((Object)(object)blackboard.tabsOBJ != (Object)null)
			{
				return blackboard.tabsOBJ.transform.parent ?? blackboard.tabsOBJ.transform;
			}
			return ((Component)blackboard).transform;
		}

		private void CreateButtonByCloning(ManagerBlackboard blackboard, Transform parent)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = FindReferenceButton(((Component)blackboard).transform);
			if ((Object)(object)val == (Object)null)
			{
				_log.LogDebug((object)"No reference button found to clone; will use fallback.");
				return;
			}
			_log.LogDebug((object)("Cloning reference button: " + ((Object)val).name));
			_buttonObj = Object.Instantiate<GameObject>(val, parent);
			((Object)_buttonObj).name = "OAO_AddLowStockButton";
			PlayMakerFSM[] components = _buttonObj.GetComponents<PlayMakerFSM>();
			for (int i = 0; i < components.Length; i++)
			{
				Object.Destroy((Object)(object)components[i]);
			}
			components = _buttonObj.GetComponentsInChildren<PlayMakerFSM>();
			for (int i = 0; i < components.Length; i++)
			{
				Object.Destroy((Object)(object)components[i]);
			}
			Button val2 = _buttonObj.GetComponent<Button>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = _buttonObj.AddComponent<Button>();
			}
			((UnityEventBase)val2.onClick).RemoveAllListeners();
			((UnityEvent)val2.onClick).AddListener(new UnityAction(OnButtonClicked));
			SetButtonText(_buttonObj, _config.ButtonText.Value);
			RectTransform component = _buttonObj.GetComponent<RectTransform>();
			if ((Object)(object)component != (Object)null)
			{
				component.anchorMin = new Vector2(1f, 0f);
				component.anchorMax = new Vector2(1f, 0f);
				component.pivot = new Vector2(1f, 0f);
				component.anchoredPosition = new Vector2(-10f, 10f);
				component.sizeDelta = new Vector2(180f, 40f);
			}
			_log.LogInfo((object)"Button created by cloning native button.");
		}

		private GameObject FindReferenceButton(Transform root)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			foreach (Transform item in root)
			{
				Transform val = item;
				string text = ((Object)val).name.ToLower();
				if ((Object)(object)((Component)val).GetComponent<Button>() != (Object)null && (text.Contains("buy") || text.Contains("button") || text.Contains("btn")))
				{
					return ((Component)val).gameObject;
				}
				foreach (Transform item2 in val)
				{
					Transform val2 = item2;
					string text2 = ((Object)val2).name.ToLower();
					if ((Object)(object)((Component)val2).GetComponent<Button>() != (Object)null && (text2.Contains("buy") || text2.Contains("button") || text2.Contains("btn")))
					{
						return ((Component)val2).gameObject;
					}
				}
			}
			return null;
		}

		private void CreateButtonFallback(Transform parent)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected O, but got Unknown
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			_buttonObj = new GameObject("OAO_AddLowStockButton");
			_buttonObj.transform.SetParent(parent, false);
			RectTransform obj = _buttonObj.AddComponent<RectTransform>();
			obj.anchorMin = new Vector2(1f, 0f);
			obj.anchorMax = new Vector2(1f, 0f);
			obj.pivot = new Vector2(1f, 0f);
			obj.anchoredPosition = new Vector2(-10f, 10f);
			obj.sizeDelta = new Vector2(180f, 40f);
			((Graphic)_buttonObj.AddComponent<Image>()).color = new Color(0.2f, 0.6f, 0.2f, 1f);
			Button obj2 = _buttonObj.AddComponent<Button>();
			((UnityEvent)obj2.onClick).AddListener(new UnityAction(OnButtonClicked));
			ColorBlock colors = ((Selectable)obj2).colors;
			((ColorBlock)(ref colors)).normalColor = new Color(0.2f, 0.6f, 0.2f, 1f);
			((ColorBlock)(ref colors)).highlightedColor = new Color(0.3f, 0.7f, 0.3f, 1f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.1f, 0.4f, 0.1f, 1f);
			((Selectable)obj2).colors = colors;
			GameObject val = new GameObject("ButtonText");
			val.transform.SetParent(_buttonObj.transform, false);
			RectTransform obj3 = val.AddComponent<RectTransform>();
			obj3.anchorMin = Vector2.zero;
			obj3.anchorMax = Vector2.one;
			obj3.offsetMin = Vector2.zero;
			obj3.offsetMax = Vector2.zero;
			try
			{
				TextMeshProUGUI obj4 = val.AddComponent<TextMeshProUGUI>();
				((TMP_Text)obj4).text = _config.ButtonText.Value;
				((TMP_Text)obj4).alignment = (TextAlignmentOptions)514;
				((Graphic)obj4).color = Color.white;
				((TMP_Text)obj4).fontSize = 16f;
				((TMP_Text)obj4).fontStyle = (FontStyles)1;
			}
			catch
			{
				Text obj6 = val.AddComponent<Text>();
				obj6.text = _config.ButtonText.Value;
				obj6.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
				obj6.alignment = (TextAnchor)4;
				((Graphic)obj6).color = Color.white;
				obj6.fontStyle = (FontStyle)1;
				obj6.fontSize = 16;
			}
			_log.LogInfo((object)"Button created using fallback method.");
		}

		private void CreateAutoLabel(Transform parent)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			_autoLabelObj = new GameObject("OAO_AutoLabel");
			_autoLabelObj.transform.SetParent(parent, false);
			RectTransform obj = _autoLabelObj.AddComponent<RectTransform>();
			obj.anchorMin = new Vector2(1f, 0f);
			obj.anchorMax = new Vector2(1f, 0f);
			obj.pivot = new Vector2(1f, 0f);
			obj.anchoredPosition = new Vector2(-10f, 52f);
			obj.sizeDelta = new Vector2(180f, 20f);
			try
			{
				TextMeshProUGUI obj2 = _autoLabelObj.AddComponent<TextMeshProUGUI>();
				((TMP_Text)obj2).alignment = (TextAlignmentOptions)514;
				((TMP_Text)obj2).fontSize = 12f;
			}
			catch
			{
				Text obj4 = _autoLabelObj.AddComponent<Text>();
				obj4.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
				obj4.alignment = (TextAnchor)4;
				obj4.fontSize = 12;
			}
			UpdateAutoLabel();
		}

		public void UpdateAutoLabel()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_autoLabelObj == (Object)null)
			{
				return;
			}
			Func<bool> isAutoEnabled = _isAutoEnabled;
			int num;
			object obj;
			if (isAutoEnabled == null)
			{
				num = 0;
			}
			else
			{
				num = (isAutoEnabled() ? 1 : 0);
				if (num != 0)
				{
					obj = "Auto Order: ON";
					goto IL_0030;
				}
			}
			obj = "Auto Order: OFF";
			goto IL_0030;
			IL_0030:
			string text = (string)obj;
			Color color = ((num != 0) ? Color.green : Color.gray);
			TextMeshProUGUI component = _autoLabelObj.GetComponent<TextMeshProUGUI>();
			if ((Object)(object)component != (Object)null)
			{
				((TMP_Text)component).text = text;
				((Graphic)component).color = color;
				return;
			}
			Text component2 = _autoLabelObj.GetComponent<Text>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.text = text;
				((Graphic)component2).color = color;
			}
		}

		private void SetButtonText(GameObject buttonObj, string newText)
		{
			TextMeshProUGUI componentInChildren = buttonObj.GetComponentInChildren<TextMeshProUGUI>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((TMP_Text)componentInChildren).text = newText;
				return;
			}
			Text componentInChildren2 = buttonObj.GetComponentInChildren<Text>();
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.text = newText;
			}
		}

		private void OnButtonClicked()
		{
			if (_isRunning)
			{
				return;
			}
			_isRunning = true;
			try
			{
				SetButtonInteractable(interactable: false);
				ExecuteManualRestock();
			}
			finally
			{
				SetButtonInteractable(interactable: true);
				_isRunning = false;
			}
		}

		private void ExecuteManualRestock()
		{
			int value = _config.ThresholdUnits.Value;
			bool value2 = _config.VerboseLogging.Value;
			List<ProductStockSnapshot> snapshots = new InventoryScanner(_log, _inventory, _catalog, _shoppingList, _pendingTracker, value2).ScanAll();
			List<ProductOrderCandidate> candidates = new RestockPlanner().PlanManualRestock(snapshots, value);
			var (num, num2) = new ShoppingListService(_log, _shoppingList, _catalog).AddCandidatesToShoppingList(candidates);
			_log.LogInfo((object)$"Manual restock: {num} added, {num2} skipped, threshold={value}");
			new NotificationService(_notification, _config.ShowNotifications.Value).NotifyManualResult(num, num2, value);
		}

		private void SetButtonInteractable(bool interactable)
		{
			if (!((Object)(object)_buttonObj == (Object)null))
			{
				Button component = _buttonObj.GetComponent<Button>();
				if ((Object)(object)component != (Object)null)
				{
					((Selectable)component).interactable = interactable;
				}
			}
		}

		private void LogUiHierarchy(ManagerBlackboard blackboard)
		{
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			_log.LogInfo((object)"=== UI Hierarchy Dump (ManagerBlackboard) ===");
			ManualLogSource log = _log;
			GameObject tabsOBJ = blackboard.tabsOBJ;
			log.LogInfo((object)("tabsOBJ: " + (((tabsOBJ != null) ? ((Object)tabsOBJ).name : null) ?? "NULL")));
			ManualLogSource log2 = _log;
			GameObject tabsOBJ2 = blackboard.tabsOBJ;
			object obj;
			if (tabsOBJ2 == null)
			{
				obj = null;
			}
			else
			{
				Transform transform = tabsOBJ2.transform;
				if (transform == null)
				{
					obj = null;
				}
				else
				{
					Transform parent = transform.parent;
					obj = ((parent != null) ? ((Object)parent).name : null);
				}
			}
			if (obj == null)
			{
				obj = "NULL";
			}
			log2.LogInfo((object)("tabsOBJ.parent: " + (string?)obj));
			ManualLogSource log3 = _log;
			GameObject shopItemsParent = blackboard.shopItemsParent;
			log3.LogInfo((object)("shopItemsParent: " + (((shopItemsParent != null) ? ((Object)shopItemsParent).name : null) ?? "NULL")));
			ManualLogSource log4 = _log;
			GameObject shopItemsParent2 = blackboard.shopItemsParent;
			object obj2;
			if (shopItemsParent2 == null)
			{
				obj2 = null;
			}
			else
			{
				Transform transform2 = shopItemsParent2.transform;
				if (transform2 == null)
				{
					obj2 = null;
				}
				else
				{
					Transform parent2 = transform2.parent;
					obj2 = ((parent2 != null) ? ((Object)parent2).name : null);
				}
			}
			if (obj2 == null)
			{
				obj2 = "NULL";
			}
			log4.LogInfo((object)("shopItemsParent.parent: " + (string?)obj2));
			ManualLogSource log5 = _log;
			GameObject shoppingListParent = blackboard.shoppingListParent;
			log5.LogInfo((object)("shoppingListParent: " + (((shoppingListParent != null) ? ((Object)shoppingListParent).name : null) ?? "NULL")));
			ManualLogSource log6 = _log;
			GameObject shoppingListParent2 = blackboard.shoppingListParent;
			object obj3;
			if (shoppingListParent2 == null)
			{
				obj3 = null;
			}
			else
			{
				Transform transform3 = shoppingListParent2.transform;
				if (transform3 == null)
				{
					obj3 = null;
				}
				else
				{
					Transform parent3 = transform3.parent;
					obj3 = ((parent3 != null) ? ((Object)parent3).name : null);
				}
			}
			if (obj3 == null)
			{
				obj3 = "NULL";
			}
			log6.LogInfo((object)("shoppingListParent.parent: " + (string?)obj3));
			ManualLogSource log7 = _log;
			TextMeshProUGUI totalChargeOBJ = blackboard.totalChargeOBJ;
			log7.LogInfo((object)("totalChargeOBJ: " + (((totalChargeOBJ != null) ? ((Object)totalChargeOBJ).name : null) ?? "NULL")));
			ManualLogSource log8 = _log;
			TextMeshProUGUI totalChargeOBJ2 = blackboard.totalChargeOBJ;
			object obj4;
			if (totalChargeOBJ2 == null)
			{
				obj4 = null;
			}
			else
			{
				Transform transform4 = ((TMP_Text)totalChargeOBJ2).transform;
				if (transform4 == null)
				{
					obj4 = null;
				}
				else
				{
					Transform parent4 = transform4.parent;
					obj4 = ((parent4 != null) ? ((Object)parent4).name : null);
				}
			}
			if (obj4 == null)
			{
				obj4 = "NULL";
			}
			log8.LogInfo((object)("totalChargeOBJ.parent: " + (string?)obj4));
			Transform transform5 = ((Component)blackboard).transform;
			_log.LogInfo((object)$"ManagerBlackboard root: {((Object)transform5).name} (children={transform5.childCount})");
			LogChildren(transform5, 1, 3);
			if ((Object)(object)blackboard.shoppingListParent != (Object)null)
			{
				_log.LogInfo((object)"--- Shopping list parent chain ---");
				Transform val = blackboard.shoppingListParent.transform;
				int num = 0;
				while ((Object)(object)val != (Object)null && num < 8)
				{
					RectTransform component = ((Component)val).GetComponent<RectTransform>();
					string arg = (((Object)(object)component != (Object)null) ? $"pos={component.anchoredPosition}, size={component.sizeDelta}, anchors=({component.anchorMin},{component.anchorMax})" : "no RectTransform");
					_log.LogInfo((object)$"  [depth {num}] {((Object)val).name} ({arg})");
					val = val.parent;
					num++;
				}
			}
			_log.LogInfo((object)"=== End UI Hierarchy Dump ===");
		}

		private void LogChildren(Transform parent, int currentDepth, int maxDepth)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			if (currentDepth > maxDepth)
			{
				return;
			}
			string text = new string(' ', currentDepth * 2);
			foreach (Transform item in parent)
			{
				Transform val = item;
				RectTransform component = ((Component)val).GetComponent<RectTransform>();
				bool num = (Object)(object)((Component)val).GetComponent<Button>() != (Object)null;
				bool flag = (Object)(object)((Component)val).GetComponent<TextMeshProUGUI>() != (Object)null;
				string text2 = "";
				if (num)
				{
					text2 += " [Button]";
				}
				if (flag)
				{
					string text3 = text2;
					TextMeshProUGUI component2 = ((Component)val).GetComponent<TextMeshProUGUI>();
					text2 = text3 + " [TMP: " + ((component2 != null) ? ((TMP_Text)component2).text : null) + "]";
				}
				string text4 = (((Object)(object)component != (Object)null) ? $" pos={component.anchoredPosition}" : "");
				_log.LogDebug((object)$"{text}{((Object)val).name} (children={val.childCount}){text4}{text2}");
				LogChildren(val, currentDepth + 1, maxDepth);
			}
		}
	}
}
namespace OrderAndOrganize.Services
{
	public class AutomationController
	{
		private readonly ManualLogSource _log;

		private readonly ModConfiguration _config;

		private readonly GameAuthorityAdapter _authority;

		private readonly GameMoneyAdapter _money;

		private readonly GamePurchaseAdapter _purchase;

		private readonly GameProductCatalogAdapter _catalog;

		private readonly GameInventoryAdapter _inventory;

		private readonly GameShoppingListAdapter _shoppingList;

		private readonly GameNotificationAdapter _notification;

		private readonly PendingOrderTracker _pendingTracker;

		private bool _enabled;

		private bool _isRunningCycle;

		private Coroutine _automationCoroutine;

		private bool _notifiedNotAuthority;

		public bool IsEnabled => _enabled;

		public AutomationController(ManualLogSource log, ModConfiguration config, GameAuthorityAdapter authority, GameMoneyAdapter money, GamePurchaseAdapter purchase, GameProductCatalogAdapter catalog, GameInventoryAdapter inventory, GameShoppingListAdapter shoppingList, GameNotificationAdapter notification, PendingOrderTracker pendingTracker)
		{
			_log = log;
			_config = config;
			_authority = authority;
			_money = money;
			_purchase = purchase;
			_catalog = catalog;
			_inventory = inventory;
			_shoppingList = shoppingList;
			_notification = notification;
			_pendingTracker = pendingTracker;
		}

		public void Toggle(MonoBehaviour host)
		{
			_enabled = !_enabled;
			_log.LogInfo((object)("Automation toggled: " + (_enabled ? "ENABLED" : "DISABLED")));
			NotificationService notificationService = new NotificationService(_notification, _config.ShowNotifications.Value);
			if (_enabled)
			{
				notificationService.NotifyAutomationEnabled();
				StartAutomation(host);
			}
			else
			{
				notificationService.NotifyAutomationDisabled();
				StopAutomation(host);
			}
		}

		public void SetEnabled(bool enabled, MonoBehaviour host)
		{
			if (_enabled != enabled)
			{
				_enabled = enabled;
				_log.LogInfo((object)("Automation set: " + (_enabled ? "ENABLED" : "DISABLED")));
				if (_enabled)
				{
					StartAutomation(host);
				}
				else
				{
					StopAutomation(host);
				}
			}
		}

		private void StartAutomation(MonoBehaviour host)
		{
			if (_automationCoroutine == null)
			{
				_automationCoroutine = host.StartCoroutine(AutomationLoop());
				_log.LogInfo((object)"Automation coroutine started.");
			}
		}

		public void StopAutomation(MonoBehaviour host)
		{
			if (_automationCoroutine != null)
			{
				host.StopCoroutine(_automationCoroutine);
				_automationCoroutine = null;
				_log.LogInfo((object)"Automation coroutine stopped.");
			}
			_isRunningCycle = false;
		}

		public void OnSceneUnload()
		{
			_pendingTracker.ClearAll();
			_isRunningCycle = false;
			_notifiedNotAuthority = false;
			_log.LogInfo((object)"Scene unloaded: cleared automation state.");
		}

		private IEnumerator AutomationLoop()
		{
			while (_enabled)
			{
				yield return (object)new WaitForSeconds((float)_config.ScanIntervalSeconds.Value);
				if (!_enabled)
				{
					break;
				}
				if (!_authority.IsStoreLoaded())
				{
					_log.LogDebug((object)"Automation: no store loaded, skipping cycle.");
				}
				else if (!_authority.IsLocalAuthority())
				{
					if (!_notifiedNotAuthority)
					{
						_log.LogInfo((object)"Automation: not the host/server. Automatic purchases disabled.");
						new NotificationService(_notification, _config.ShowNotifications.Value).NotifyNotAuthority();
						_notifiedNotAuthority = true;
					}
				}
				else if (_isRunningCycle)
				{
					_log.LogDebug((object)"Automation: previous cycle still running, skipping.");
				}
				else
				{
					yield return RunCycle();
				}
			}
			_automationCoroutine = null;
		}

		private IEnumerator RunCycle()
		{
			_isRunningCycle = true;
			ManagerBlackboard managerBlackboard = _catalog.GetManagerBlackboard();
			if ((Object)(object)managerBlackboard == (Object)null)
			{
				_log.LogDebug((object)"Automation: ManagerBlackboard not available.");
				_isRunningCycle = false;
				yield break;
			}
			if (!_purchase.IsShoppingListEmpty(managerBlackboard))
			{
				new NotificationService(_notification, _config.ShowNotifications.Value).NotifyManualListBlocking();
				_isRunningCycle = false;
				yield break;
			}
			int value = _config.ThresholdUnits.Value;
			bool value2 = _config.VerboseLogging.Value;
			List<ProductStockSnapshot> list;
			List<ProductOrderCandidate> list2;
			AutomationCycleResult result;
			try
			{
				list = new InventoryScanner(_log, _inventory, _catalog, _shoppingList, _pendingTracker, value2).ScanAll();
				_pendingTracker.Reconcile(list, _config.PendingOrderTimeoutSeconds.Value);
				list2 = new RestockPlanner().PlanAutoRestock(list, value, _pendingTracker);
				result = new AutomationCycleResult
				{
					ProductsScanned = list.Count,
					ProductsBelowThreshold = list2.Count
				};
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Automation scan/plan error: {arg}");
				_isRunningCycle = false;
				yield break;
			}
			if (list2 == null || list2.Count == 0)
			{
				_log.LogDebug((object)$"Automation: no products below threshold ({value}).");
				_isRunningCycle = false;
				yield break;
			}
			float value3 = _config.CashReserve.Value;
			PurchaseService purchaseService = new PurchaseService(_log, _purchase, _money, _pendingTracker, value2);
			yield return CoroutineRunner.Instance.StartTrackedCoroutine(purchaseService.ExecutePurchases(managerBlackboard, list2, list, value3, result));
			_log.LogInfo((object)($"Automation cycle complete: scanned={result.ProductsScanned}, " + $"below threshold={result.ProductsBelowThreshold}, purchased={result.ProductsPurchased}, " + $"skipped(funds)={result.ProductsSkippedInsufficientFunds}, " + $"skipped(pending)={result.ProductsSkippedPending}, " + $"spent=${result.TotalSpent:F2}, " + $"money={result.MoneyBefore:F2}->{result.MoneyAfter:F2}"));
			new NotificationService(_notification, _config.ShowNotifications.Value).NotifyAutomationResult(result);
			_isRunningCycle = false;
		}
	}
	public class CategoryMapper
	{
		private readonly ManualLogSource _log;

		private Dictionary<int, int> _productToGroup;

		private Dictionary<int, string> _groupNames;

		private Dictionary<int, Color> _groupColors;

		private bool _initialized;

		public CategoryMapper(ManualLogSource log)
		{
			_log = log;
		}

		public int GetGroupForProduct(int productId)
		{
			EnsureInitialized();
			if (!_productToGroup.TryGetValue(productId, out var value))
			{
				return -1;
			}
			return value;
		}

		public string GetGroupName(int groupIndex)
		{
			EnsureInitialized();
			if (_groupNames.TryGetValue(groupIndex, out var value))
			{
				return value;
			}
			return $"Group {groupIndex}";
		}

		public Color GetGroupColor(int groupIndex)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			EnsureInitialized();
			if (!_groupColors.TryGetValue(groupIndex, out var value))
			{
				return Color.white;
			}
			return value;
		}

		public Dictionary<int, string> GetAllGroups()
		{
			EnsureInitialized();
			return new Dictionary<int, string>(_groupNames);
		}

		public void Rebuild()
		{
			_initialized = false;
			EnsureInitialized();
		}

		private void EnsureInitialized()
		{
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			if (_initialized)
			{
				return;
			}
			_productToGroup = new Dictionary<int, int>();
			_groupNames = new Dictionary<int, string>();
			_groupColors = new Dictionary<int, Color>();
			ProductListing instance = ProductListing.Instance;
			if ((Object)(object)instance == (Object)null || instance.tiers == null || instance.productGroups == null)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)"CategoryMapper: ProductListing not available yet.");
				}
				return;
			}
			_initialized = true;
			for (int i = 0; i < instance.tiers.Length; i++)
			{
				string text = instance.tiers[i];
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				string[] array = text.Split(new char[1] { '-' });
				if (array.Length != 2 || !int.TryParse(array[0], out var result) || !int.TryParse(array[1], out var result2))
				{
					continue;
				}
				int num = ((i < instance.productGroups.Length) ? instance.productGroups[i] : (-1));
				if (num < 0)
				{
					continue;
				}
				for (int j = result; j <= result2; j++)
				{
					_productToGroup[j] = num;
				}
				if (_groupNames.ContainsKey(num))
				{
					continue;
				}
				string text2 = "productGroup" + num;
				string text3 = null;
				try
				{
					if ((Object)(object)LocalizationManager.instance != (Object)null)
					{
						text3 = LocalizationManager.instance.GetLocalizationString(text2);
					}
				}
				catch
				{
				}
				_groupNames[num] = ((!string.IsNullOrEmpty(text3)) ? text3 : $"Group {num}");
				if (instance.groupsColors != null && num < instance.groupsColors.Length)
				{
					_groupColors[num] = instance.groupsColors[num];
				}
				else
				{
					_groupColors[num] = Color.white;
				}
			}
			ManualLogSource log2 = _log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"CategoryMapper: Mapped {_productToGroup.Count} products across {_groupNames.Count} groups.");
			}
			foreach (KeyValuePair<int, string> groupName in _groupNames)
			{
				ManualLogSource log3 = _log;
				if (log3 != null)
				{
					log3.LogDebug((object)$"  Group {groupName.Key}: {groupName.Value}");
				}
			}
		}
	}
	public class CategoryShelfManager
	{
		private readonly ManualLogSource _log;

		private readonly CategoryMapper _categoryMapper;

		private readonly string _savePath;

		private Dictionary<string, int> _assignments = new Dictionary<string, int>();

		public int AssignmentCount => _assignments.Count;

		private string BackupPath => _savePath + ".backup";

		public CategoryShelfManager(ManualLogSource log, CategoryMapper categoryMapper, string savePath)
		{
			_log = log;
			_categoryMapper = categoryMapper;
			_savePath = savePath;
			Load();
		}

		public void SetCategory(Data_Container container, int groupIndex)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			string text = PositionKey(((Component)container).transform.position);
			_assignments[text] = groupIndex;
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"Category set: shelf at {text} -> group {groupIndex} ({_categoryMapper.GetGroupName(groupIndex)})");
			}
			Save();
		}

		public void ClearCategory(Data_Container container)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			string text = PositionKey(((Component)container).transform.position);
			if (_assignments.Remove(text))
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)("Category cleared: shelf at " + text));
				}
				Save();
			}
		}

		public void ClearCategoryByPosition(Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			string text = PositionKey(position);
			if (_assignments.Remove(text))
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)("Category auto-cleared: shelf destroyed at " + text));
				}
				Save();
			}
		}

		public void PurgeStaleAssignments()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (_assignments.Count == 0)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (string key in _assignments.Keys)
			{
				Vector3 val = ParsePositionKey(key);
				bool flag = false;
				Collider[] array = Physics.OverlapSphere(val, 0.5f);
				foreach (Collider val2 in array)
				{
					Data_Container val3 = ((Component)val2).GetComponent<Data_Container>();
					if ((Object)(object)val3 == (Object)null)
					{
						val3 = ((Component)val2).GetComponentInParent<Data_Container>();
					}
					if ((Object)(object)val3 != (Object)null && val3.containerClass == 69)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					list.Add(key);
				}
			}
			if (list.Count == 0)
			{
				return;
			}
			int count = _assignments.Count;
			float num = (float)list.Count / (float)count;
			if (num > 0.5f)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)($"CategoryShelfManager: Purge ABORTED — {list.Count}/{count} entries " + $"({num:P0}) would be removed. This likely means shelves haven't loaded yet."));
				}
				return;
			}
			CreateBackup();
			foreach (string item in list)
			{
				_assignments.Remove(item);
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogInfo((object)("CategoryShelfManager: Purged stale assignment at " + item + " (shelf no longer exists)"));
				}
			}
			Save();
		}

		public int? GetCategory(Data_Container container)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			string key = PositionKey(((Component)container).transform.position);
			if (!_assignments.TryGetValue(key, out var value))
			{
				return null;
			}
			return value;
		}

		public bool IsProductAllowed(Data_Container container, int productId)
		{
			int? category = GetCategory(container);
			if (!category.HasValue)
			{
				return true;
			}
			return _categoryMapper.GetGroupForProduct(productId) == category.Value;
		}

		public IReadOnlyDictionary<string, int> GetAllAssignments()
		{
			return _assignments;
		}

		public bool IsProductAllowedAtPosition(Vector3 position, int productId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			string key = PositionKey(position);
			if (!_assignments.TryGetValue(key, out var value))
			{
				return true;
			}
			return _categoryMapper.GetGroupForProduct(productId) == value;
		}

		public int? GetCategoryAtPosition(Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			string key = PositionKey(position);
			if (!_assignments.TryGetValue(key, out var value))
			{
				return null;
			}
			return value;
		}

		public static string PositionKey(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.RoundToInt(pos.x * 10f);
			int num2 = Mathf.RoundToInt(pos.y * 10f);
			int num3 = Mathf.RoundToInt(pos.z * 10f);
			return $"{num},{num2},{num3}";
		}

		public static Vector3 ParsePositionKey(string key)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			string[] array = key.Split(new char[1] { ',' });
			if (array.Length != 3)
			{
				return Vector3.zero;
			}
			if (!int.TryParse(array[0], out var result))
			{
				return Vector3.zero;
			}
			if (!int.TryParse(array[1], out var result2))
			{
				return Vector3.zero;
			}
			if (!int.TryParse(array[2], out var result3))
			{
				return Vector3.zero;
			}
			return new Vector3((float)result / 10f, (float)result2 / 10f, (float)result3 / 10f);
		}

		private void CreateBackup()
		{
			try
			{
				if (File.Exists(_savePath))
				{
					File.Copy(_savePath, BackupPath, overwrite: true);
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogInfo((object)("CategoryShelfManager: Backup created at " + BackupPath));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("CategoryShelfManager: Failed to create backup: " + ex.Message));
				}
			}
		}

		private bool TryRestoreFromBackup()
		{
			if (!File.Exists(BackupPath))
			{
				return false;
			}
			try
			{
				string json = File.ReadAllText(BackupPath);
				Dictionary<string, int> assignments = new Dictionary<string, int>();
				Dictionary<string, int> assignments2 = _assignments;
				_assignments = assignments;
				ParseJson(json);
				int count = _assignments.Count;
				_assignments = assignments2;
				if (count == 0)
				{
					return false;
				}
				_assignments = assignments;
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)$"CategoryShelfManager: Restored {count} assignments from backup.");
				}
				Save();
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("CategoryShelfManager: Failed to restore from backup: " + ex.Message));
				}
				return false;
			}
		}

		private void Save()
		{
			try
			{
				string directoryName = Path.GetDirectoryName(_savePath);
				if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("{");
				stringBuilder.AppendLine("  \"version\": 1,");
				stringBuilder.AppendLine("  \"assignments\": {");
				int num = 0;
				foreach (KeyValuePair<string, int> assignment in _assignments)
				{
					num++;
					string arg = ((num < _assignments.Count) ? "," : "");
					stringBuilder.AppendLine($"    \"{EscapeJson(assignment.Key)}\": {assignment.Value}{arg}");
				}
				stringBuilder.AppendLine("  }");
				stringBuilder.AppendLine("}");
				File.WriteAllText(_savePath, stringBuilder.ToString());
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)$"CategoryShelfManager: Saved {_assignments.Count} assignments to {_savePath}");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogError((object)("CategoryShelfManager: Failed to save: " + ex.Message));
				}
			}
		}

		private void Load()
		{
			_assignments.Clear();
			if (!File.Exists(_savePath))
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)"CategoryShelfManager: No save file found, starting fresh.");
				}
				return;
			}
			try
			{
				string json = File.ReadAllText(_savePath);
				ParseJson(json);
				PurgeCorruptKeys();
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogInfo((object)$"CategoryShelfManager: Loaded {_assignments.Count} assignments from {_savePath}");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = _log;
				if (log3 != null)
				{
					log3.LogError((object)("CategoryShelfManager: Failed to load: " + ex.Message));
				}
			}
			if (_assignments.Count == 0 && File.Exists(BackupPath))
			{
				ManualLogSource log4 = _log;
				if (log4 != null)
				{
					log4.LogWarning((object)"CategoryShelfManager: Main file has 0 assignments but backup exists — attempting restore.");
				}
				TryRestoreFromBackup();
			}
		}

		private void ParseJson(string json)
		{
			int num = json.IndexOf("\"assignments\"", StringComparison.Ordinal);
			if (num < 0)
			{
				return;
			}
			int num2 = json.IndexOf('{', num + 13);
			if (num2 < 0)
			{
				return;
			}
			int num3 = json.IndexOf('}', num2);
			if (num3 < 0)
			{
				return;
			}
			string[] array = json.Substring(num2 + 1, num3 - num2 - 1).Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim().TrimEnd(new char[1] { ',' });
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				int num4 = text.IndexOf('"');
				if (num4 < 0)
				{
					continue;
				}
				int num5 = text.LastIndexOf('"');
				if (num5 > num4)
				{
					string text2 = text.Substring(num4 + 1, num5 - num4 - 1);
					string s = text.Substring(text.LastIndexOf(':') + 1).Trim();
					if (!string.IsNullOrEmpty(text2) && int.TryParse(s, out var result))
					{
						_assignments[text2] = result;
					}
				}
			}
		}

		private void PurgeCorruptKeys()
		{
			List<string> list = new List<string>();
			foreach (string key in _assignments.Keys)
			{
				string[] array = key.Split(new char[1] { ',' });
				if (array.Length != 3 || !int.TryParse(array[0], out var result) || !int.TryParse(array[1], out result) || !int.TryParse(array[2], out result))
				{
					list.Add(key);
				}
			}
			if (list.Count <= 0)
			{
				return;
			}
			foreach (string item in list)
			{
				_assignments.Remove(item);
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("CategoryShelfManager: Removed corrupt key: '" + item + "'"));
				}
			}
			Save();
		}

		private static string EscapeJson(string s)
		{
			return s.Replace("\\", "\\\\").Replace("\"", "\\\"");
		}
	}
	public class CoroutineRunner : MonoBehaviour
	{
		public static CoroutineRunner Instance { get; private set; }

		public static void Initialize()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (!((Object)(object)Instance != (Object)null))
			{
				GameObject val = new GameObject("OAO_CoroutineRunner");
				Object.DontDestroyOnLoad((Object)val);
				Instance = val.AddComponent<CoroutineRunner>();
			}
		}

		public Coroutine StartTrackedCoroutine(IEnumerator routine)
		{
			return ((MonoBehaviour)this).StartCoroutine(routine);
		}
	}
	public class InventoryScanner
	{
		private readonly ManualLogSource _log;

		private readonly GameInventoryAdapter _inventory;

		private readonly GameProductCatalogAdapter _catalog;

		private readonly GameShoppingListAdapter _shoppingList;

		private readonly PendingOrderTracker _pendingTracker;

		private readonly bool _verbose;

		public InventoryScanner(ManualLogSource log, GameInventoryAdapter inventory, GameProductCatalogAdapter catalog, GameShoppingListAdapter shoppingList, PendingOrderTracker pendingTracker, bool verbose)
		{
			_log = log;
			_inventory = inventory;
			_catalog = catalog;
			_shoppingList = shoppingList;
			_pendingTracker = pendingTracker;
			_verbose = verbose;
		}

		public List<ProductStockSnapshot> ScanAll()
		{
			List<ProductStockSnapshot> list = new List<ProductStockSnapshot>();
			ProductListing productListing = _catalog.GetProductListing();
			ManagerBlackboard managerBlackboard = _catalog.GetManagerBlackboard();
			if ((Object)(object)productListing == (Object)null || (Object)(object)managerBlackboard == (Object)null)
			{
				_log.LogWarning((object)"Cannot scan: ProductListing or ManagerBlackboard not available.");
				return list;
			}
			if (!_inventory.Resolve())
			{
				_log.LogError((object)"Cannot scan: GetProductsExistences method not resolved.");
				return list;
			}
			List<int> availableProducts = _catalog.GetAvailableProducts(productListing);
			if (availableProducts == null || availableProducts.Count == 0)
			{
				_log.LogDebug((object)"No available products to scan.");
				return list;
			}
			foreach (int item in availableProducts)
			{
				try
				{
					ProductStockSnapshot productStockSnapshot = ScanProduct(managerBlackboard, productListing, item);
					if (productStockSnapshot != null)
					{
						list.Add(productStockSnapshot);
					}
				}
				catch (Exception ex)
				{
					_log.LogWarning((object)$"Error scanning product {item}: {ex.Message}");
				}
			}
			_log.LogDebug((object)$"Scan complete: {list.Count} products scanned.");
			return list;
		}

		private ProductStockSnapshot ScanProduct(ManagerBlackboard blackboard, ProductListing listing, int productId)
		{
			if (listing.productsData == null || productId < 0 || productId >= listing.productsData.Length)
			{
				return null;
			}
			bool flag = _catalog.IsProductUnlocked(listing, productId);
			int[] productExistences = _inventory.GetProductExistences(blackboard, productId);
			if (productExistences == null || productExistences.Length < 3)
			{
				return null;
			}
			int num = productExistences[0];
			int num2 = productExistences[1];
			int num3 = productExistences[2];
			int num4 = 0;
			PendingAutomatedOrder pendingAutomatedOrder = _pendingTracker?.GetPendingOrder(productId);
			if (pendingAutomatedOrder != null)
			{
				int num5 = Math.Max(0, num3 - pendingAutomatedOrder.InMovementBeforePurchase);
				num4 = Math.Max(0, pendingAutomatedOrder.OrderedUnits - num5);
			}
			string productName = _catalog.GetProductName(productId);
			int maxItemsPerBox = _catalog.GetMaxItemsPerBox(listing, productId);
			float boxPrice = _catalog.GetBoxPrice(listing, productId);
			bool flag2 = _shoppingList.IsProductOnShoppingList(blackboard, productId);
			ProductStockSnapshot productStockSnapshot = new ProductStockSnapshot
			{
				ProductId = productId,
				ProductName = productName,
				OnShelves = num,
				InStorage = num2,
				InMovement = num3,
				PendingUnreflectedUnits = num4,
				UnitsPerBox = maxItemsPerBox,
				BoxPrice = boxPrice,
				IsUnlocked = flag,
				IsOrderable = (flag && maxItemsPerBox > 0),
				IsOnShoppingList = flag2
			};
			if (_verbose)
			{
				_log.LogDebug((object)($"Product={productName} ProductId={productId} " + $"OnShelves={num} InStorage={num2} InMovement={num3} " + $"PendingUnreflected={num4} CombinedStock={productStockSnapshot.CombinedStock} " + $"EffectiveCombinedStock={productStockSnapshot.EffectiveCombinedStock} " + $"UnitsPerBox={maxItemsPerBox} BoxPrice={boxPrice:F2} " + $"AlreadyOnShoppingList={flag2}"));
			}
			return productStockSnapshot;
		}
	}
	public class NotificationService
	{
		private readonly GameNotificationAdapter _adapter;

		private readonly bool _enabled;

		public NotificationService(GameNotificationAdapter adapter, bool enabled)
		{
			_adapter = adapter;
			_enabled = enabled;
		}

		public void NotifyAutomationEnabled()
		{
			if (_enabled)
			{
				_adapter.ShowNotification("Order & Organize automation enabled.");
			}
		}

		public void NotifyAutomationDisabled()
		{
			if (_enabled)
			{
				_adapter.ShowNotification("Order & Organize automation disabled.");
			}
		}

		public void NotifyManualResult(int added, int skipped, int threshold)
		{
			if (!_enabled)
			{
				return;
			}
			if (added == 0 && skipped == 0)
			{
				_adapter.ShowNotification($"Order & Organize: nothing is below {threshold} units.");
				return;
			}
			string message = $"Order & Organize: added {added} products to the shopping list.";
			if (skipped > 0)
			{
				message = $"Order & Organize: added {added} products, skipped {skipped} already listed.";
			}
			_adapter.ShowNotification(message);
		}

		public void NotifyAutomationResult(AutomationCycleResult result)
		{
			if (_enabled && (result.HasPurchases || result.HasSkips))
			{
				if (result.ProductsPurchased > 0 && result.ProductsSkippedInsufficientFunds > 0)
				{
					_adapter.ShowImportantNotification($"Auto-Order: {result.ProductsPurchased} boxes purchased for ${result.TotalSpent:F2} " + $"({result.ProductsSkippedInsufficientFunds} skipped - low funds)");
				}
				else if (result.ProductsPurchased > 0)
				{
					_adapter.ShowImportantNotification($"Auto-Order: {result.ProductsPurchased} boxes purchased for ${result.TotalSpent:F2}");
				}
			}
		}

		public void NotifyManualListBlocking()
		{
			if (_enabled)
			{
				_adapter.ShowRateLimitedNotification("manual_list_block", "Order & Organize paused: manual shopping list is not empty.");
			}
		}

		public void NotifyNotAuthority()
		{
			if (_enabled)
			{
				_adapter.ShowRateLimitedNotification("not_authority", "Order & Organize: automation disabled (not host).");
			}
		}

		public void NotifyCompatibilityError(string detail)
		{
			_adapter.ShowNotification("Order & Organize could not access the current ordering system. Check BepInEx logs.");
		}
	}
	public class PendingOrderTracker
	{
		private readonly ManualLogSource _log;

		private readonly Dictionary<int, PendingAutomatedOrder> _pendingOrders = new Dictionary<int, PendingAutomatedOrder>();

		public int Count => _pendingOrders.Count;

		public PendingOrderTracker(ManualLogSource log)
		{
			_log = log;
		}

		public void RecordOrder(ProductStockSnapshot snapshot, float boxPrice)
		{
			PendingAutomatedOrder pendingAutomatedOrder = new PendingAutomatedOrder
			{
				ProductId = snapshot.ProductId,
				ProductName = snapshot.ProductName,
				OrderedUnits = snapshot.UnitsPerBox,
				UnitsPerBox = snapshot.UnitsPerBox,
				PurchaseTimestamp = DateTime.UtcNow,
				CombinedStockBeforePurchase = snapshot.CombinedStock,
				InMovementBeforePurchase = snapshot.InMovement,
				ExpectedCombinedStock = snapshot.CombinedStock + snapshot.UnitsPerBox,
				BoxPrice = boxPrice
			};
			_pendingOrders[snapshot.Product