using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using System.Text.Json.Nodes;
using System.ServiceProcess;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Threading;
using JJServiceManager.Remote;
using Forms = System.Windows.Forms;
namespace JJServiceManager
{
/// 초기화면
public sealed class MainWindow : Window
{
private static readonly TimeSpan OpTimeout = TimeSpan.FromSeconds(60);
private readonly AppSettings _settings;
private readonly FrameworkElement _root;
private readonly ObservableCollection _groups = new ObservableCollection();
private readonly HostGroup _local;
private readonly LogPanel _log;
private readonly LogWindowManager _logWindows;
private readonly DispatcherTimer _statusTimer;
private readonly RemoteServer _remoteServer;
private readonly PassiveHub _passiveHub;
private readonly RelayAgent _relayAgent;
private readonly RelayManager _relayManager;
private string _relayAgentKey = "", _relayManageKey = "";
private string _relayLoginNotice;
/// 중계 기기 그룹의 표시용 대상 정보 (그룹 Id → 대상)
private readonly Dictionary _relayTargets = new Dictionary(StringComparer.OrdinalIgnoreCase);
/// 시작할 때 열려 있던 중계 기기 탭 (로그인 뒤 기기 목록을 받으면 다시 엶)
private readonly HashSet _pendingRelayTabs = new HashSet(StringComparer.OrdinalIgnoreCase);
private RemoteIndicatorWindow _indicator;
private readonly Dictionary _viewers = new Dictionary(StringComparer.OrdinalIgnoreCase);
private string _passiveKey = "";
private string _passiveListenKey = "";
private readonly TabControl _tabs;
private readonly TabItem _tabAll;
private readonly ComboBox _cmbAddTab;
private readonly CheckBox _chkAll;
private readonly TextBlock _txtCount, _txtLogHidden;
private readonly ContentControl _ccLog;
private readonly FrameworkElement _pnlShutdown;
private readonly Dictionary _hostTabs = new Dictionary(StringComparer.OrdinalIgnoreCase);
/// 원격 접속 허용 쪽에 넘겨줄 등록 서비스 목록 (다른 스레드에서 읽음)
private volatile IReadOnlyList _servicesSnapshot = Array.Empty();
private string _serverKey = "";
private string _targetsKey = "";
private Forms.NotifyIcon _tray;
private HotkeyManager _hotkey;
private bool _exiting;
private bool _refreshing;
private bool _trayTipShown;
private bool _modalOpen;
public MainWindow(AppSettings settings)
{
_settings = settings;
Title = "JJServiceManager - 서비스 관리" + AppInstance.TitleTag;
FontFamily = new FontFamily("Malgun Gothic");
FontSize = 13;
Background = Brushes2.Make("#F5F7F8");
MinWidth = 860;
MinHeight = 560;
AppIcon.Apply(this);
RestoreWindowBounds(settings);
_root = XamlLoader.LoadElement("MainWindow.xaml");
Content = _root;
_tabs = _root.Find("tabHosts");
_tabAll = _root.Find("tabAll");
_cmbAddTab = _root.Find("cmbAddTab");
_chkAll = _root.Find("chkAll");
_txtCount = _root.Find("txtCount");
_txtLogHidden = _root.Find("txtLogHidden");
_ccLog = _root.Find("ccLog");
_pnlShutdown = _root.Find("pnlShutdown");
_log = new LogPanel { ShowTimestamp = true };
_ccLog.Content = _log;
_logWindows = new LogWindowManager(() => _settings, SaveSettings, LogChoices);
// 내 PC
_local = new HostGroup
{
Id = HostGroup.LocalId,
Title = $"내 PC ({Environment.MachineName})",
EmptyText = "[추가] 버튼을 눌러 관리할 서비스를 등록하세요."
};
foreach (var e in settings.Services) _local.Rows.Add(new ServiceRow(e, _local));
_local.Rows.CollectionChanged += (s, e) => UpdateCounts();
_groups.Add(_local);
UpdateSnapshot();
_root.Find("icGroups").ItemsSource = _groups;
_cmbAddTab.ItemsSource = _groups;
_cmbAddTab.SelectionChanged += OnAddTabSelected;
_tabs.SelectionChanged += (s, e) => { if (e.Source == _tabs) UpdateCounts(); };
// 상단 버튼
_root.Find