Imports System.Collections.Generic
Imports System.Data
Imports System.Data.SqlClient
Imports System.Net
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Reflection
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Web.Http
Imports System.Web.Http.Controllers
Imports System.Xml
Imports Windream.WebService.Documents
Imports Windream.WebService.Logging
Imports Windream.WebService.WebAPI.PlugIns
Imports WINDREAMLib
Imports WMCNNCTDLLLib
Imports WMOBRWSLib

Namespace Controllers

    Public Class DigitalDataController
        Inherits PlugInBaseController

        Private ReadOnly _docController As IDocumentsController
        Private _session As IWMSession6
        Private _logger As ILogging

        ''' <summary>
        ''' Gets the routes settings for the controller.
        ''' This property will automatically be called from the windream Web Service - WebAPI framework.
        ''' </summary>
        ''' <value>
        ''' The routes settings of the controller.
        ''' </value>
        Public Overrides ReadOnly Property RoutesSettings As IEnumerable(Of RouteSettings)
            Get
                Return New List(Of RouteSettings) From {
                    New RouteSettings("DigitalDataController", "DigitalData/{action}/{id}", New With {
                        .id = RouteParameter.Optional, .controller = "DigitalData"
                    })
                }
            End Get
        End Property

        ''' <summary>
        ''' Initializes a new instance of the <see cref="DigitalDataController"/> class.
        ''' </summary>
        Sub New(pLogger As ILogging)
            _logger = pLogger

            _logger.Write("[INIT] Die Initialisierung wurde abgeschlossen.")
        End Sub

        Private Function GetPluginPath()
            Dim s = Assembly.GetExecutingAssembly().CodeBase
            s = New Uri(s).AbsolutePath
            s = Uri.UnescapeDataString(s)
            s = IO.Path.GetFullPath(s)
            s = IO.Path.GetDirectoryName(s)

            Return s
        End Function

        Private Function GetConfig() As XmlDocument
            Dim path As String = GetPluginPath()
            Dim configFile = path & "\config.xml"

            If IO.File.Exists(configFile) Then
                Dim Doc As New XmlDocument()
                Doc.Load(configFile)

                Return Doc
            Else
                _logger.Write($"[CONFIG] Konfigurations Datei {configFile} wurde NICHT gefunden!")

                Return Nothing
            End If
        End Function

        Private Function GetConnectionString() As String
            Dim oConfig = GetConfig()

            If oConfig IsNot Nothing Then
                Dim connectionString As String = oConfig.DocumentElement.SelectSingleNode("/config/connectionString").InnerText
                Return connectionString
            Else
                Return Nothing
            End If
        End Function

        ''' <summary>
        ''' A simple example of a http-get service method implementation.
        ''' </summary>
        ''' <param name="docId">windream Document-ID</param>
        ''' <param name="userId">windream User-ID</param>
        ''' <remarks>This method creates a nice greeting.</remarks>
        <HttpGet>
        Public Function BNSDownload(<FromUri> docId As Integer, <FromUri> userId As String) As HttpResponseMessage
            Dim DT As New DataTable("DDRESULT")
            Dim Domain, Username, Password As String

            _logger.Write($"[REQUEST] Anfrage von Benutzer-ID {userId} für Dokument-ID {docId}")

            Try
                Using oConnection As New SqlConnection(GetConnectionString())
                    Using oAdapter As New SqlDataAdapter($"SELECT DOMAIN, USERNAME, PW FROM TBDD_WEBSERVICE_USER_EX WHERE USERNAME_LINK = '{userId}'", oConnection)
                        oAdapter.Fill(DT)
                    End Using
                End Using

                'DT = _database.GetDatatable($"SELECT DOMAIN, USERNAME, PW FROM TBDD_WEBSERVICE_USER_EX WHERE USERNAME_LINK = '{userId}'")
            Catch ex As Exception
                _logger.Write("[DATABASE] Fehler beim Zugriff auf die Datenbank ")
                _logger.WriteError(ex)

                Return CreateResponseMessage(Request, HttpStatusCode.InternalServerError)
            End Try

            If DT.Rows.Count = 0 Then
                _logger.Write($"[DATABASE] BenutzerID {userId} wurde nicht in der Datenbank gefunden.")
                Return CreateResponseMessage(Request, $"Benutzer {userId} wurde nicht gefunden", HttpStatusCode.Unauthorized)
            Else
                Dim oRow As DataRow = DT.Rows.Item(0)

                Domain = oRow.Item("DOMAIN")
                Username = oRow.Item("USERNAME")
                Password = oRow.Item("PW")

                _logger.Write($"[DATABASE] BenutzerID {userId} wurde gefunden.")
            End If

            Dim loggedIn As Boolean = CreateSessionForUser(Username, Password, Domain)

            If Not loggedIn Then
                Return CreateResponseMessage(Request, $"Session für Benutzer {userId} konnte nicht aufgebaut werden. Weitere Informationen im Log", HttpStatusCode.BadRequest)
            End If


            Dim WMDoc As IWMObject7
            Dim WMStream As IWMStream
            Dim fileContent As Byte()

            Try
                WMDoc = _session.GetWMObjectById(WMEntity.WMEntityDocument, docId)
            Catch ex As Exception
                _logger.Write("[WINDREAM/GetWMObjectById] Ein Fehler beim Zugriff auf Windream ist aufgetreten ")
                _logger.WriteError(ex)
                _logger.Write($"[WINDREAM/Session] Session für Benutzer {Username} wird geschlossen")
                _session.Logout()

                Return CreateResponseMessage(Request, "Document not found", HttpStatusCode.NotFound)
            End Try

            Try
                WMStream = WMDoc.OpenStream("BinaryObject", WMObjectStreamOpenMode.WMObjectStreamOpenModeRead)
                fileContent = WMStream.Read(WMStream.GetSize())
            Catch ex As Exception
                _logger.Write("[WINDREAM/OpenStream] Ein Fehler beim Zugriff auf Windream ist aufgetreten")
                _logger.WriteError(ex)
                _logger.Write($"[WINDREAM/Session] Session für Benutzer {Username} wird geschlossen")
                _session.Logout()

                Return CreateResponseMessage(Request, HttpStatusCode.InternalServerError)
            End Try

            _logger.Write($"[WINDREAM/Session] Session für Benutzer {Username} wird geschlossen")
            _session.Logout()

            ' Gibt die Datei zum Download zurück
            Return CreateFileResponseMessage(fileContent, WMDoc.aName)
        End Function

        Private Function CreateFileResponseMessage(data As Byte(), filename As String) As HttpResponseMessage
            _logger.Write($"[WINDREAM/Download] Datei {filename} wird für Download zur Verfügung gestellt")
            Dim Res = New HttpResponseMessage With {
                .StatusCode = HttpStatusCode.OK,
                .Content = New ByteArrayContent(data)
            }
            Res.Content.Headers.ContentType = New MediaTypeHeaderValue("application/octet-stream")
            Res.Content.Headers.ContentDisposition = New ContentDispositionHeaderValue("attachment") With {
                .FileName = filename
            }
            Return Res
        End Function

        Private Function CreateSessionForUser(username As String, password As String, domain As String)
            Dim WMServerBrowser As New ServerBrowser()
            Dim DMSServer As String
            Dim Connect As IWMConnect2
            Dim Session As IWMSession6
            Dim User As WMOTOOLLib.WMUserIdentity

            Try
                '' Get the current Windream Server
                DMSServer = WMServerBrowser.GetCurrentServer()
            Catch ex As Exception
                _logger.Write($"[WINDREAM/ServerBrowser] DMS Server konnte nicht ausgelesen werden.")
                _logger.WriteError(ex)
                Return False
            End Try

            Try
                ' Create a User Object for Session
                User = New WMOTOOLLib.WMUserIdentity With {
                    .aDomain = domain,
                    .aPassword = password,
                    .aUserName = username,
                    .aServerName = DMSServer
                }
            Catch ex As Exception
                _logger.Write($"[WINDREAM/User] User Objekt konnte nicht erstellt werden.")
                _logger.WriteError(ex)
                Return False
            End Try


            _logger.Write("[WINDREAM/Session] Session wird aufgebaut")
            _logger.Write($"[WINDREAM/Session] Username: {username}")
            _logger.Write($"[WINDREAM/Session] Passwort: {password}")
            _logger.Write($"[WINDREAM/Session] Domäne: {domain}")
            _logger.Write($"[WINDREAM/Session] Windream Server: {DMSServer}")

            Try
                ' Create Connect Object for Session
                Connect = New WMConnect With {
                    .ModuleId = 9
                }
            Catch ex As Exception
                _logger.Write($"[WINDREAM/Connect] Connect Objekt konnte nicht erstellt werden.")
                _logger.WriteError(ex)
                Return False
            End Try


            Try
                Session = Connect.Login(User)
                _logger.Write($"[WINDREAM/Session] Session wurde aufgebaut")

                If Session.aLoggedin Then
                    _session = Session

                    _logger.Write($"[WINDREAM/Session] Benutzer {username} ist eingeloggt")
                    Return True
                Else
                    _logger.Write($"[WINDREAM/Session] Fehler beim Aufbau der Session. Benutzer {username} ist nicht eingeloggt!")
                    Return False
                End If
            Catch ex As Exception
                _logger.Write($"[WINDREAM/Session] Fehler bei Login von Benutzer {username}!")
                _logger.WriteError(ex)

                If Not IsNothing(Session) AndAlso Session.aLoggedin Then
                    _session = Session
                    _logger.Write($"[WINDREAM/Session] Benutzer {username} ist eingeloggt")
                    Return True
                Else
                    _logger.Write($"[WINDREAM/Session] Fehler beim Aufbau der Session. Benutzer {username} ist nicht eingeloggt!")
                    _logger.WriteError(ex)
                    Return False
                End If
            End Try
        End Function

    End Class

End Namespace