#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
using static UVC.UIToolkit.UTKStyleGuide;
namespace UVC.UIToolkit
{
///
/// 계층적 트리 구조를 표시하는 커스텀 UI Toolkit 컴포넌트입니다.
///
/// 개요:
///
/// UTKTreeListWindow는 Unity UI Toolkit의 TreeView를 래핑하여 검색, 가시성 토글,
/// 닫기 기능 등을 제공하는 재사용 가능한 컴포넌트입니다.
/// UXML 파일(UTKTreeListWindow.uxml, UTKTreeListItem.uxml)과 함께 사용됩니다.
///
///
/// 주요 기능:
///
/// - 계층적 트리 구조 표시 (펼치기/접기 지원)
/// - 실시간 검색 필터링
/// - 항목별 가시성(눈 아이콘) 토글
/// - 다중 선택 지원
/// - 삭제 기능 (Delete/Backspace 키)
///
///
/// UXML 사용 예시:
///
///
///
///
/// ]]>
///
/// C# 사용 예시:
/// ("tree-list-window");
///
/// // 2. 윈도우 제목 및 닫기 버튼 설정
/// treeWindow.Title = "씬 계층구조";
/// treeWindow.ShowCloseButton = true;
///
/// // 3. 데이터 구성 - 계층적 트리 구조
/// var data = new List
/// {
/// new UTKTreeListItemData
/// {
/// name = "루트 오브젝트",
/// isExpanded = true,
/// IsVisible = true,
/// children = new List
/// {
/// new UTKTreeListItemData
/// {
/// name = "자식 오브젝트 1",
/// IsVisible = true
/// },
/// new UTKTreeListItemData
/// {
/// name = "자식 오브젝트 2",
/// IsVisible = false,
/// children = new List
/// {
/// new UTKTreeListItemData { name = "손자 오브젝트" }
/// }
/// }
/// }
/// }
/// };
/// treeWindow.SetData(data);
///
/// // 4. 선택 변경 이벤트 구독 (선택 및 해제 모두)
/// treeWindow.OnSelectionChanged += (selectedItems) =>
/// {
/// Debug.Log($"선택된 아이템 수: {selectedItems.Count}");
/// foreach (var item in selectedItems)
/// {
/// Debug.Log($"선택: {item.name}");
/// }
/// };
///
/// // 5. 가시성 변경 이벤트 (눈 아이콘 클릭)
/// treeWindow.OnVisibilityChanged += (item) =>
/// {
/// Debug.Log($"{item.name} 가시성: {item.IsVisible}");
/// // 3D 씬에서 해당 오브젝트 활성화/비활성화
/// var gameObject = FindGameObjectByName(item.name);
/// if (gameObject != null)
/// {
/// gameObject.SetActive(item.IsVisible);
/// }
/// };
///
/// // 6. 삭제 이벤트 (Delete/Backspace 키)
/// treeWindow.EnabledDeleteItem = true;
/// treeWindow.OnItemDeleted += (item) =>
/// {
/// Debug.Log($"삭제 요청: {item.name}");
/// // 데이터에서 제거 후 UI 갱신
/// RemoveFromData(item);
/// treeWindow.Rebuild();
/// };
///
/// // 7. 윈도우 닫힘 이벤트
/// treeWindow.OnClosed += () =>
/// {
/// Debug.Log("윈도우가 닫혔습니다.");
/// };
///
/// // 8. 검색 실행
/// treeWindow.ApplySearch("자식");
/// // 검색어는 SearchQuery 속성으로 확인 가능
/// string currentQuery = treeWindow.SearchQuery;
///
/// // 9. 프로그래밍 방식 선택
/// treeWindow.SelectByItemId(itemId);
///
/// // 10. 전체 펼치기/접기
/// treeWindow.ExpandAll();
/// treeWindow.CollapseAll();
///
/// // 11. TreeView 갱신 (데이터 변경 후)
/// treeWindow.Rebuild();
///
/// // 12. 윈도우 표시/숨김
/// treeWindow.Show();
/// treeWindow.Hide();
///
/// // 13. 리소스 해제 (OnDestroy에서 호출)
/// treeWindow.Dispose();
/// ]]>
///
/// 관련 리소스:
///
/// - Resources/UIToolkit/Window/UTKTreeListWindow.uxml - 메인 레이아웃
/// - Resources/UIToolkit/List/UTKTreeListItem.uxml - 개별 항목 템플릿
///
///
/// 선택 해제 방지:
///
/// 빈 영역 클릭 시 선택이 해제되지 않도록 하려면 EventSystem의 InputSystemUIInputModule 컴포넌트에서
/// Deselect On Background Click 옵션을 해제해야 합니다.
///
///
[UxmlElement]
public partial class UTKTreeListWindow : VisualElement, IDisposable
{
#region IDisposable
private bool _disposed = false;
#endregion
#region 상수 (Constants)
/// 메인 UXML 파일 경로 (Resources 폴더 기준)
private const string UXML_PATH = "UIToolkit/Window/UTKTreeListWindow";
/// USS 파일 경로 (Resources 폴더 기준)
private const string USS_PATH = "UIToolkit/Window/UTKTreeListWindowUss";
#endregion
#region UI 컴포넌트 참조 (UI Component References)
/// 검색어 입력 필드
private UTKInputField? _searchField;
/// Unity UI Toolkit의 TreeView 컴포넌트
private TreeView? _treeView;
/// 트리 리스트 닫기 버튼 (UTKButton)
private UTKButton? _closeButton;
/// 검색어 지우기 버튼 (UTKButton)
private UTKButton? _clearButton;
/// 윈도우 제목 라벨
private Label? _titleLabel;
#endregion
#region 내부 데이터 (Internal Data)
///
/// 원본 루트 데이터입니다.
/// 검색 필터 해제 시 원래 데이터로 복원하는 데 사용됩니다.
///
private List _originalRoots = new();
///
/// TreeView에 바인딩되는 데이터 소스입니다.
/// TreeViewItemData는 Unity의 TreeView가 요구하는 래퍼 타입입니다.
///
private List>? _rootData;
///
/// 항목 ID 자동 생성을 위한 시드 값입니다.
/// SetData() 호출 시 id가 0인 항목에 순차적으로 ID를 할당합니다.
///
private int _idSeed = 1;
///
/// 이전에 선택된 항목들입니다.
/// 선택 해제 이벤트 발송에 사용됩니다.
///
private List _previouslySelectedItems = new();
///
/// 선택 이벤트 발송을 일시적으로 억제하는 플래그입니다.
/// 프로그래밍 방식으로 선택 시 이벤트를 발송하지 않으려면 true로 설정합니다.
///
private bool _suppressSelectionEvent = false;
///
/// 펼침/접힘 이벤트 처리를 일시적으로 억제하는 플래그입니다.
/// ExpandByData() 실행 중 이벤트로 인한 데이터 덮어쓰기를 방지합니다.
///
private bool _suppressExpandEvent = false;
#endregion
#region 공개 속성 (Public Properties)
///
/// 항목 삭제 기능 활성화 여부입니다.
/// true일 때만 Delete/Backspace 키로 항목 삭제 이벤트가 발생합니다.
/// 기본값은 true입니다.
///
public bool EnabledDeleteItem { get; set; } = true;
/// 윈도우 제목
public string Title
{
get => _titleLabel?.text ?? string.Empty;
set { if (_titleLabel != null) _titleLabel.text = value; }
}
/// 닫기 버튼 표시 여부
public bool ShowCloseButton
{
get => _closeButton?.style.display == DisplayStyle.Flex;
set { if (_closeButton != null) _closeButton.style.display = value ? DisplayStyle.Flex : DisplayStyle.None; }
}
#endregion
#region 외부 이벤트 (Public Events)
///
/// 메인/검색 리스트에서 항목이 선택될 때 발생합니다.
///
public Action>? OnItemSelected;
///
/// 메인/검색 리스트에서 항목이 선택 해제될 때 발생합니다.
///
public Action>? OnItemDeselected;
///
/// 항목의 가시성(눈 아이콘)이 변경될 때 발생합니다.
/// 3D 모델의 GameObject 활성화/비활성화에 연동합니다.
///
public event Action? OnItemVisibilityChanged;
///
/// 메인/검색 리스트에서 항목이 삭제될 때 발생합니다 (Delete 키).
///
public Action? OnItemDeleted;
///
/// 메인/검색 리스트에서 항목이 더블클릭될 때 발생합니다.
///
public Action? OnItemDoubleClicked;
///
/// 트리 리스트가 닫힐 때(숨겨질 때) 발생합니다.
/// 닫기 버튼 클릭 시 트리거됩니다.
///
public event Action? OnClosed;
#endregion
#region 생성자 (Constructor)
///
/// TreeListWindow 컴포넌트를 초기화합니다.
/// UXML 템플릿을 로드하고 내부 컴포넌트를 설정합니다.
///
public UTKTreeListWindow()
{
// 1. 메인 UXML 로드 및 복제
// CloneTree(this)로 UXML 내용이 이 클래스의 자식으로 추가됨
var visualTree = Resources.Load(UXML_PATH);
if (visualTree == null)
{
Debug.LogError($"[TreeMenu] UXML not found at: {UXML_PATH}");
return;
}
visualTree!.CloneTree(this);
// 2. 테마 적용
UTKThemeManager.Instance.ApplyThemeToElement(this);
SubscribeToThemeChanges();
// USS 로드 (테마 변수 스타일시트 이후에 로드되어야 변수가 해석됨)
var uss = Resources.Load(USS_PATH);
if (uss != null)
{
styleSheets.Add(uss);
}
// 3. 자식 요소 참조 획득 (UXML의 name 속성으로 찾음)
_searchField = this.Q("search-field");
_treeView = this.Q("main-tree-view");
_titleLabel = this.Q