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 abstract class TrajectoryImportService where T : TrajectoryGeoDto { private readonly IWellService wellService; private readonly ITrajectoryRepository trajectoryService; protected abstract void AddCoordinatesToRow(IXLRow row, T trajectory); protected abstract T ParseRow(IXLRow row); public abstract string templateFileName { get; set; } public abstract string usingTemplateFile { get; set; } public abstract string sheetNamePlannedTrajectory { get; set; } public abstract int headerRowsCount { get; set; } public abstract int ColumnWellboreDepth { get; set; } public abstract int ColumnZenithAngle { get; set; } public abstract int ColumnAzimuthGeo { get; set; } public abstract int ColumnAzimuthMagnetic { get; set; } public abstract int ColumnVerticalDepth { get; set; } public abstract int ColumnRadius { get; set; } public abstract int ColumnComment { get; set; } public TrajectoryImportService(ITrajectoryRepository trajectoryService, IWellService wellService) { this.trajectoryService = trajectoryService; this.wellService = wellService; } 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 ExportAsync(int idWell, CancellationToken token) { var trajectorys = await trajectoryService.GetAsync(idWell, token); return MakeExelFileStream(trajectorys); } private Stream MakeExelFileStream(IEnumerable trajectories) { using Stream ecxelTemplateStream = GetTemplateFile(); using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled); AddTrajecoryToWorkbook(workbook, trajectories); MemoryStream memoryStream = new MemoryStream(); workbook.SaveAs(memoryStream, new SaveOptions { }); memoryStream.Seek(0, SeekOrigin.Begin); return memoryStream; } private void AddTrajecoryToWorkbook(XLWorkbook workbook, IEnumerable trajectories) { if (trajectories.Any()) { var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlannedTrajectory); if (sheet is null) throw new FileFormatException($"Лист с именем {sheetNamePlannedTrajectory} отсутствует, либо имеет некорректное название"); AddTrajecoryToSheet(sheet, trajectories); } } private void AddTrajecoryToSheet(IXLWorksheet sheet, IEnumerable trajectories) { var rowList = trajectories.ToList(); for (int i = 0; i < rowList.Count; i++) { var row = sheet.Row(1 + i + headerRowsCount); AddCoordinatesToRow(row, rowList[i]); } } public async Task GetFileNameAsync(int idWell, CancellationToken token) { var caption = await wellService.GetWellCaptionByIdAsync(idWell, token); return string.Format("{0}_{1}", caption, templateFileName); } public async Task> ImportAsync(int idWell, int idUser, Stream stream, 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; } return trajectoryRows; } private IEnumerable ParseFileStream(Stream stream) { using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); return ParseWorkbook(workbook); } private IEnumerable ParseWorkbook(IXLWorkbook workbook) { var sheetTrajectory = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlannedTrajectory); if (sheetTrajectory is null) throw new FileFormatException($"Книга excel не содержит листа {sheetNamePlannedTrajectory}."); var trajectoryRows = ParseSheet(sheetTrajectory); return trajectoryRows; } 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; } } }