using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using SolutionCleanupTool.Interfaces; using SolutionCleanupTool.Models; namespace SolutionCleanupTool.Services { /// /// Generates detailed cleanup reports with removed projects, error messages, and restoration recommendations /// public class ReportGenerator : IReportGenerator { /// /// Generates a comprehensive cleanup report including all changes, validation results, and recommendations /// /// The result of the cleanup operation /// The result of post-cleanup validation /// Path to the original solution file /// Formatted report as a string public string GenerateReport(CleanupResult cleanupResult, ValidationResult validationResult, string solutionPath) { var report = new StringBuilder(); // Header report.AppendLine("=".PadRight(80, '=')); report.AppendLine("SOLUTION CLEANUP REPORT"); report.AppendLine("=".PadRight(80, '=')); report.AppendLine(); // Basic Information report.AppendLine("BASIC INFORMATION"); report.AppendLine("-".PadRight(40, '-')); report.AppendLine($"Solution File: {Path.GetFileName(solutionPath)}"); report.AppendLine($"Solution Path: {solutionPath}"); report.AppendLine($"Cleanup Date: {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); report.AppendLine($"Cleanup Status: {(cleanupResult.Success ? "SUCCESS" : "FAILED")}"); report.AppendLine(); // Summary Statistics report.AppendLine(GenerateSummary(cleanupResult)); // Backup Information if (!string.IsNullOrEmpty(cleanupResult.BackupFilePath)) { report.AppendLine("BACKUP INFORMATION"); report.AppendLine("-".PadRight(40, '-')); report.AppendLine($"Backup Location: {cleanupResult.BackupFilePath}"); report.AppendLine($"Backup Created: {(File.Exists(cleanupResult.BackupFilePath) ? "YES" : "NO")}"); report.AppendLine(); } // Detailed Removal Information if (cleanupResult.RemovedProjects.Any()) { report.AppendLine("REMOVED PROJECTS DETAILS"); report.AppendLine("-".PadRight(40, '-')); for (int i = 0; i < cleanupResult.RemovedProjects.Count; i++) { var project = cleanupResult.RemovedProjects[i]; report.AppendLine($"{i + 1}. {project.Reference.Name}"); report.AppendLine($" Expected Path: {project.ExpectedPath}"); report.AppendLine($" Project GUID: {project.Reference.ProjectGuid}"); if (!string.IsNullOrEmpty(project.ErrorMessage)) { report.AppendLine($" Error Message: {project.ErrorMessage}"); } if (project.ReferencingProjects.Any()) { report.AppendLine($" Referenced By: {string.Join(", ", project.ReferencingProjects)}"); } report.AppendLine(); } } // Warnings if (cleanupResult.Warnings.Any()) { report.AppendLine("WARNINGS"); report.AppendLine("-".PadRight(40, '-')); foreach (var warning in cleanupResult.Warnings) { report.AppendLine($"• {warning}"); } report.AppendLine(); } // Validation Results report.AppendLine("POST-CLEANUP VALIDATION"); report.AppendLine("-".PadRight(40, '-')); report.AppendLine($"Solution Valid: {(validationResult.IsValid ? "YES" : "NO")}"); report.AppendLine($"Can Load Solution: {(validationResult.CanLoadSolution ? "YES" : "NO")}"); report.AppendLine($"Has Circular References: {(validationResult.HasCircularReferences ? "YES" : "NO")}"); if (validationResult.Errors.Any()) { report.AppendLine(); report.AppendLine("Validation Errors:"); foreach (var error in validationResult.Errors) { report.AppendLine($"• {error}"); } } if (validationResult.Warnings.Any()) { report.AppendLine(); report.AppendLine("Validation Warnings:"); foreach (var warning in validationResult.Warnings) { report.AppendLine($"• {warning}"); } } report.AppendLine(); // Restoration Recommendations if (cleanupResult.RemovedProjects.Any()) { report.AppendLine(GenerateRestorationRecommendations(cleanupResult.RemovedProjects)); } // Footer report.AppendLine("=".PadRight(80, '=')); report.AppendLine("END OF REPORT"); report.AppendLine("=".PadRight(80, '=')); return report.ToString(); } /// /// Generates a concise summary report with key statistics /// /// The result of the cleanup operation /// Summary report as a string public string GenerateSummary(CleanupResult cleanupResult) { var summary = new StringBuilder(); summary.AppendLine("CLEANUP SUMMARY"); summary.AppendLine("-".PadRight(40, '-')); summary.AppendLine($"Total Projects Removed: {cleanupResult.TotalProjectsRemoved}"); summary.AppendLine($"Projects with Details: {cleanupResult.RemovedProjects.Count}"); summary.AppendLine($"Warnings Generated: {cleanupResult.Warnings.Count}"); summary.AppendLine($"Operation Status: {(cleanupResult.Success ? "Completed Successfully" : "Failed")}"); if (cleanupResult.RemovedProjects.Any()) { var projectsWithReferences = cleanupResult.RemovedProjects.Count(p => p.ReferencingProjects.Any()); summary.AppendLine($"Projects Referenced by Others: {projectsWithReferences}"); var totalReferences = cleanupResult.RemovedProjects.Sum(p => p.ReferencingProjects.Count); summary.AppendLine($"Total Reference Relationships Removed: {totalReferences}"); } summary.AppendLine(); return summary.ToString(); } /// /// Generates detailed restoration recommendations for removed projects /// /// List of projects that were removed /// Restoration recommendations as a string public string GenerateRestorationRecommendations(List removedProjects) { var recommendations = new StringBuilder(); recommendations.AppendLine("RESTORATION RECOMMENDATIONS"); recommendations.AppendLine("-".PadRight(40, '-')); if (!removedProjects.Any()) { recommendations.AppendLine("No projects were removed, so no restoration is needed."); recommendations.AppendLine(); return recommendations.ToString(); } recommendations.AppendLine("If you need to restore any of the removed projects, follow these steps:"); recommendations.AppendLine(); recommendations.AppendLine("GENERAL RESTORATION STEPS:"); recommendations.AppendLine("1. Locate or recreate the missing project files"); recommendations.AppendLine("2. Restore the original solution file from the backup"); recommendations.AppendLine("3. Ensure project files are in the expected locations"); recommendations.AppendLine("4. Rebuild the solution to verify all references work"); recommendations.AppendLine(); recommendations.AppendLine("PROJECT-SPECIFIC RECOMMENDATIONS:"); recommendations.AppendLine(); for (int i = 0; i < removedProjects.Count; i++) { var project = removedProjects[i]; recommendations.AppendLine($"{i + 1}. {project.Reference.Name}"); recommendations.AppendLine($" Expected Location: {project.ExpectedPath}"); // Provide specific recommendations based on the project type if (!string.IsNullOrEmpty(project.Reference.ProjectTypeGuid)) { var projectType = GetProjectTypeDescription(project.Reference.ProjectTypeGuid); recommendations.AppendLine($" Project Type: {projectType}"); } // Suggest possible locations to look for the project var possibleLocations = GeneratePossibleLocations(project.ExpectedPath); if (possibleLocations.Any()) { recommendations.AppendLine(" Possible Alternative Locations:"); foreach (var location in possibleLocations) { recommendations.AppendLine($" • {location}"); } } // If the project was referenced by others, mention the impact if (project.ReferencingProjects.Any()) { recommendations.AppendLine($" Impact: This project was referenced by {project.ReferencingProjects.Count} other project(s)"); recommendations.AppendLine($" Affected Projects: {string.Join(", ", project.ReferencingProjects)}"); } recommendations.AppendLine(); } recommendations.AppendLine("ALTERNATIVE SOLUTIONS:"); recommendations.AppendLine("• If projects are permanently removed, consider updating dependent projects"); recommendations.AppendLine("• Check source control history for when projects were last available"); recommendations.AppendLine("• Consider creating stub projects if dependencies are critical"); recommendations.AppendLine("• Review project documentation for migration or replacement guidance"); recommendations.AppendLine(); return recommendations.ToString(); } /// /// Gets a human-readable description of the project type based on GUID /// /// The project type GUID /// Description of the project type private string GetProjectTypeDescription(string projectTypeGuid) { // Common Visual Studio project type GUIDs var projectTypes = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", "C# Project" }, { "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}", "VB.NET Project" }, { "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "C++ Project" }, { "{349C5851-65DF-11DA-9384-00065B846F21}", "Web Application Project" }, { "{E24C65DC-7377-472B-9ABA-BC803B73C61A}", "Web Site Project" }, { "{F85E285D-A4E0-4152-9332-AB1D724D3325}", "Modeling Project" }, { "{A9ACE9BB-CECE-4E62-9AA4-C7E7C5BD2124}", "Database Project" }, { "{4F174C21-8C12-11D0-8340-0000F80270F8}", "Database Project (Legacy)" }, { "{3AC096D0-A1C2-E12C-1390-A8335801FDAB}", "Test Project" }, { "{F2A71F9B-5D33-465A-A702-920D77279786}", "F# Project" } }; return projectTypes.TryGetValue(projectTypeGuid, out var description) ? description : $"Unknown Project Type ({projectTypeGuid})"; } /// /// Generates possible alternative locations where a missing project might be found /// /// The expected path of the missing project /// List of possible alternative locations private List GeneratePossibleLocations(string expectedPath) { var locations = new List(); if (string.IsNullOrEmpty(expectedPath)) return locations; try { var fileName = Path.GetFileName(expectedPath); var directory = Path.GetDirectoryName(expectedPath); var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(expectedPath); if (!string.IsNullOrEmpty(directory) && !string.IsNullOrEmpty(fileName)) { // Common alternative locations locations.Add(Path.Combine(directory, "src", fileName)); locations.Add(Path.Combine(directory, "Source", fileName)); locations.Add(Path.Combine(directory, fileNameWithoutExtension, fileName)); locations.Add(Path.Combine(Path.GetDirectoryName(directory) ?? "", fileName)); // Check for common renamed patterns if (fileNameWithoutExtension.Contains(".")) { var parts = fileNameWithoutExtension.Split('.'); if (parts.Length > 1) { locations.Add(Path.Combine(directory, $"{parts[0]}.csproj")); } } } } catch (Exception) { // If path parsing fails, return empty list } return locations.Distinct().ToList(); } } }