using AsbCloudApp.Data; using AsbCloudApp.Repositories; using AsbCloudApp.Services; using ClosedXML.Excel; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.Trajectory { public class PlannedTrajectoryImportService : IPlannedTrajectoryImportService { /* * password for PlannedTrajectoryTemplate.xlsx is Drill2022 */ private readonly IWellService wellService; private readonly ITrajectoryPlanRepository plannedTrajectoryService; private const string templateFileName = "PlannedTrajectoryTemplate.xlsx"; private const string usingTemplateFile = "AsbCloudInfrastructure.Services.Trajectory"; private const string sheetNamePlannedTrajectory = "Плановая траектория"; private const int headerRowsCount = 2; private const int ColumnWellboreDepth = 1; private const int ColumnZenithAngle = 2; private const int ColumnAzimuthGeo = 3; private const int ColumnAzimuthMagnetic = 4; private const int ColumnVerticalDepth = 5; private const int ColumnRadius = 6; private const int ColumnComment = 7; public PlannedTrajectoryImportService(IWellService wellService, ITrajectoryPlanRepository plannedTrajectoryService) { this.wellService = wellService; this.plannedTrajectoryService = plannedTrajectoryService; } public Stream GetTemplateFile() { var stream = System.Reflection.Assembly.GetExecutingAssembly() .GetManifestResourceStream($"{usingTemplateFile}.{templateFileName}"); if (stream is null) throw new Exception($"Область {usingTemplateFile} не содержит файла с названием {templateFileName}"); return stream; } public async Task GetFileNameAsync(int idWell, CancellationToken token) { var fileName = await wellService.GetWellCaptionByIdAsync(idWell, token) + "_plannedTrajectory.xlsx"; return fileName; } public async Task ExportAsync(int idWell, CancellationToken token) { var plannedTrajectorys = await plannedTrajectoryService.GetAsync(idWell, token); return MakeExelFileStream(plannedTrajectorys); } private Stream MakeExelFileStream(IEnumerable plannedTrajectories) { using Stream ecxelTemplateStream = GetTemplateFile(); using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled); AddPlannedTrajecoryToWorkbook(workbook, plannedTrajectories); MemoryStream memoryStream = new MemoryStream(); workbook.SaveAs(memoryStream, new SaveOptions { }); memoryStream.Seek(0, SeekOrigin.Begin); return memoryStream; } private static void AddPlannedTrajecoryToWorkbook(XLWorkbook workbook, IEnumerable plannedTrajectories) { if (plannedTrajectories.Any()) { var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlannedTrajectory); if (sheet is null) throw new FileFormatException($"Лист с именем {sheetNamePlannedTrajectory} отсутствует, либо имеет некорректное название"); AddPlannedTrajecoryToSheet(sheet, plannedTrajectories); } } private static void AddPlannedTrajecoryToSheet(IXLWorksheet sheet, IEnumerable plannedTrajectories) { var rowList = plannedTrajectories.ToList(); for (int i = 0; i < rowList.Count; i++) { var row = sheet.Row(1 + i + headerRowsCount); AddCoordinatesToRow(row, rowList[i]); } } private static void AddCoordinatesToRow(IXLRow row, TrajectoryGeoPlanDto trajectory) { row.Cell(ColumnWellboreDepth).Value = trajectory.WellboreDepth; row.Cell(ColumnZenithAngle).Value = trajectory.ZenithAngle; row.Cell(ColumnAzimuthGeo).Value = trajectory.AzimuthGeo; row.Cell(ColumnAzimuthMagnetic).Value = trajectory.AzimuthMagnetic; row.Cell(ColumnVerticalDepth).Value = trajectory.VerticalDepth; row.Cell(ColumnRadius).Value = trajectory.Radius; row.Cell(ColumnComment).Value = trajectory.Comment; } public async Task ImportAsync(int idWell, int idUser, Stream stream, bool deletePrevRows, CancellationToken token) { using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); var trajectoryRows = ParseFileStream(stream); foreach (var row in trajectoryRows) { row.IdWell = idWell; row.IdUser = idUser; } var rowsCount = await SavePlannedTrajectoryAsync(idWell, trajectoryRows, deletePrevRows, token); return rowsCount; } private async Task SavePlannedTrajectoryAsync(int idWell, IEnumerable newRows, bool deletePrevRow, CancellationToken token) { if (deletePrevRow) await plannedTrajectoryService.DeleteByIdWellAsync(idWell, token); var rowsCount = await plannedTrajectoryService.AddRangeAsync(newRows, token); return rowsCount; } private IEnumerable ParseFileStream(Stream stream) { using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); return ParseWorkbook(workbook); } private IEnumerable ParseWorkbook(IXLWorkbook workbook) { var sheetPlannedTrajectory = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlannedTrajectory); if (sheetPlannedTrajectory is null) throw new FileFormatException($"Книга excel не содержит листа {sheetNamePlannedTrajectory}."); var plannedTrajectoryRows = ParseSheet(sheetPlannedTrajectory); return plannedTrajectoryRows; } private IEnumerable ParseSheet(IXLWorksheet sheet) { if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 7) throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов."); var count = sheet.RowsUsed().Count() - headerRowsCount; if (count > 1024) throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк."); if (count <= 0) throw new FileFormatException($"Лист {sheet.Name} некорректного формата либо пустой"); var trajectoryRows = new List(count); var parseErrors = new List(); for (int i = 0; i < count; i++) { var row = sheet.Row(1 + i + headerRowsCount); try { var trajectoryRow = ParseRow(row); trajectoryRows.Add(trajectoryRow); } catch (FileFormatException ex) { parseErrors.Add(ex.Message); } } if (parseErrors.Any()) throw new FileFormatException(string.Join("\r\n", parseErrors)); return trajectoryRows; } private TrajectoryGeoPlanDto ParseRow(IXLRow row) { var trajectoryRow = new TrajectoryGeoPlanDto { WellboreDepth = row.Cell(ColumnWellboreDepth).GetCellValue(), ZenithAngle = row.Cell(ColumnZenithAngle).GetCellValue(), AzimuthGeo = row.Cell(ColumnAzimuthGeo).GetCellValue(), AzimuthMagnetic = row.Cell(ColumnAzimuthMagnetic).GetCellValue(), VerticalDepth = row.Cell(ColumnVerticalDepth).GetCellValue(), Radius = row.Cell(ColumnRadius).GetCellValue(), Comment = row.Cell(ColumnComment).GetCellValue() }; return trajectoryRow; } } }