Files
manual_wpf/Models/ExportExcel.cs
2025-08-13 13:57:46 +09:00

443 lines
18 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Teigha.Runtime;
namespace DwgExtractorManual.Models
{
/// <summary>
/// DWG 파일에서 Excel로 데이터 내보내기 메인 클래스
/// 리팩토링된 구조로 각 기능별 클래스를 조합하여 사용
/// </summary>
internal class ExportExcel : IDisposable
{
// 컴포넌트들
private readonly ExcelManager excelManager;
public readonly DwgDataExtractor DwgExtractor;
private readonly JsonDataProcessor jsonProcessor;
private readonly ExcelDataWriter excelWriter;
private readonly FieldMapper fieldMapper;
// ODA 서비스 관리
private Services? appServices;
// 매핑 데이터 저장용
private Dictionary<string, Dictionary<string, (string, string, string, string)>> FileToMapkeyToLabelTagValuePdf
= new Dictionary<string, Dictionary<string, (string, string, string, string)>>();
readonly List<string>? MapKeys;
/// <summary>
/// 생성자: 모든 컴포넌트 초기화
/// </summary>
public ExportExcel()
{
try
{
Debug.WriteLine("🔄 FieldMapper 로딩 중: mapping_table_json.json...");
fieldMapper = FieldMapper.LoadFromFile("fletimageanalysis/mapping_table_json.json");
Debug.WriteLine("✅ FieldMapper 로딩 성공");
MapKeys = fieldMapper.GetAllDocAiKeys() ?? new List<string>();
Debug.WriteLine($"📊 총 DocAI 키 개수: {MapKeys?.Count ?? 0}");
// 매핑 테스트 (디버깅용)
TestFieldMapper();
Debug.WriteLine("🔄 ODA 초기화 중...");
InitializeTeighaServices();
// 컴포넌트들 초기화
excelManager = new ExcelManager();
DwgExtractor = new DwgDataExtractor(fieldMapper);
jsonProcessor = new JsonDataProcessor();
excelWriter = new ExcelDataWriter(excelManager);
Debug.WriteLine("🔄 Excel 초기화 중...");
excelManager.InitializeExcel();
}
catch (System.Exception ex)
{
Debug.WriteLine($"❌ ExportExcel 초기화 오류: {ex.Message}");
throw;
}
}
/// <summary>
/// 단일 DWG 파일에서 데이터를 추출하여 Excel에 추가
/// </summary>
public bool ExportDwgToExcel(string filePath, IProgress<double>? progress = null, CancellationToken cancellationToken = default)
{
Debug.WriteLine($"[DEBUG] ExportDwgToExcel 시작: {filePath}");
if (excelManager.ExcelApplication == null)
{
Debug.WriteLine("❌ Excel이 초기화되지 않았습니다.");
return false;
}
if (!File.Exists(filePath))
{
Debug.WriteLine($"❌ 파일이 존재하지 않습니다: {filePath}");
return false;
}
try
{
// DWG 데이터 추출
var extractionResult = DwgExtractor.ExtractFromDwgFile(filePath, progress, cancellationToken);
if (extractionResult == null)
{
return false;
}
// Excel에 데이터 기록
excelWriter.WriteTitleBlockData(extractionResult.TitleBlockRows);
excelWriter.WriteTextEntityData(extractionResult.TextEntityRows);
// 매핑 데이터 병합
foreach (var fileEntry in extractionResult.FileToMapkeyToLabelTagValuePdf)
{
if (!FileToMapkeyToLabelTagValuePdf.ContainsKey(fileEntry.Key))
{
FileToMapkeyToLabelTagValuePdf[fileEntry.Key] = new Dictionary<string, (string, string, string, string)>();
}
foreach (var mapEntry in fileEntry.Value)
{
FileToMapkeyToLabelTagValuePdf[fileEntry.Key][mapEntry.Key] = mapEntry.Value;
}
}
// 매핑 데이터를 Excel에 기록
excelWriter.WriteMappingDataToExcel(FileToMapkeyToLabelTagValuePdf);
return true;
}
catch (System.Exception ex)
{
Debug.WriteLine($"❌ ExportDwgToExcel 오류: {ex.Message}");
return false;
}
}
/// <summary>
/// 기존 Excel 파일을 열어 JSON 파일의 PDF 분석 결과로 업데이트
/// </summary>
public bool UpdateExistingExcelWithJson(string excelFilePath, string jsonFilePath)
{
try
{
Debug.WriteLine($"[DEBUG] 기존 Excel 파일 업데이트 시작: {excelFilePath}");
if (!excelManager.OpenExistingFile(excelFilePath))
{
return false;
}
Debug.WriteLine("✅ 기존 Excel 파일 열기 성공");
return UpdateMappingSheetFromJson(jsonFilePath);
}
catch (System.Exception ex)
{
Debug.WriteLine($"❌ 기존 Excel 파일 업데이트 중 오류: {ex.Message}");
return false;
}
}
/// <summary>
/// JSON 파일에서 PDF 분석 결과를 읽어 Excel 매핑 시트 업데이트
/// </summary>
public bool UpdateMappingSheetFromJson(string jsonFilePath)
{
if (!File.Exists(jsonFilePath))
{
Debug.WriteLine($"❌ JSON 파일이 존재하지 않습니다: {jsonFilePath}");
return false;
}
// JSON 처리를 통해 매핑 데이터를 업데이트하고, Excel에 반영
return jsonProcessor.UpdateMappingDataFromJson(FileToMapkeyToLabelTagValuePdf, jsonFilePath) &&
UpdateExcelFromMappingData();
}
/// <summary>
/// DWG 파일들을 처리하여 Height 순으로 정렬된 Excel 파일 생성
/// </summary>
public void ExportDwgToExcelHeightSorted(string[] dwgFiles, string resultFolder)
{
try
{
Debug.WriteLine($"[DEBUG] Height 정렬 Excel 생성 시작: {dwgFiles.Length}개 파일");
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
string savePath = Path.Combine(resultFolder, $"{timestamp}_HeightSorted.xlsx");
var heightSortedWorkbook = excelManager.CreateNewWorkbook();
bool firstSheetProcessed = false;
foreach (string dwgFile in dwgFiles)
{
if (!File.Exists(dwgFile))
{
continue;
}
string fileName = Path.GetFileNameWithoutExtension(dwgFile);
try
{
Microsoft.Office.Interop.Excel.Worksheet worksheet = firstSheetProcessed ?
(Microsoft.Office.Interop.Excel.Worksheet)heightSortedWorkbook.Worksheets.Add() :
(Microsoft.Office.Interop.Excel.Worksheet)heightSortedWorkbook.Worksheets[1];
worksheet.Name = excelManager.GetValidSheetName(fileName);
firstSheetProcessed = true;
// Note 엔티티 먼저 추출
var noteEntities = DwgExtractor.ExtractNotesFromDrawing(dwgFile);
// Note에서 사용된 텍스트 제외하고 일반 텍스트 추출
var textEntities = DwgExtractor.ExtractTextEntitiesWithHeightExcluding(dwgFile, noteEntities.UsedTextIds);
excelWriter.WriteHeightSortedData(textEntities, worksheet, fileName);
Debug.WriteLine($"[DEBUG] {fileName} 시트 완료: {textEntities.Count}개 엔티티");
}
catch (System.Exception ex)
{
Debug.WriteLine($"❌ {fileName} 처리 중 오류: {ex.Message}");
continue;
}
}
if (!firstSheetProcessed)
{
Microsoft.Office.Interop.Excel.Worksheet defaultSheet = (Microsoft.Office.Interop.Excel.Worksheet)heightSortedWorkbook.Worksheets[1];
defaultSheet.Name = "No_DWG_Files";
defaultSheet.Cells[1, 1] = "No DWG files found in this folder";
}
excelManager.SaveWorkbookAs(heightSortedWorkbook, savePath);
heightSortedWorkbook.Close(false);
Debug.WriteLine($"✅ Height 정렬 Excel 파일 저장 완료: {Path.GetFileName(savePath)}");
}
catch (System.Exception ex)
{
Debug.WriteLine($"❌ Height 정렬 Excel 생성 중 오류: {ex.Message}");
throw;
}
}
/// <summary>
/// 모든 DWG 파일들을 하나의 Excel 파일로 처리하여 Height 순으로 정렬
/// </summary>
public void ExportAllDwgToExcelHeightSorted(List<(string filePath, string folderName)> allDwgFiles, string savePath)
{
try
{
Debug.WriteLine($"[DEBUG] 단일 Excel 파일로 Height 정렬 생성 시작: {allDwgFiles.Count}개 파일");
// 시각화 데이터 초기화
MainWindow.ClearVisualizationData();
Debug.WriteLine("[VISUALIZATION] 시각화 데이터 초기화 완료");
var heightSortedWorkbook = excelManager.CreateNewWorkbook();
bool firstSheetProcessed = false;
foreach (var (filePath, folderName) in allDwgFiles)
{
if (!File.Exists(filePath))
{
continue;
}
string fileName = Path.GetFileNameWithoutExtension(filePath);
try
{
Microsoft.Office.Interop.Excel.Worksheet worksheet = firstSheetProcessed ?
(Microsoft.Office.Interop.Excel.Worksheet)heightSortedWorkbook.Worksheets.Add() :
(Microsoft.Office.Interop.Excel.Worksheet)heightSortedWorkbook.Worksheets[1];
worksheet.Name = excelManager.GetValidSheetName(fileName);
firstSheetProcessed = true;
// Note 엔티티 먼저 추출
var noteEntities = DwgExtractor.ExtractNotesFromDrawing(filePath);
// Note에서 사용된 텍스트 제외하고 일반 텍스트 추출
var textEntities = DwgExtractor.ExtractTextEntitiesWithHeightExcluding(filePath, noteEntities.UsedTextIds);
excelWriter.WriteHeightSortedData(textEntities, worksheet, fileName);
if (noteEntities.NoteEntities.Count > 0)
{
excelWriter.WriteNoteEntities(noteEntities.NoteEntities, worksheet, fileName);
Debug.WriteLine($"[DEBUG] {fileName}: {noteEntities.NoteEntities.Count}개 Note 엔티티 추가됨");
}
Debug.WriteLine($"[DEBUG] {fileName} 시트 완료: {textEntities.Count}개 엔티티");
}
catch (System.Exception ex)
{
Debug.WriteLine($"❌ {fileName} 처리 중 오류: {ex.Message}");
continue;
}
}
if (!firstSheetProcessed)
{
Microsoft.Office.Interop.Excel.Worksheet defaultSheet = (Microsoft.Office.Interop.Excel.Worksheet)heightSortedWorkbook.Worksheets[1];
defaultSheet.Name = "No_DWG_Files";
defaultSheet.Cells[1, 1] = "No DWG files found in any folder";
}
excelManager.SaveWorkbookAs(heightSortedWorkbook, savePath);
heightSortedWorkbook.Close(false);
Debug.WriteLine($"✅ 단일 Height 정렬 Excel 파일 저장 완료: {Path.GetFileName(savePath)}");
}
catch (System.Exception ex)
{
Debug.WriteLine($"❌ 단일 Height 정렬 Excel 생성 중 오류: {ex.Message}");
throw;
}
}
// Helper methods and legacy support methods
public bool SaveExcel() => excelManager.SaveWorkbook();
public void SaveMappingWorkbookOnly(string savePath) => excelManager.SaveWorkbookAs(excelManager.MappingWorkbook, savePath);
public void SaveDwgOnlyMappingWorkbook(string resultFolderPath) => excelWriter.SaveDwgOnlyMappingWorkbook(FileToMapkeyToLabelTagValuePdf, resultFolderPath);
public void SaveAndCloseExcel(string savePath)
{
try
{
excelManager.SaveWorkbookAs(excelManager.TitleBlockWorkbook, savePath);
if (excelManager.MappingWorkbook != null)
{
string directory = Path.GetDirectoryName(savePath) ?? "";
string mappingPath = Path.Combine(directory, Path.GetFileNameWithoutExtension(savePath) + "_Mapping.xlsx");
excelManager.SaveWorkbookAs(excelManager.MappingWorkbook, mappingPath);
}
}
catch (System.Exception ex)
{
Debug.WriteLine($"Excel 파일 저장 중 오류 발생: {ex.Message}");
}
finally
{
excelManager.CloseWorkbooks();
}
}
public void CloseExcelObjectsWithoutSaving() => excelManager.CloseWorkbooks();
public void SaveMappingDictionary(string filePath) => jsonProcessor.SaveMappingDictionary(FileToMapkeyToLabelTagValuePdf, filePath);
public void LoadMappingDictionary(string filePath)
{
FileToMapkeyToLabelTagValuePdf = jsonProcessor.LoadMappingDictionary(filePath);
}
public void WriteCompleteMapping() => excelWriter.WriteMappingDataToExcel(FileToMapkeyToLabelTagValuePdf);
public void UpdateWithPdfData(string jsonFilePath) => jsonProcessor.UpdateMappingDataFromJson(FileToMapkeyToLabelTagValuePdf, jsonFilePath);
public void ClearAccumulatedData() => FileToMapkeyToLabelTagValuePdf.Clear();
// Private helper methods
private void TestFieldMapper()
{
Debug.WriteLine("[DEBUG] Testing field mapper...");
var testFields = new[] { "TD_DNAME_MAIN", "TD_DWGNO", "TD_DWGCODE", "TB_MTITIL" };
foreach (var field in testFields)
{
var aiLabel = fieldMapper.ExpresswayToAilabel(field);
var docAiKey = fieldMapper.AilabelToDocAiKey(aiLabel);
Debug.WriteLine($"[DEBUG] Field: {field} -> AILabel: {aiLabel} -> DocAiKey: {docAiKey}");
}
}
private void InitializeTeighaServices()
{
try
{
Debug.WriteLine("[DEBUG] TeighaServicesManager를 통한 Services 획득 중...");
appServices = TeighaServicesManager.Instance.AcquireServices();
Debug.WriteLine($"[DEBUG] Services 획득 성공. Reference Count: {TeighaServicesManager.Instance.ReferenceCount}");
}
catch (Teigha.Runtime.Exception ex)
{
Debug.WriteLine($"[DEBUG] Teigha Services 초기화 실패: {ex.Message}");
throw;
}
}
private bool UpdateExcelFromMappingData()
{
try
{
foreach (var fileEntry in FileToMapkeyToLabelTagValuePdf)
{
foreach (var mapEntry in fileEntry.Value)
{
var (aiLabel, dwgTag, dwgValue, pdfValue) = mapEntry.Value;
if (!string.IsNullOrEmpty(pdfValue))
{
excelWriter.UpdateExcelRow(fileEntry.Key, aiLabel, pdfValue);
}
}
}
return true;
}
catch (System.Exception ex)
{
Debug.WriteLine($"❌ Excel 업데이트 중 오류: {ex.Message}");
return false;
}
}
public void Dispose()
{
try
{
Debug.WriteLine("[DEBUG] ExportExcel Dispose 시작");
excelManager?.Dispose();
if (appServices != null)
{
Debug.WriteLine("[DEBUG] Teigha Services 해제 중...");
try
{
TeighaServicesManager.Instance.ReleaseServices();
Debug.WriteLine($"[DEBUG] Teigha Services 해제 완료. Remaining ref count: {TeighaServicesManager.Instance.ReferenceCount}");
}
catch (System.Exception ex)
{
Debug.WriteLine($"[DEBUG] Teigha Services 해제 중 오류 (무시됨): {ex.Message}");
}
finally
{
appServices = null;
}
}
Debug.WriteLine("[DEBUG] ExportExcel Dispose 완료");
}
catch (System.Exception ex)
{
Debug.WriteLine($"[DEBUG] ExportExcel Dispose 중 전역 오류: {ex.Message}");
}
}
}
}