Imports System.Console
Imports System.IO
Imports System.Xml
Imports NLog

Module Main
    Private mainDoc As XmlDocument
    Private markDoc As XmlDocument
    Private patentDoc As XmlDocument

    Private parserMarks As New ParserMarks()
    Private parserPatents As New ParserPatents()

    Private dpmaPatents As DPMAConnectPatents
    Private dpmaMarks As DPMAConnectMarks

    Private query As String
    Private version As String

    Private patents As New List(Of Patent)
    Private propsMarks = New List(Of String) From {
        "RegistrationOfficeCode", ' Aktenzeichen
        "RegistrationDate", ' Anmeldetag
        "RegistrationNumber", ' Registernummer
        "MarkCurrentStatusCode", ' Aktenzustand
        "MarkVerbalElementText", ' Wiedergabe der Marke
        "MarkFeature", ' Markenform
        "ApplicationDate", ' Anmeldetag
        "Applicant", ' Inhaber
        "Representative", ' Vertreter
        "PublicationDate", 'Tag der Veröffentlichung
        "ExpiryDate", 'Schutzendedatum
        "TerminationDate", 'Wirkungsdatum Löschung
        "OppositionPeriodStartDate", 'Wiederspruchsfrist Anfang
        "OppositionPeriodEndDate", 'Wiederspruchsfrist Ende
        "Classification", 'Klasse(n) Nizza
        "ClassificationLong" 'Klasse(n) Nizza vollständig
    }

    Private propsPatents = New List(Of String) From {
        "LeadingRegisteredNumber", ' Aktenzeichen
        "Type", ' Schutzrechtsart
        "Status", ' Status
        "Title", ' Titel
        "ICM", 'IPC-Klasse
        "ApplicationDate", ' Anmeldetag
        "PublicationDate", ' Offenlegungstag
        "Inventors", ' Erfinder
        "Applicants", ' Inhaber
        "Abstract" ' Zusammenfassung
    }

    Public DataDir As String = "Data"
    Public LogDir As String = "Log"

    Public MainFileMarks As String = "DPMA-Marks.xml"
    Public MainFilePatents As String = "DPMA-Patents.xml"
    Public MainPathMarks As String = Path.Combine(DataDir, MainFileMarks)
    Public MainPathPatents As String = Path.Combine(DataDir, MainFilePatents)

    Public logger As Logger
    Public config As ConfigValues
    Public database As DB


    Sub Main()
        Try
            logger = LogManager.GetLogger("Main")
            config = AppConfig.GetConfiguration()

            database = New DB(config.connstring, config.database)
            version = AppConfig.GetVersion()

            logger.Info("{0} (Version {1}) started", My.Application.Info.Title, version)

            If Not Directory.Exists(DataDir) Then
                Directory.CreateDirectory(DataDir)
            End If

            If Not Directory.Exists(LogDir) Then
                Directory.CreateDirectory(LogDir)
            End If

            Dim marks As New List(Of Mark)
            Dim patents As New List(Of Patent)

            Dim updatedMarks As Integer = 0
            Dim addedMarks As Integer = 0
            Dim failedMarks As Integer = 0

            Dim updatedPatents As Integer = 0
            Dim addedPatents As Integer = 0
            Dim failedPatents As Integer = 0

            ' Abfrage starten
            If config.searchType.Contains("M") Then
                marks = ImporterMarks.FromDPMA()

                Dim formId As Integer = database.GetFormIdFor("Marken")


                For Each m As Mark In marks

                    logger.Debug("Mark Verbal Element: {0}", m.MarkVerbalElementText)

                    Dim mainControlId As Integer

                    ' Das eindeutige Control suchen
                    mainControlId = database.GetControlId(formId)

                    ' Über mainControlId überprüfen, ob marke vorhanden
                    Dim markExists As Integer = database.GetRecordId(mainControlId, m.ApplicationNumber)
                    logger.Debug("Mark {0} exists: {1}", markExists, CBool(markExists))

                    ' Wenn noch nicht vorhanden
                    If (markExists = 0) Then
                        Try
                            ' Einen Record erstellen
                            Dim recordId = database.InsertRecord(formId)
                            logger.Info("New record created with GUID: " & recordId)
                            ' Den Leit-Wert einfügen für mainControlId
                            Dim valueId = database.InsertValue(mainControlId, recordId, m.ApplicationNumber)
                            addedMarks = addedMarks + 1
                            logger.Debug("Value inserted - Property: {0}, Value: {1}, ControlId: {2}", "ApplicationNumber", m.ApplicationNumber, mainControlId)

                            ' alle anderen properties zu dieser marke einfügen
                            For Each prop As String In propsMarks
                                ' ControlID für die aktuelle property holen
                                Dim controlId = database.GetControlId(formId, prop)
                                ' Wert für die aktuelle property holen
                                Dim value = database.GetPropertyMark(m, prop)

                                If controlId = 0 Then
                                    logger.Warn("Value NOT inserted - ControlId for Property {0} could not be found.")
                                    Continue For
                                End If

                                ' Wert einfügen
                                database.InsertValue(controlId, recordId, value)

                                ' Wenn Bildmarke oder Wort- und Bildmarke, Bild einfügen
                                If prop = "MarkFeature" Then
                                    If value = "wort-bildmarke" Or value = "bildmarke" Then
                                        Dim imageControlId = database.GetControlId(formId, "MarkImage")
                                        Dim bimage() As Byte = Convert.FromBase64String(m.Image.BinaryImage)
                                        logger.Debug("Image inserted, RecordId: {0}")
                                        database.InsertImage(bimage, imageControlId, recordId)
                                    End If
                                End If

                                logger.Debug("Value inserted - Property: {0}, Value: {1}, ControlId: {2}", prop, value, controlId)
                            Next

                            addedMarks += 1
                        Catch ex As Exception
                            logger.Error($"Exception while ADDING mark {m.ApplicationNumber}: {ex.Message}")
                            failedMarks += 1

                            Continue For
                        End Try
                    Else
                        Try
                            ' Marke aktualisieren
                            Dim recordId As Integer = markExists
                            Dim propsChanged = False

                            logger.Info("Existing Record updated with GUID: {0}", recordId)

                            For Each prop As String In propsMarks
                                ' ControlID für die aktuelle property holen
                                Dim controlId = database.GetControlId(formId, prop)
                                ' Wert für die aktuelle property holen
                                Dim value = database.GetPropertyMark(m, prop)

                                ' Wert aktualisieren
                                database.UpdateValue(controlId, recordId, value)

                                ' Wenn Bildmarke oder Wort- und Bildmarke, Bild aktualisieren
                                If prop = "MarkFeature" Then
                                    If value = "wort-bildmarke" Or value = "bildmarke" Then
                                        Dim imageControlId = database.GetControlId(formId, "MarkImage")
                                        Dim bimage() As Byte = Convert.FromBase64String(m.Image.BinaryImage)
                                        database.UpdateImage(bimage, imageControlId, recordId)
                                    End If
                                End If

                                logger.Debug("Value updated - Property: {0}, ControlId: {1}", prop, controlId)

                                'Dim hasChanged As Boolean = Not db.IsEqual(controlId, recordId, value)
                                'logger.Debug("Value for {0} has changed", recordId)

                                'If hasChanged Then
                                '    propsChanged = True
                                '    ' Wert aktualisieren
                                '    db.UpdateValue(controlId, recordId, value)
                                '    logger.Debug("Value updated - Property: {0}, ControlId: {1}", prop, controlId)
                                'End If
                            Next

                            updatedMarks += 1
                        Catch ex As Exception
                            logger.Error($"Exception while UPDATING mark {m.ApplicationNumber}: {ex.Message}")
                            failedMarks += 1

                            Continue For
                        End Try
                    End If
                Next

                logger.Info($"{addedMarks} Marks added, {updatedMarks} updated, {failedMarks} failed." & vbCrLf)
            End If

            If config.searchType.Contains("P") Then
                patents = ImporterPatents.FromDPMA()

                Dim formId As Integer = database.GetFormIdFor("Patente")

                For Each p In patents

                    logger.Debug("Patent Title: {0}", p.Title)

                    Dim mainControlId As Integer

                    ' Das eindeutige Control suchen
                    mainControlId = database.GetControlId(formId, "LeadingRegisteredNumber")

                    ' Über mainControlId überprüfen, ob patent vorhanden
                    Dim patentExists As Integer = database.GetRecordId(mainControlId, p.LeadingRegisteredNumber)
                    logger.Debug("Patent {0} exists: {1}", patentExists, CBool(patentExists))

                    If (patentExists = 0) Then
                        Try
                            ' Einen Record erstellen
                            Dim recordId = database.InsertRecord(formId)
                            logger.Info("New record created with GUID: " & recordId)
                            ' Den Leit-Wert einfügen für mainControlId
                            Dim valueId = database.InsertValue(mainControlId, recordId, p.LeadingRegisteredNumber)
                            addedPatents = addedPatents + 1
                            logger.Debug("Value inserted - Property: {0}, Value: {1}, ControlId: {2}", "LeadingRegisteredNumber", p.LeadingRegisteredNumber, mainControlId)

                            ' alle anderen properties zu dieses patents einfügen
                            For Each prop As String In propsPatents
                                ' ControlID für die aktuelle property holen
                                Dim controlId = database.GetControlId(formId, prop)
                                ' Wert für die aktuelle property holen
                                Dim value = database.GetPropertyPatent(p, prop)

                                If controlId = 0 Then
                                    logger.Warn("Value NOT inserted - ControlId for Property {0} could not be found.")
                                    Continue For
                                End If

                                ' Wert einfügen
                                database.InsertValue(controlId, recordId, value)

                                logger.Debug("Value inserted - Property: {0}, Value: {1}, ControlId: {2}", prop, value, controlId)
                            Next

                            addedPatents += 1
                        Catch ex As Exception
                            logger.Error($"Exception while ADDING patent {p.LeadingRegisteredNumber}: {ex.Message}")
                            failedPatents += 1

                            Continue For
                        End Try
                    Else
                        Try
                            ' Patent aktualisieren
                            Dim recordId As Integer = patentExists
                            Dim propsChanged = False

                            logger.Info("Existing Record updated with GUID: {0}", recordId)

                            For Each prop As String In propsPatents
                                ' ControlID für die aktuelle property holen
                                Dim controlId = database.GetControlId(formId, prop)
                                ' Wert für die aktuelle property holen
                                Dim value = database.GetPropertyPatent(p, prop)

                                If controlId = 0 Then
                                    logger.Warn("Value NOT updated - ControlId for Property {0} could not be found.")
                                    Continue For
                                End If

                                ' Wert aktualisieren
                                database.UpdateValue(controlId, recordId, value)

                                logger.Debug("Value updated - Property: {0}, ControlId: {1}", prop, controlId)
                            Next

                            updatedPatents += 1
                        Catch ex As Exception
                            logger.Error($"Exception while UPDATING patent {p.LeadingRegisteredNumber}: {ex.Message}")
                            failedPatents += 1

                            Continue For
                        End Try
                    End If
                Next

                logger.Info($"{addedPatents} Marks added, {updatedPatents} updated, {failedPatents} failed." & vbCrLf)
            End If

            logger.Debug("=================== IMPORT END ===================")
        Catch ex As Exception
            logger.Error("==================================================")
            logger.Error("=================== ERROR ========================")
            logger.Error("==================================================")
            logger.Error("An Error occurred: {0}", GetExceptionInfo(ex))
        End Try
    End Sub

    Public Function GetExceptionInfo(ex As Exception) As String
        Dim Result As String
        Dim hr As Integer = Runtime.InteropServices.Marshal.GetHRForException(ex)
        Result = ex.GetType.ToString & "(0x" & hr.ToString("X8") & "): " & ex.Message & Environment.NewLine & ex.StackTrace & Environment.NewLine
        Dim st As StackTrace = New StackTrace(ex, True)
        For Each sf As StackFrame In st.GetFrames
            If sf.GetFileLineNumber() > 0 Then
                Result &= "Line:" & sf.GetFileLineNumber() & " Filename: " & IO.Path.GetFileName(sf.GetFileName) & Environment.NewLine
            End If
        Next
        Return Result
    End Function
End Module
