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 ColumnAbsoluteMark = 6; private const int ColumnNorthOrifice = 7; private const int ColumnEastOrifice = 8; private const int ColumnEastCartographic = 9; private const int ColumnNorthCartographic = 10; private const int ColumnSpatialIntensity = 11; private const int ColumnAngleIntensity = 12; private const int ColumnAzimuthIntensity = 13; private const int ColumnOrificeOffset = 14; private const int ColumnComment = 15; 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(ColumnAbsoluteMark).Value = trajectory.AbsoluteMark; row.Cell(ColumnNorthOrifice).Value = trajectory.NorthOrifice; row.Cell(ColumnEastOrifice).Value = trajectory.EastOrifice; row.Cell(ColumnEastCartographic).Value = trajectory.EastCartographic; row.Cell(ColumnNorthCartographic).Value = trajectory.NorthCartographic; row.Cell(ColumnSpatialIntensity).Value = trajectory.SpatialIntensity; row.Cell(ColumnAngleIntensity).Value = trajectory.AngleIntensity; row.Cell(ColumnAzimuthIntensity).Value = trajectory.AzimuthIntensity; row.Cell(ColumnOrificeOffset).Value = trajectory.OrificeOffset; 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 < 15) 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); } }; return trajectoryRows; } private TrajectoryGeoPlanDto ParseRow(IXLRow row) { var _wellboreDepth = row.Cell(ColumnWellboreDepth).Value; var _zenithAngle = row.Cell(ColumnZenithAngle).Value; var _azimuthGeo = row.Cell(ColumnAzimuthGeo).Value; var _azimuthMagnetic = row.Cell(ColumnAzimuthMagnetic).Value; var _verticalDepth = row.Cell(ColumnVerticalDepth).Value; var _absoluteMark = row.Cell(ColumnAbsoluteMark).Value; var _northOrifice = row.Cell(ColumnNorthOrifice).Value; var _eastOrifice = row.Cell(ColumnEastOrifice).Value; var _eastCartographic = row.Cell(ColumnEastCartographic).Value; var _northCartographic = row.Cell(ColumnNorthCartographic).Value; var _spatialIntensity = row.Cell(ColumnSpatialIntensity).Value; var _angleIntensity = row.Cell(ColumnAngleIntensity).Value; var _azimuthIntensity = row.Cell(ColumnAzimuthIntensity).Value; var _orificeOffset = row.Cell(ColumnOrificeOffset).Value; var _comment = row.Cell(ColumnComment).Value; var trajectoryRow = new TrajectoryGeoPlanDto(); static double getDoubleValue(object value, string nameParam, IXLRow row) { if (value is double _value) return _value; throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} - некорректные данные - {nameParam}"); } trajectoryRow.WellboreDepth = getDoubleValue(_wellboreDepth, "Глубина по стволу", row); trajectoryRow.ZenithAngle = getDoubleValue(_zenithAngle, "Зенитный угол", row); trajectoryRow.AzimuthGeo = getDoubleValue(_azimuthGeo, "Азимут географический", row); trajectoryRow.AzimuthMagnetic = getDoubleValue(_azimuthMagnetic, "Азимут магнитный", row); trajectoryRow.VerticalDepth = getDoubleValue(_verticalDepth, "Глубина вертикальная", row); trajectoryRow.AbsoluteMark = getDoubleValue(_absoluteMark, "Абсолютная отметка", row); trajectoryRow.NorthOrifice = getDoubleValue(_northOrifice, "Север относительно устья", row); trajectoryRow.EastOrifice = getDoubleValue(_eastOrifice, "Восток относительно устья", row); trajectoryRow.EastCartographic = getDoubleValue(_eastCartographic, "Восток картографический", row); trajectoryRow.NorthCartographic = getDoubleValue(_northCartographic, "Север картографический", row); trajectoryRow.SpatialIntensity = getDoubleValue(_spatialIntensity, "Простр. интенсивность", row); trajectoryRow.AngleIntensity = getDoubleValue(_angleIntensity, "Интенсивность по углу", row); trajectoryRow.AzimuthIntensity = getDoubleValue(_azimuthIntensity, "Интенсивность по азимуту", row); trajectoryRow.OrificeOffset = getDoubleValue(_orificeOffset, "Смещение от устья", row); if (_comment is not null) trajectoryRow.Comment = _comment.ToString(); return trajectoryRow; } } }