using System;
using System.IO;
using UnityEngine;
using System.Collections.Generic;
using IntelligentProjectAnalyzer.Helper;
using static IntelligentProjectAnalyzer.Editor.DependencyBuilderData;
namespace IntelligentProjectAnalyzer.Editor.DependencyViewer
{
///
/// Loads, parses, and organizes dependency data from the cache into a queryable graph.
/// This version reads the unified AssetMetadata structure.
///
public class DependencyGraph
{
// Maps an asset's GUID to a list of GUIDs it depends.
private readonly Dictionary> _dependencies = new();
// Maps an asset's GUID to a list of GUIDs that reference it.
private readonly Dictionary> _references = new();
private readonly HashSet _allKnownGuids = new();
///
/// Initializes a new instance of the DependencyGraph class and builds it from the cache.
///
public DependencyGraph()
{
BuildGraph();
}
///
/// Gets the list of assets that the specified asset depends on.
///
public List GetDependencies(string guid)
{
return _dependencies.TryGetValue(guid, out var dependencies) ? dependencies : new List();
}
///
/// Gets the list of assets that reference the specified asset.
///
public List GetReferences(string guid)
{
return _references.TryGetValue(guid, out var refs) ? refs : new List();
}
///
/// Checks if the graph contains any data related to the given asset GUID.
///
public bool AssetExists(string guid)
{
return _allKnownGuids.Contains(guid);
}
///
/// Clears and rebuilds the entire dependency graph by reading from the cache.
///
public void BuildGraph()
{
_dependencies.Clear();
_references.Clear();
_allKnownGuids.Clear();
var cachePath = DependencyCacheManager.GetCachePath();
if (!Directory.Exists(cachePath))
{
Debug.LogWarning("Cache directory does not exist. Skipping dependency graph build.");
return;
}
var files = Directory.GetFiles(cachePath, "*.json");
foreach (var file in files)
{
try
{
// First, deserialize the outer wrapper object.
var wrapper = JsonFileSystem.Read(file);
if (wrapper == null || string.IsNullOrEmpty(wrapper.JsonData))
{
continue;
}
// Dynamically get the concrete type from the stored index using our helper.
var concreteType = MetadataTypeHelper.GetTypeFromIndex(wrapper.AssetTypeIndex);
if (concreteType == null)
{
Debug.LogWarning($"Could not find a registered type for index '{wrapper.AssetTypeIndex}' during deserialization. Skipping file: {Path.GetFileName(file)}");
continue;
}
// Now, deserialize the nested JSON data into the correct concrete type.
var metadata = JsonFileSystem.Read(wrapper.JsonData, concreteType) as AssetMetadata;
if (metadata?.DependencyGuids == null) continue;
_dependencies[metadata.Guid] = metadata.DependencyGuids;
_allKnownGuids.Add(metadata.Guid);
foreach(var depGuid in metadata.DependencyGuids)
{
_allKnownGuids.Add(depGuid);
}
}
catch (Exception e)
{
Debug.LogError($"Failed to parse dependency file {Path.GetFileName(file)}. Error: {e.Message}");
}
}
// Now, build the inverse map (the references).
foreach (var (referrerGuid, dependencies) in _dependencies)
{
foreach (var dependencyGuid in dependencies)
{
if (!_references.ContainsKey(dependencyGuid))
{
_references[dependencyGuid] = new List();
}
_references[dependencyGuid].Add(referrerGuid);
}
}
}
}
}