Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization
Imports System.Xml.XPath
Imports System.Xml.Xsl
Imports DigitalData.Modules.Interfaces.Exceptions
Imports DigitalData.Modules.Logging
Imports GdPicture14

Public Class ZUGFeRDInterface
    Private _logConfig As LogConfig
    Private _logger As Logger

    Private Const ZUGFERD_CONVERTER_EXE = "ZUGFeRDInterface\pdf_zugferd_lib\pdf_zugferd_test.exe"
    Private Const ZUGFERD_CONVERTER_SUCCESS_MESSAGE = "Document contains ZUGFeRD data."

    Public Enum ErrorType
        NoValidFile
        NoZugferd
        NoValidZugferd
        MissingProperties
    End Enum

    Public ReadOnly Property FileGroup As FileGroups
    Public ReadOnly Property PropertyValues As PropertyValues

    Public Sub New(LogConfig As LogConfig, GDPictureKey As String)
        _logConfig = LogConfig
        _logger = _logConfig.GetLogger()

        FileGroup = New FileGroups(_logConfig)
        PropertyValues = New PropertyValues(_logConfig)

        Try
            Dim oLicenseManager As New LicenseManager
            oLicenseManager.RegisterKEY(GDPictureKey)
        Catch ex As Exception
            _logger.Warn("GDPicture License could not be registered!")
            _logger.Error(ex)
        End Try
    End Sub


    ''' <summary>
    ''' Validates a ZUGFeRD File and extracts the XML Document from it
    ''' </summary>
    ''' <param name="Path"></param>
    ''' <exception cref="ZUGFeRDExecption"></exception>
    ''' <returns></returns>
    Public Function ExtractZUGFeRDFile(Path As String) As CrossIndustryDocumentType
        Dim oXmlDocument = ValidateZUGFeRDFile(Path)

        If IsNothing(oXmlDocument) Then
            Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
        End If

        Return SerializeZUGFeRDDocument(oXmlDocument)
    End Function

    Public Function ExtractZUGFeRDFileWithGDPicture(Path As String) As CrossIndustryDocumentType
        Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Path)

        If IsNothing(oXmlDocument) Then
            Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
        End If

        Return SerializeZUGFeRDDocument(oXmlDocument)
    End Function

    Public Function ExtractZUGFeRDFileWithGDPicture(Stream As Stream) As CrossIndustryDocumentType
        Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Stream)

        If IsNothing(oXmlDocument) Then
            Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
        End If

        Return SerializeZUGFeRDDocument(oXmlDocument)
    End Function

    Public Function ValidateZUGFeRDFile(Path As String) As XPathDocument
        Dim oProcessOutput, oProcessError As String
        Dim oXmlDocument As XPathDocument
        Dim oTempFile = IO.Path.GetTempFileName()

        Dim oProcess As New Process() With {
            .StartInfo = New ProcessStartInfo() With {
                .FileName = ZUGFERD_CONVERTER_EXE,
                .RedirectStandardError = True,
                .RedirectStandardOutput = True,
                .UseShellExecute = False,
                .Arguments = $"-i ""{Path}"" -o ""{oTempFile}"""
            }
        }

        Try
            oProcess.Start()
            oProcessOutput = oProcess.StandardOutput.ReadToEnd()
            oProcessError = oProcess.StandardError.ReadToEnd()
            oProcess.WaitForExit()

            _logger.Debug("Process Output:")
            _logger.Debug(oProcessOutput)
        Catch ex As Exception
            _logger.Error(ex)
            Throw ex
        End Try

        If Not oProcessOutput.ToLower.Contains(ZUGFERD_CONVERTER_SUCCESS_MESSAGE.ToLower) Then
            _logger.Warn("File {0} is not a valid ZUGFeRD File!", Path)
            Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
        End If

        Try
            oXmlDocument = New XPathDocument(oTempFile)

        Catch ex As Exception
            _logger.Error(ex)
            Throw ex
        End Try

        Return oXmlDocument
    End Function

    Public Function ValidateZUGFeRDFileWithGDPicture(Stream As Stream) As XPathDocument
        Dim oAttachmentExtractor = New PDFAttachments(_logConfig)
        Dim oAllowedExtensions = New List(Of String) From {"xml"}

        Try
            Dim oResults = oAttachmentExtractor.Extract(Stream, oAllowedExtensions)
            Return HandleAttachments(oResults)
        Catch ex As Exception
            _logger.Error(ex)
            Throw ex
        End Try
    End Function

    Public Function ValidateZUGFeRDFileWithGDPicture(Path As String) As XPathDocument
        Dim oAttachmentExtractor = New PDFAttachments(_logConfig)
        Dim oAllowedExtensions = New List(Of String) From {"xml"}

        Try
            Dim oResults = oAttachmentExtractor.Extract(Path, oAllowedExtensions)
            Return HandleAttachments(oResults)
        Catch ex As Exception
            _logger.Error(ex)
            Throw ex
        End Try
    End Function

    Private Function HandleAttachments(Results As List(Of PDFAttachments.AttachmentResult)) As XPathDocument
        Dim oXmlDocument As XPathDocument

        If Results Is Nothing Then
            Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
        End If

        If Results.Count = 0 Then
            Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
        End If

        Dim oFound As Boolean = False
        Dim oFoundResult As PDFAttachments.AttachmentResult = Nothing

        For Each oResult In Results
            If oResult.FileName.ToUpper() = PDFAttachments.ZUGFERD_XML_FILENAME.ToUpper() Then
                oFound = True
                oFoundResult = oResult
            End If
        Next

        If Not oFound Then
            Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
        End If

        Try
            Using oStream As New MemoryStream(oFoundResult.FileContents)
                oXmlDocument = New XPathDocument(oStream)
            End Using

            Return oXmlDocument
        Catch ex As Exception
            _logger.Error(ex)
            Throw ex
        End Try
    End Function

    Public Function SerializeZUGFeRDDocument(Document As XPathDocument) As CrossIndustryDocumentType
        Try
            Dim oNavigator As XPathNavigator = Document.CreateNavigator()
            Dim oReader = oNavigator.ReadSubtree()
            Dim oSerializer As New XmlSerializer(GetType(CrossIndustryDocumentType))

            Return oSerializer.Deserialize(oReader)
        Catch ex As Exception
            _logger.Error(ex)
            Throw New ZUGFeRDExecption(ErrorType.NoValidZugferd, "Datei ist eine ungültige ZUGFeRD Datei.")
        End Try
    End Function
End Class
