using AsbCloudApp.Data.ProcessMap; using AsbCloudApp.Services; using ClosedXML.Excel; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.ProcessMap { public class ProcessMapReportMakerService : IProcessMapReportMakerService { const int firstColumn = 2; const int lastColumn = 49; const int headerRowsCount = 5; private readonly IProcessMapReportService processMapService; public ProcessMapReportMakerService(IProcessMapReportService processMapService) { this.processMapService = processMapService; } public async Task MakeReportAsync(int idWell, CancellationToken token) { var stream = GetExcelTemplateStream(); using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); var data = await processMapService.GetProcessMapReportAsync(idWell, token); FillProcessMapToWorkbook(workbook, data); MemoryStream memoryStream = new MemoryStream(); workbook.SaveAs(memoryStream, new SaveOptions { }); memoryStream.Seek(0, SeekOrigin.Begin); return memoryStream; } private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable data) { var sheet = workbook.Worksheets.FirstOrDefault(); if (sheet is null) return; var dataBySections = data.GroupBy(p => p.IdWellSectionType); FillSheet(sheet, dataBySections); } private static void FillSheet(IXLWorksheet sheet, IEnumerable> dataBySections) { var startRow = headerRowsCount + 1; foreach (var sectionData in dataBySections) { if(sectionData.Any()) startRow = FillSection(sheet, sectionData, startRow); } } private static int FillSection(IXLWorksheet sheet, IGrouping sectionData, int row) { var rowStart = row; var sectionName = sectionData.FirstOrDefault()?.WellSectionTypeName ?? sectionData.Key.ToString(); sheet.Range(row, firstColumn, row, lastColumn) .Merge() .FirstCell() .SetVal(sectionName) .Style .Fill.SetBackgroundColor(XLColor.LightGray); row++; foreach (var interval in sectionData) row = FillIntervalData(sheet, interval, row); var sectionStyle = sheet.Range(rowStart, firstColumn, row - 1, lastColumn).Style; SetBorders(sectionStyle); return row; } private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportDto interval, int row) { const int columnDepth = firstColumn + 1; const int columnDate = firstColumn + 2; const int columnRopTime = firstColumn + 3; const int columnMode = firstColumn + 4; sheet.Cell(row, firstColumn) .SetVal(interval.DepthStart, "0.0"); sheet.Cell(row, columnDepth) .SetVal(interval.DepthEnd, "0.0"); sheet.Cell(row, columnDate) .SetVal(interval.DateStart); sheet.Cell(row, columnRopTime) .SetVal(interval.MechDrillingHours); row = FillIntervalModeData(sheet, interval, columnMode, row); return row; } private static int FillIntervalModeData(IXLWorksheet sheet, ProcessMapReportDto modeData, int column, int row) { int columnDeltaDepth = column + 1; int columnPressure = columnDeltaDepth + 1; int columnLoad = columnPressure + 5; int columnTorque = columnLoad + 5; int columnSpeed = columnTorque + 5; int columnUsagePlan = columnSpeed + 5; int columnUsageFact = columnUsagePlan + 1; int columnRop = columnUsageFact + 12; sheet.Cell(row, column) .SetVal(modeData.DrillingMode); sheet.Cell(row, columnDeltaDepth) .SetVal(modeData.DeltaDepth); FillIntervalModeDataParam(sheet, modeData.PressureDiff, columnPressure, row); FillIntervalModeDataParam(sheet, modeData.AxialLoad, columnLoad, row); FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row); FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row); sheet.Cell(row, columnUsagePlan) .SetVal(modeData.UsagePlan); sheet.Cell(row, columnUsageFact) .SetVal(modeData.UsageFact); sheet.Cell(row, columnRop) .SetVal(modeData.Rop); return row + 1; } private static void FillIntervalModeDataParam(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row) { const int columnOffsetSpPlan = 0; const int columnOffsetSpFact = 1; const int columnOffsetFact = 2; const int columnOffsetLimit = 3; const int columnOffsetPercent = 4; sheet.Cell(row, column + columnOffsetSpPlan) .SetVal(dataParam.SetpointPlan); sheet.Cell(row, column + columnOffsetSpFact) .SetVal(dataParam.SetpointFact); sheet.Cell(row, column + columnOffsetFact) .SetVal(dataParam.Fact); sheet.Cell(row, column + columnOffsetLimit) .SetVal(dataParam.Limit); sheet.Cell(row, column + columnOffsetPercent) .SetVal(dataParam.SetpointUsage); } private static void FillIntervalModeDataSpeed(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row) { const int columnOffsetSpPlan = 0; const int columnOffsetSpFact = 1; const int columnOffsetFact = 2; const int columnOffsetLimit = 3; const int columnOffsetPercent = 4; sheet.Cell(row, column + columnOffsetSpPlan) .SetVal(dataParam.SetpointPlan); sheet.Cell(row, column + columnOffsetSpFact) .SetVal(dataParam.SetpointFact); sheet.Cell(row, column + columnOffsetFact) .SetVal(dataParam.Fact); sheet.Cell(row, column + columnOffsetLimit) .SetVal(dataParam.Limit); sheet.Cell(row, column + columnOffsetPercent) .SetVal(dataParam.SetpointUsage); } private static Stream GetExcelTemplateStream() { var stream = System.Reflection.Assembly.GetExecutingAssembly() .GetManifestResourceStream("AsbCloudInfrastructure.Services.ProcessMap.ProcessMapReportTemplate.xlsx"); return stream!; } private static IXLStyle SetBorders(IXLStyle style) { style.Border.RightBorder = XLBorderStyleValues.Thin ; style.Border.LeftBorder = XLBorderStyleValues.Thin; style.Border.TopBorder = XLBorderStyleValues.Thin ; style.Border.BottomBorder = XLBorderStyleValues.Thin ; style.Border.InsideBorder = XLBorderStyleValues.Thin ; return style; } } }