2021-09-10 11:28:57 +05:00
using AsbCloudApp.Data ;
2022-01-18 11:04:15 +05:00
using AsbCloudApp.Exceptions ;
2021-09-10 11:28:57 +05:00
using AsbCloudApp.Services ;
2021-09-23 11:37:57 +05:00
using ClosedXML.Excel ;
using ClosedXML.Excel.Drawings ;
2021-11-09 17:36:44 +05:00
using System ;
2021-08-29 17:25:16 +05:00
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Threading ;
using System.Threading.Tasks ;
namespace AsbCloudInfrastructure.Services
{
public class DrillingProgramService : IDrillingProgramService
{
private readonly IFileService fileService ;
2021-08-29 17:27:24 +05:00
private readonly IWellService wellService ;
2021-08-31 09:52:32 +05:00
private const int idFileCategoryDrillingProgramItems = 13 ;
private const int idFileCategoryDrillingProgram = 14 ;
2021-08-29 17:25:16 +05:00
2021-10-18 16:23:58 +05:00
private const int maxAllowedColumns = 256 ;
2021-08-29 17:27:24 +05:00
public DrillingProgramService ( IFileService fileService , IWellService wellService )
2021-08-29 17:25:16 +05:00
{
this . fileService = fileService ;
this . wellService = wellService ;
}
2021-11-17 13:06:48 +05:00
public async Task < string > GetOrCreateSharedUrlAsync ( int idWell , int idUser , IFileShareService fileShareService , CancellationToken token = default )
2021-08-29 17:25:16 +05:00
{
2021-11-09 17:36:44 +05:00
var fileInfo = await GetOrCreateAsync ( idWell , idUser , token )
2021-08-29 17:25:16 +05:00
. ConfigureAwait ( false ) ;
2021-11-09 17:36:44 +05:00
if ( fileInfo is null )
return null ;
2021-11-17 13:06:48 +05:00
var sharedUrl = await fileService . GetSharedUrlAsync ( fileInfo , idUser , fileShareService , token )
2021-11-09 17:36:44 +05:00
. ConfigureAwait ( false ) ;
return sharedUrl ;
}
public async Task < FileInfoDto > GetOrCreateAsync ( int idWell , int idUser , CancellationToken token = default )
{
var programParts = ( await fileService . GetInfosByCategoryAsync ( idWell , idFileCategoryDrillingProgramItems , token )
. ConfigureAwait ( false ) )
. Where ( f = > f . FileMarks ? . Any ( m = > m . IdMarkType = = 1 & & ! m . IsDeleted ) ? ? false ) ;
2021-08-29 17:25:16 +05:00
var well = await wellService . GetAsync ( idWell , token )
. ConfigureAwait ( false ) ;
2021-11-09 17:36:44 +05:00
var programs = await fileService . GetInfosByCategoryAsync ( idWell , idFileCategoryDrillingProgram , token )
2021-08-31 09:52:32 +05:00
. ConfigureAwait ( false ) ;
2021-11-03 14:12:39 +05:00
2021-11-09 17:36:44 +05:00
if ( programs is not null & & programs . Any ( ) & & programParts . Any ( ) )
2021-09-10 11:28:57 +05:00
{
2021-11-09 17:36:44 +05:00
programs = programs . OrderByDescending ( f = > f . UploadDate ) ;
var matchFilesIterator = programs . GetEnumerator ( ) ;
2021-08-31 09:52:32 +05:00
matchFilesIterator . MoveNext ( ) ;
var matchFile = matchFilesIterator . Current ;
2021-11-09 17:36:44 +05:00
if ( programParts . All ( pp = > matchFile . UploadDate > pp . UploadDate ) & &
File . Exists ( fileService . GetUrl ( matchFile ) ) )
2021-08-29 17:25:16 +05:00
return matchFile ;
else
2021-10-06 18:07:35 +05:00
await fileService . DeleteAsync ( matchFile . Id , token )
2021-08-31 09:52:32 +05:00
. ConfigureAwait ( false ) ;
2021-11-09 17:36:44 +05:00
while ( matchFilesIterator . MoveNext ( ) )
await fileService . DeleteAsync ( matchFilesIterator . Current . Id , token )
. ConfigureAwait ( false ) ;
2021-08-29 17:25:16 +05:00
}
2021-11-09 17:36:44 +05:00
if ( ! programParts . Any ( ) )
throw new FileNotFoundException ( "Нет частей для формирования программы бурения" ) ;
2021-09-23 11:37:57 +05:00
var resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.xlsx" ;
2021-11-03 14:12:39 +05:00
2021-11-09 17:36:44 +05:00
var filteredFilePaths = programParts
2021-11-03 14:12:39 +05:00
. Select ( file = > fileService . GetUrl ( file ) ) ;
2021-08-29 17:25:16 +05:00
2021-09-23 14:36:05 +05:00
var tempResultFilePath = Path . Combine ( Path . GetTempPath ( ) , "drillingProgram" , resultFileName ) ;
2021-09-23 11:37:57 +05:00
2021-11-03 14:12:39 +05:00
UniteExcelFiles ( filteredFilePaths , tempResultFilePath ) ;
2021-09-23 11:37:57 +05:00
2021-09-23 14:36:05 +05:00
var fileInfo = await fileService . MoveAsync ( idWell , null , idFileCategoryDrillingProgram ,
resultFileName , tempResultFilePath , token ) . ConfigureAwait ( false ) ;
return fileInfo ;
2021-08-29 17:25:16 +05:00
}
2021-11-09 17:36:44 +05:00
public async Task < int > CreateFileMarkAsync ( FileMarkDto fileMarkDto , int idUser , CancellationToken token )
{
var fileInfo = await fileService . GetInfoAsync ( fileMarkDto . IdFile , token )
. ConfigureAwait ( false ) ;
if ( fileInfo . IdCategory ! = idFileCategoryDrillingProgramItems )
2022-01-18 11:04:15 +05:00
throw new ArgumentInvalidException ( $"Этот метод допустим только для файлов-частей программы бурения idCategory=={idFileCategoryDrillingProgramItems}." , nameof ( fileMarkDto ) ) ;
2021-11-09 17:36:44 +05:00
var result = await fileService . CreateFileMarkAsync ( fileMarkDto , idUser , token )
. ConfigureAwait ( false ) ;
var drillingPrograms = await fileService . GetInfosByCategoryAsync ( fileInfo . IdWell , idFileCategoryDrillingProgram , token )
. ConfigureAwait ( false ) ;
foreach ( var drillingProgram in drillingPrograms )
await fileService . DeleteAsync ( drillingProgram . Id , token )
. ConfigureAwait ( false ) ;
return result ;
}
public async Task < int > MarkFileMarkAsDeletedAsync ( int idMark ,
CancellationToken token )
{
var fileInfo = await fileService . GetByMarkId ( idMark , token )
. ConfigureAwait ( false ) ;
if ( fileInfo . IdCategory ! = idFileCategoryDrillingProgramItems )
2022-01-18 11:04:15 +05:00
throw new ArgumentInvalidException ( $"Этот метод допустим только для файлов-частей программы бурения idCategory=={idFileCategoryDrillingProgramItems}." , nameof ( idMark ) ) ;
2021-11-09 17:36:44 +05:00
var result = await fileService . MarkFileMarkAsDeletedAsync ( idMark , token )
. ConfigureAwait ( false ) ;
var drillingPrograms = await fileService . GetInfosByCategoryAsync ( fileInfo . IdWell , idFileCategoryDrillingProgram , token )
. ConfigureAwait ( false ) ;
foreach ( var drillingProgram in drillingPrograms )
await fileService . DeleteAsync ( drillingProgram . Id , token )
. ConfigureAwait ( false ) ;
return result ;
}
2021-09-23 11:37:57 +05:00
private static void UniteExcelFiles ( IEnumerable < string > excelFilesNames , string resultExcelPath )
2021-08-29 17:25:16 +05:00
{
2021-09-23 11:37:57 +05:00
var resultExcelFile = new XLWorkbook ( XLEventTracking . Disabled ) ;
2021-09-23 14:36:05 +05:00
var filteredFileNames = excelFilesNames . Distinct ( ) ;
foreach ( var excelFileName in filteredFileNames )
2021-08-29 17:25:16 +05:00
{
2021-10-18 16:23:58 +05:00
using var workbookSrc = new XLWorkbook ( excelFileName , XLEventTracking . Disabled ) ;
2021-08-29 17:25:16 +05:00
2021-10-18 16:23:58 +05:00
foreach ( var sheet in workbookSrc . Worksheets )
2021-08-29 17:25:16 +05:00
{
2021-10-18 16:23:58 +05:00
if ( sheet . Visibility = = XLWorksheetVisibility . Visible )
CopySheet ( resultExcelFile , sheet ) ;
2021-08-29 17:25:16 +05:00
}
}
2021-09-23 11:37:57 +05:00
resultExcelFile . SaveAs ( resultExcelPath ,
new SaveOptions { EvaluateFormulasBeforeSaving = true } ) ;
2021-08-29 17:25:16 +05:00
}
2021-09-23 11:37:57 +05:00
2021-10-18 16:23:58 +05:00
private static void CopySheet ( XLWorkbook workbookDst , IXLWorksheet sheetSrc )
{
var newSheetName = sheetSrc . Name ;
2021-10-18 17:38:07 +05:00
var suffix = "" ;
2021-10-18 16:23:58 +05:00
int index = 1 ;
2021-10-18 17:38:07 +05:00
while ( workbookDst . Worksheets . Contains ( newSheetName ) )
2021-10-18 16:23:58 +05:00
{
2021-10-18 17:38:07 +05:00
newSheetName = sheetSrc . Name ;
suffix = $"_{index++}" ;
2021-10-18 16:23:58 +05:00
if ( newSheetName . Length + suffix . Length > = 31 )
2022-01-05 17:50:45 +05:00
newSheetName = newSheetName [ . . ( 31 - suffix . Length ) ] ;
2021-10-18 16:23:58 +05:00
newSheetName + = suffix ;
}
var imagesInfos = sheetSrc . Pictures . Select ( p = > new ImageInfo
{
Id = p . Id ,
Data = p . ImageStream . GetBuffer ( ) ,
Height = p . Height ,
Width = p . Width ,
TopLeftCellAddress = p . TopLeftCell . Address ,
Left = p . Left ,
Top = p . Top
} ) . ToList ( ) ;
IXLWorksheet resultSheet ;
if ( sheetSrc . Columns ( ) . Count ( ) > maxAllowedColumns )
{
resultSheet = workbookDst . Worksheets . Add ( newSheetName ) ;
var rngData = GetCellsRange ( sheetSrc ) ;
rngData . CopyTo ( resultSheet . Cell ( 1 , 1 ) ) ;
var lastRowWithData = rngData . LastRowUsed ( ) . RangeAddress
. LastAddress . RowNumber ;
for ( int i = 1 ; i < lastRowWithData ; i + + )
{
resultSheet . Row ( i ) . Height = sheetSrc . Row ( i ) . Height ;
resultSheet . Column ( i ) . Width = sheetSrc . Column ( i ) . Width ;
}
}
else
{
RemovePicturesFromSheet ( sheetSrc ) ;
resultSheet = sheetSrc . CopyTo ( workbookDst , newSheetName ) ;
}
CopyImagesToAnotherSheet ( imagesInfos , resultSheet ) ;
}
2021-09-23 11:37:57 +05:00
private static IXLWorksheet CopyImagesToAnotherSheet ( IEnumerable < ImageInfo > imagesInfos ,
IXLWorksheet resultSheet )
{
foreach ( var image in imagesInfos )
{
var stream = new MemoryStream ( ) ;
stream . Write ( image . Data , 0 , image . Data . Length ) ;
resultSheet . AddPicture ( stream )
. WithPlacement ( XLPicturePlacement . Move )
. WithSize ( image . Width , image . Height )
. MoveTo ( resultSheet . Cell ( image . TopLeftCellAddress ) ,
image . Left , image . Top ) ;
}
return resultSheet ;
}
private static void RemovePicturesFromSheet ( IXLWorksheet sheet )
{
var filteredPics = sheet . Pictures . Select ( p = > p . Name ) . Distinct ( ) . ToList ( ) ;
foreach ( var n in filteredPics )
sheet . Pictures . Delete ( n ) ;
}
private static IXLRange GetCellsRange ( IXLWorksheet sheet )
{
var firstTableCell = sheet . FirstCellUsed ( ) ;
var lastTableCell = sheet . LastCellUsed ( ) ;
var rngData = sheet . Range ( firstTableCell . Address , lastTableCell . Address ) ;
return rngData ;
}
}
class ImageInfo
{
public int Id { get ; set ; }
public byte [ ] Data { get ; set ; }
public int Height { get ; set ; }
public int Width { get ; set ; }
public IXLAddress TopLeftCellAddress { get ; set ; }
public int Left { get ; set ; }
public int Top { get ; set ; }
2021-08-29 17:25:16 +05:00
}
}