Imports System.IO
Imports System.IO.Path
Imports System.Text.RegularExpressions

Imports WINDREAMLib
Imports WINDREAMLib.WMCOMEvent
Imports WINDREAMLib.WMEntity
Imports WINDREAMLib.WMObjectEditMode
Imports WMOBRWSLib
Imports WMOSRCHLib
Imports WMCNNCTDLLLib
Imports WMOTOOLLib

Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language

''' <module>Windream</module>
''' <version>0.0.0.2</version>
''' <date>23.10.2018</date>
''' <summary>
''' Module that provides methods to access the Windream ECM
''' </summary>
''' <dependencies>
''' NLog, >= 4.5.8
''' </dependencies>
''' <params>
''' LogConfig, DigitalData.Modules.Logging.LogConfig
'''     The LogFactory containing the current log config. Used to instanciate the class logger for this and any dependent class
'''                 
''' ClientDriveLetter, String
'''     Drive Letter of the Windream Drive, should default to `W`
'''             
''' ClientSupport64Bit, Boolean
'''     Should this session support 64bit methods/functionality?
'''                 
''' SessionReconnect, Boolean
'''     Should the session reconnect automatically when the connection to the server is lost?          
'''                 
''' SessionServerName, String
'''     Name of the server used in the connection. If this is `Nothing`, the current server defined in the client is used
'''                 
''' SessionUserName, String
'''     Name of the user that is used in the connection. If this is `Nothing`, the currently signed in user is used
'''                 
''' SessionPassword, String
'''     User-password that is used in the connection. If this is `Nothing`, the currently signed in user is used
'''                 
''' SessionDomain, String
'''     User-domain that is used in the connection. If this is `Nothing`, the currently signed in user is used
''' </params>
''' <props>
''' ClientDriveLetter, String (readonly)
''' ClientSupports64Bit, Boolean (readonly)               
''' Session, IWMSession2 (readonly)
''' SessionLoggedin, Boolean (readonly)
''' SessionReconnect, Boolean (readonly)
''' SessionServername, String (readonly)
''' Objecttypes, List(Of String) (readonly)
''' </props>
''' <example>
''' _windream = New ConnectionBuilder(LogConfig).
'''     WithDriveLetter("W").
'''     WithSessionReconnect().
'''     With64BitSupport().
'''     WithServerName("sdd-vmx02-aps01").
'''     Connect()
''' </example>
''' <remarks>
''' This class should not be instanciated directly. Instead, ConnectionBuilder should be used.
''' </remarks>
Public Class Windream
#Region "+++++ Konstanten +++++"
    Protected Const WMObjectEditModeObject = &H1F
    Protected Const WMObjectStreamOpenModeReadWrite = 2
    Protected Const WMEntityObjectType = 10
    Protected Const WMEntityDocument = 1

    Public Const WMObjectVariableValueTypeUndefined = 0
    Public Const WMObjectVariableValueTypeString = 1
    Public Const WMObjectVariableValueTypeInteger = 2
    Public Const WMObjectVariableValueTypeFloat = 3
    Public Const WMObjectVariableValueTypeBoolean = 4
    Public Const WMObjectVariableValueTypeDate = 5
    Public Const WMObjectVariableValueTypeFixedPoint = 6
    Public Const WMObjectVariableValueTypeTimeStamp = 7
    Public Const WMObjectVariableValueTypeCurrency = 8
    Public Const WMObjectVariableValueTypeTime = 9
    Public Const WMObjectVariableValueTypeVariant = 10
    Public Const WMObjectVariableValueTypeMask = &HFFF
    Public Const WMObjectVariableValueFlagMask = &HFFFFF000
    Public Const WMObjectVariableValueTypeVector = &H1000
    Public Const WMObjectVariableValueTypeFulltext = &H2000
    Public Const WMObjectVariableValueTypeDefaultValue = &H4000

    Public Const WMObjectEditModeIndexEdit = &H3DA
#End Region
#Region "Private Properties"
    Private ReadOnly _logger As Logger
    Private ReadOnly _logConfig As LogConfig
    Private ReadOnly _fileSystem As Filesystem.File
    Private ReadOnly _sessionDomain As String
    Private ReadOnly _sessionPassword As String
    Private ReadOnly _sessionUsername As String

#End Region
#Region "Public Properties"
    Public ReadOnly Property ClientDriveLetter As String
    Public ReadOnly Property ClientBasePath As String
    Public ReadOnly Property ClientSupports64Bit As Boolean

    Public ReadOnly Property Session As IWMSession2
    Public ReadOnly Property SessionLoggedin As Boolean = False
    Public ReadOnly Property SessionReconnect As Boolean
    Public ReadOnly Property SessionServername As String

    Public ReadOnly Property UsesDriveLetter As Boolean = True

    ''' <returns>A list of object types that are available</returns>
    Public ReadOnly Property ObjectTypes As List(Of String)
        Get
            Dim types As WMObjects = GetObjectTypes()
            Dim list As New List(Of String)

            For Each type As WMObject In types
                list.Add(type.aName)
            Next

            Return list
        End Get
    End Property



#End Region
    ''' <summary>
    ''' Creates a new Windream object and connects to a server with the provided options and credentials
    ''' </summary>
    ''' <param name="LogConfig"></param>
    ''' <param name="SessionReconnect"></param>
    ''' <param name="ClientDriveLetter"></param>
    ''' <param name="ClientSupport64Bit"></param>
    ''' <param name="SessionServerName"></param>
    ''' <param name="SessionUserName"></param>
    ''' <param name="SessionPassword"></param>
    ''' <param name="SessionDomain"></param>
    ''' <exception cref="Exceptions.SessionException"></exception>
    Public Sub New(LogConfig As LogConfig, SessionReconnect As Boolean, ClientDriveLetter As String, BasePath As String, ClientSupport64Bit As Boolean, SessionServerName As String, SessionUserName As String, SessionPassword As String, SessionDomain As String)
        ' Create logger and save LogFactory for dependent classes
        _logger = LogConfig.GetLogger()
        _logConfig = LogConfig
        _fileSystem = New Filesystem.File(LogConfig)

        ' Create a session
        Dim oSession As IWMSession2 = NewSession(SessionServerName, SessionUserName, SessionPassword, SessionDomain)

        ' If no session could be created, exit 
        If oSession Is Nothing Then
            Throw New Exceptions.SessionException()
        End If

        ' Set properties of currently established session
        Session = oSession
        SessionLoggedin = True

        Me.SessionReconnect = SessionReconnect
        Me.ClientDriveLetter = ClientDriveLetter
        Me.ClientSupports64Bit = ClientSupport64Bit
        Me.SessionServername = SessionServerName
        Me.ClientBasePath = GetNormalizedBasePath(BasePath)

        _logger.Debug("ClientBasePath: [{0}]", ClientBasePath)
        _logger.Debug("ClientDriveLetter: [{0}]", ClientDriveLetter)
        _logger.Debug("SessionServername: [{0}]", SessionServerName)
        _logger.Debug("SessionUserName: [{0}]", SessionUserName)
        _logger.Debug("SessionDomain: [{0}]", SessionDomain)

        If ClientDriveLetter = String.Empty Then
            UsesDriveLetter = False
        End If

        _sessionUsername = SessionUserName
        _sessionPassword = SessionPassword
        _sessionDomain = SessionDomain
    End Sub

    Public Function GetCleanedPath(Path As String) As String
        Return Regex.Replace(Path, Constants.REGEX_CLEAN_FILENAME, String.Empty)
    End Function

    Public Function GetChoiceListItems(ChoiceListName As String) As List(Of String)
        Dim oItems As New List(Of String)
        Dim oChoicelist As WMObject

        If TestSessionLoggedIn() = False Then
            Return oItems
        End If

        Try
            oChoicelist = Session.GetWMObjectByName(WMEntityChoiceList, ChoiceListName)
        Catch ex As Exception
            _logger.Error(ex, "Could not get choice list")
            Return oItems
        End Try

        Try
            Dim oChoiceListItems As Object = oChoicelist.GetVariableValue("vItems")

            If oChoiceListItems Is Nothing Then
                Return oItems
            End If

            For Each oChoiceListItem In oChoiceListItems
                oItems.Add(oChoiceListItem)
            Next

            Return oItems
        Catch ex As Exception
            _logger.Error(ex, "Could not get choice list items")
            Return oItems
        End Try
    End Function

    Public Function GetChoiceLists() As List(Of String)
        Dim oItems As New List(Of String)

        If TestSessionLoggedIn() = False Then
            Return oItems
        End If

        Try
            Dim oChoiceLists As WMObjects
            Dim oChoiceList As IWMObject2
            'load list of choicelists
            oChoiceLists = Session.GetAllObjects(WMEntityChoiceList)

            For Each oChoiceList In oChoiceLists
                oItems.Add(oChoiceList.aName)
            Next

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

    Public Function GetFileByPath(pPath As String) As WMObject
        If TestSessionLoggedIn() = False Then
            Return Nothing
        End If
        pPath = GetNormalizedPath(pPath)

        Dim oWMObject As WMObject
        Try
            oWMObject = Session.GetWMObjectByPath(WMEntityDocument, pPath)
            Return oWMObject
        Catch ex As Exception
            _logger.Error(ex)
            Return Nothing
        End Try
    End Function

    Public Function GetIndexType(IndexName As String) As Integer
        If TestSessionLoggedIn() = False Then
            Return Nothing
        End If

        Try
            Dim oAttribute = Session.GetWMObjectByName(WMEntityAttribute, IndexName)
            Dim oType = oAttribute.GetVariableValue("dwAttrType")
            Return oType
        Catch ex As Exception
            _logger.Error(ex)
            Return Nothing
        End Try
    End Function

    Public Function GetIndexValue(Path As String, IndexName As String) As List(Of String)
        Dim oResult As New List(Of String)

        If TestSessionLoggedIn() = False Then
            Return oResult
        End If

        Try
            Path = GetNormalizedPath(Path)
            Dim oWMObject As WMObject = Session.GetWMObjectByPath(WMEntityDocument, Path)

            If oWMObject Is Nothing Then
                Return oResult
            End If

            Dim oValues = oWMObject.GetVariableValue(IndexName)

            If oValues Is Nothing Then
                Return oResult
            End If

            If TypeOf oValues Is IEnumerable Then
                For Each oValue In oValues
                    oResult.Add(oValue)
                Next
            Else
                oResult.Add(oValues)
            End If

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

    Public Function GetIndiciesByObjecttype(ObjectTypeName As String) As List(Of String)
        If TestSessionLoggedIn() = False Then
            Return Nothing
        End If

        Dim oObjectType As WMObject
        Dim oIndexAttributes As WMObjectRelation
        Dim oIndexAttribute As WMObject
        Dim oIndex As WMObject
        Dim oRelProperties As WMObjectRelation
        Dim oTempSession As IWMSession2
        Dim oIndicies As New List(Of String)

        Try
            ' den Objekttyp laden
            oTempSession = DirectCast(Session, IWMSession2)
            oObjectType = Session.GetWMObjectByName(WMEntityObjectType, ObjectTypeName)

            ' Beziehung zu Indizes des Objekttyp auslesen
            oIndexAttributes = oObjectType.GetWMObjectRelationByName("TypeAttributes")

            ' alle Indizes durchlaufen
            For j As Integer = 0 To oIndexAttributes.Count - 1

                ' aktuellen Index auslesen
                oIndexAttribute = oIndexAttributes.Item(j)

                ' Eigenschaften des Index auslesen
                oRelProperties = oIndexAttribute.GetWMObjectRelationByName("Attribute")

                ' Index aus den Eigenschaften auslesen
                oIndex = oRelProperties.Item(0)

                ' Indexname speichern
                'aIndexNames(j) = oIndex.aName
                oIndicies.Add(oIndex.aName)
            Next

            ' Indexarray zurückgeben
            oIndicies.Sort()
            'Return aIndexNames
            Return oIndicies

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

    Public Function GetTypeIndiciesByObjecttype(ObjectTypeName As String, Optional SystemIndicies As Boolean = False) As List(Of String)
        If TestSessionLoggedIn() = False Then
            Return Nothing
        End If

        Dim oObjectType As IWMObject6
        Dim oTempSession As IWMSession2
        Dim oIndicies As New List(Of String)
        Dim oAttributeFlag As Integer = 0

        Try
            ' den Objekttyp laden
            oTempSession = DirectCast(Session, IWMSession2)
            oObjectType = Session.GetWMObjectByName(WMEntityObjectType, ObjectTypeName)

            If SystemIndicies = True Then
                oAttributeFlag = Constants.ATTRIBUTE_TYPE_SYSTEMINDEX
            Else
                oAttributeFlag = Constants.ATTRIBUTE_TYPE_TYPEINDEX
            End If

            Dim oVariableNames As WMObjectVariableNames = oObjectType.GetVariableNames(oAttributeFlag, False)

            For oIndex = 0 To oVariableNames.Count - 1
                oIndicies.Add(oVariableNames.Item(oIndex))
            Next

            Return oIndicies
        Catch ex As Exception
            _logger.Warn("Type Indicies could not be read")
            _logger.Error(ex)
            Return Nothing
        End Try
    End Function

    Public Function NewSession(Optional ServerName As String = Nothing, Optional UserName As String = Nothing, Optional Password As String = Nothing, Optional Domain As String = Nothing) As IWMSession2
        Dim oBrowser As ServerBrowser
        Dim oConnect As IWMConnect2
        Dim oSession As IWMSession2
        Dim oCredentials As WMUserIdentity

        Dim oImpersonation As Boolean
        Dim oServerNameFromClient As Boolean

        ' Create initial windream objects
        Try
            oBrowser = New ServerBrowser()
            oConnect = New WMConnect()
            _logger.Info("Successfully created windream objects")
        Catch ex As Exception
            _logger.Error(ex, "Error while creating windream objects")
            Return Nothing
        End Try

        ' If no server was supplied, try to get the current server set in the client
        Try
            If ServerName Is Nothing OrElse ServerName.Length = 0 Then
                ServerName = oBrowser.GetCurrentServer
                oServerNameFromClient = True
            Else
                oServerNameFromClient = False
            End If
        Catch ex As Exception
            _logger.Error(ex, "Error while getting Servername")
            Return Nothing
        End Try

        _logger.Info("Servername: {0}", ServerName)
        _logger.Info("Servername aquired from client: {0}", oServerNameFromClient)

        'Test connection to windream server
        Try
            Dim response = My.Computer.Network.Ping(ServerName)
            If response = False Then
                _logger.Warn("Windream Server {0} refused connection", ServerName)
                Return Nothing
            End If
        Catch ex As Exception
            _logger.Error(ex)
            Return Nothing
        End Try

        ' If username, password and domain are set, login with impersonation
        ' Else, login with current credentials
        If UserName IsNot Nothing And Password IsNot Nothing And Domain IsNot Nothing Then
            oImpersonation = True
            oCredentials = New WMUserIdentity() With {
                .aServerName = ServerName,
                .aUserName = UserName,
                .aPassword = Password,
                .aDomain = Domain
            }

            oConnect.ModuleId = 9
        Else
            oImpersonation = False
            oCredentials = New WMUserIdentity() With {
                .aServerName = ServerName
            }
        End If
        If UserName IsNot Nothing Then
            If UserName <> String.Empty Then
                _logger.Info("Impersonated Login: {0}", oImpersonation)
                _logger.Info("Username: {0}", IIf(UserName IsNot Nothing, UserName, Environment.UserName))
                _logger.Info("Domain: {0}", IIf(Domain IsNot Nothing, Domain, Environment.UserDomainName))
            End If
        End If


        Try
            oSession = oConnect.Login(oCredentials)
            _logger.Info("Connected..Session created")
        Catch ex As Exception
            _logger.Error(ex, "Error while logging in")
            Return Nothing
        End Try

        Try
            ' Standardmässig hinterlegen dass abgelegte Dateien keine Indexmaske öffnet
            oSession.SwitchEvents(WMCOMEventWMSessionNeedIndex, False)
        Catch ex As Exception
            _logger.Error(ex, "Could not SwitchEvents")
            Return Nothing
        End Try

        If oSession.aLoggedin = False Then
            _logger.Warn("Session created but user {0} could not be logged in", Environment.UserName)
            Return Nothing
        End If

        _logger.Info("Connection to {0} established!", ServerName)
        Return oSession
    End Function

#Region "Public Methods"
    ''' <summary>
    ''' changes the archive end date
    ''' </summary>
    ''' <param name="wmfilepath">WM Filepath</param>
    ''' <param name="date_period">number/count of period (if </param>
    ''' <param name="date_unit">date_unity (d,m,y or day(s),month(s),years(s)</param>
    ''' <param name="dateFrom_value">dateFrom_value</param>
    ''' <returns>Returns true when date was set, false if not</returns>
    ''' <remarks></remarks>
    Public Function NewLifecycle_Period(ByVal wmfilepath As String, ByVal dateFrom_value As Date, ByVal date_period As Double, ByVal date_unit As String)
        Dim oWMObject As WMObject
        Try
            oWMObject = GetFileByPath(wmfilepath)
            _logger.Info($"Changing the archive end-date for file '{oWMObject.aName}', Items: {dateFrom_value},{date_period},{date_unit}")
            Try
                ' die Datei sperren
                oWMObject.LockFor(WMObjectEditModeLifeCycleEdit)
                _logger.Debug(">> object locked")

            Catch ex As Exception
                _logger.Error(ex)
                ' nichts tun (Datei ist bereits gesperrt)
            End Try

            Dim oObjectLifecycle = oWMObject.aWMLifeCycle

            Dim oIntervalType As DateInterval
            If date_unit.ToLower = "d" Or date_unit.ToLower = "day(s)" Then
                oIntervalType = DateInterval.Day
            ElseIf date_unit.ToLower = "m" Or date_unit.ToLower = "month(s)" Then
                oIntervalType = DateInterval.Month
            ElseIf date_unit.ToLower = "y" Or date_unit.ToLower = "year(s)" Then
                oIntervalType = DateInterval.Year
            End If

            Dim oArchUntil = DateAdd(oIntervalType, date_period, dateFrom_value)
            _logger.Debug("New date shall be: " & oArchUntil.ToString)

            oObjectLifecycle.SetPeriodEndDate(2, oArchUntil)
            _logger.Info("Archive end-date has been changed!")
            oWMObject.Save()
            oWMObject.unlock()
            Return SetArchive_Active(oWMObject)

        Catch ex As Exception
            _logger.Warn($"Unexpected Error in NewLifecycle_Period {ex.Message}")
            If Not IsNothing(oWMObject) Then
                If oWMObject.aLocked = True Then
                    oWMObject.unlock()
                End If
            End If
            Return False
        End Try
    End Function
    ''' <summary>
    ''' changes the archive end date
    ''' </summary>
    ''' <param name="wmfilepath">WM Filepath</param>
    ''' <param name="date_period">number/count of period (if </param>
    ''' <param name="date_unit">date_unity (d,m,y or day(s),month(s),years(s)</param>
    ''' <param name="dateFrom_value">dateFrom_value</param>
    ''' <returns>Returns true when date was set, false if not</returns>
    ''' <remarks></remarks>
    Public Function NewLifecycle_PeriodTEST(ByVal wmfilepath As String, ByVal oArchUntil As String)
        Dim oWMObject As WMObject
        Try
            oWMObject = GetFileByPath(wmfilepath)
            _logger.Info($"Changing the archive end-date for file '{oWMObject.aName}', Items: {oArchUntil}")
            Try
                ' die Datei sperren
                oWMObject.LockFor(WMObjectEditModeLifeCycleEdit)
                _logger.Debug(">> object locked")

            Catch ex As Exception
                _logger.Error(ex)
                ' nichts tun (Datei ist bereits gesperrt)
            End Try

            Dim oObjectLifecycle = oWMObject.aWMLifeCycle
            ' Dim oDate = CDate(oArchUntil)
            ' Dim omMyFormattedDate = oDate.ToString("dd.MM.yyyy")

            If oArchUntil <> String.Empty Then
                If IsDate(oArchUntil) Then
                    If CDate(oArchUntil) < CDate(Now) Then
                        _logger.Debug("oArchUntil < today so direct move to archivepool")
                    Else
                        _logger.Debug("New date shall be: " & oArchUntil)
                        oObjectLifecycle.SetPeriodEndDate(2, oArchUntil)
                        _logger.Info("Archive end-date has been changed!")
                    End If
                End If
            Else
                _logger.Debug("oArchUntil is empty so direct move to archivepool")
            End If

            Dim result = SetArchive_Active(oWMObject)
            oWMObject.Save()
            oWMObject.unlock()
            Return result

        Catch ex As Exception
            _logger.Warn($"Unexpected Error in NewLifecycle_PeriodTEST {ex.Message}")
            If Not IsNothing(oWMObject) Then
                If oWMObject.aLocked = True Then
                    oWMObject.unlock()
                End If
            End If
            Return False
        End Try
    End Function
    ''' <summary>
    ''' Archives windream object immediately
    ''' </summary>
    ''' <returns>Returns true when archiving was set, false if not</returns>
    ''' <remarks></remarks>
    Private Function SetArchive_Active(oWMObject As WMObject)
        Try
            oWMObject.MoveToArchivePool()
            _logger.Info("oWMObject has been archived!")
            Return True
        Catch ex As Exception
            _logger.Warn($"Unexpected Error in SetArchive_Active {ex.Message}")
            Return False
        End Try
    End Function

    Public Function NewFolder(Path As String, pExtension As String) As Boolean
        If Not TestSessionLoggedIn() Then
            Return False
        End If

        Try
            Path = GetNormalizedPath(Path)
            Dim oFolders As List(Of String) = Path.Split("\").ToList()
            Dim oFolderObject As WMObject
            Dim oCurrentPath As String = String.Empty


            For Each oFolder In oFolders
                If oFolder.ToString.EndsWith(pExtension) Then
                    Exit For
                End If
                oCurrentPath = Combine(oCurrentPath, oFolder)

                If TestFolderExists(oCurrentPath) = False Then
                    oFolderObject = Session.GetNewWMObjectFS(WMEntityFolder, oCurrentPath, WMObjectEditModeNoEdit)
                    _logger.Info($"new Folder [{oCurrentPath}] has been created!")
                End If
            Next

            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Public Function NewFileVersion(Path As String, Comment As String) As Boolean
        If Not TestSessionLoggedIn() Then
            Return False
        End If

        Try
            Path = GetNormalizedPath(Path)
            Dim oFileObject As IWMObject6
            oFileObject = GetObjectByPath(Path, WMEntityDocument)
            oFileObject.CreateVersion2(False, Constants.HISTORY_NEW_FROM_VERSION, Comment)
            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Public Function NewFileStream(ByVal FilenameSource As String, ByVal FilenameTarget As String) As Boolean
        Dim oExtension As String = Path.GetExtension(FilenameSource)

        If Not TestSessionLoggedIn() Then
            Return False
        End If

        Dim oTargetDrive As String = Path.GetDirectoryName(FilenameTarget)
        FilenameTarget = GetNormalizedPath(FilenameTarget)

        _logger.NewBlock("File Stream")
        _logger.Debug($"Preparing to stream file from {FilenameSource} to {FilenameTarget}")

        Dim oWMObject As IWMObject6 = Nothing
        Dim oFileIO As WMFileIO
        Dim oWMStream As WMStream

        'Indexierungsdialog der Session unterdrücken
        Session.SwitchEvents(Constants.COM_EVENT_SESSION_NEED_INDEX, False)

        Try
            ' GetNewWMObjectFS already locks the WMObject
            _logger.Debug("Creating WMObject for file {0}", FilenameTarget)
            oWMObject = Session.GetNewWMObjectFS(WMEntityDocument, FilenameTarget, WMObjectEditModeObject)
        Catch ex As Exception
            _logger.Error(ex, "WMObject could not be created")
            Return False
        End Try

        If oWMObject Is Nothing Then
            _logger.Warn("Document {0} could not be found", FilenameTarget)
            Return False
        End If

        Try
            _logger.Debug("Opening stream for {0}", FilenameTarget)
            oWMStream = oWMObject.OpenStream(Constants.STREAM_BINARY_OBJECT, Constants.STREAM_OPEN_MODE_READ_WRITE)
        Catch ex As Exception
            _logger.Error(ex)
            If UnlockObject(oWMObject) Then RemoveFile(FilenameTarget)
            Return False
        End Try

        Try
            _logger.Debug("Creating FileIO", FilenameTarget)

            oFileIO = New WMFileIO With {
                .bstrOriginalFileName = FilenameSource,
                .aWMStream = oWMStream
            }
        Catch ex As Exception
            If UnlockObject(oWMObject) Then RemoveFile(FilenameTarget)
            _logger.Error(ex, "Error while creating FileIO object")
            Return False
        End Try

        Try
            _logger.Debug("Streaming file...")
            oFileIO.ImportOriginal(True)
            _logger.Debug("Content of file was transferred!")
        Catch ex As Exception
            If UnlockObject(oWMObject) Then RemoveFile(FilenameTarget)
            _logger.Error(ex, "Error while streaming file")
            Return False
        End Try

        Try
            _logger.Debug("Closing Stream")
            oWMStream.Close()
            _logger.Debug("Saving new object")
            oWMObject.Save()
            _logger.Debug("Unlocking new object")
            oWMObject.unlock()
        Catch ex As Exception
            RemoveFile(FilenameTarget)
            Return False
        End Try

        _logger.Info($"File '{FilenameTarget}' was streamed.")
        _logger.EndBlock()

        Return True
    End Function

    Public Function LockObject(WMObject As WMObject, Optional EditMode As WMObjectEditMode = WMObjectEditModeNoEdit) As Boolean
        Try
            WMObject.LockFor(EditMode)
            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Public Function UnlockObject(WMObject As WMObject) As Boolean
        Try
            WMObject.unlock()
            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Public Function GetNormalizedPath(Path As String) As String
        'Dim oNormalizedPath = GetCleanedPath(Path)
        Dim oNormalizedPath = Language.Utils.RemoveInvalidCharacters(Path)
        _logger.Debug("Normalizing Path: [{0}]", oNormalizedPath)

        Try
            ' Convert any forward slashes / and double slashes \\ into backslashes \
            ' See: https://stackoverflow.com/questions/3144492/how-do-i-get-nets-path-combine-to-convert-forward-slashes-to-backslashes
            If IsPathRooted(oNormalizedPath) Then
                oNormalizedPath = GetFullPath(oNormalizedPath)
            End If

            ' Remove Driveletter, eg. W:\
            If oNormalizedPath.StartsWith($"{ClientDriveLetter}:\") Then
                _logger.Debug($"Replacing ClientDriveLetter: [{ClientDriveLetter}]")
                oNormalizedPath = oNormalizedPath.Substring(ClientDriveLetter.Length + 2)
            End If

            ' Remove Windream Base Path, eg. \\windream\objects\
            If oNormalizedPath.ToLower.StartsWith(ClientBasePath.ToLower) Then
                _logger.Debug($"Replacing ClientBasePath: [{ClientBasePath}]")
                oNormalizedPath = oNormalizedPath.Substring(ClientBasePath.Length)
            End If

            ' Handle misconfigured drive-letter
            If oNormalizedPath.Contains(":") Then
                _logger.Warn($"oNormalizedPath still contains a drive name!!")
                _logger.Warn($"Check Your config ClientDriveLetter [{ClientDriveLetter}] // ClientBasePath [{ClientBasePath}]")
                oNormalizedPath = oNormalizedPath.Substring(3)
            End If

            _logger.Debug($"oNormalizedPath: [{oNormalizedPath}]")

            Return oNormalizedPath
        Catch ex As Exception
            _logger.Warn($"Unexpected error in GetNormalizedPath - oNormalizedPath [{oNormalizedPath}] - Error: [{ex.Message}]")
            Return ""
        End Try
    End Function

    ''' <summary>
    ''' Returns the result of a search file
    ''' </summary>
    ''' <param name="SearchFilePath">Path of a search file (*.wdf)</param>
    ''' <param name="DocIdIndexName">Index containing the Document-ID</param>
    ''' <returns>A datatable of the results with columns PATH and DOCID</returns>
    Public Function GetSearchDocuments(SearchFilePath As String, DocIdIndexName As String) As DataTable
        Dim oDatatable As New DataTable
        oDatatable.Columns.Add("PATH", GetType(String))
        oDatatable.Columns.Add("DOCID", GetType(Integer))

        If TestSessionLoggedIn() = False Then
            Return oDatatable
        End If

        If TestFileExists(SearchFilePath) = False Then
            Return oDatatable
        End If

        Try
            Dim oFileInfo = New FileInfo(SearchFilePath)
            Dim oProfileName = oFileInfo.Name
            Dim oProfilePath = oFileInfo.DirectoryName

            Dim oSearchController As New WMOSearchController()
            oSearchController.CheckSearchProfile(SearchFilePath)

            Dim oSearchType = oSearchController.SearchProfileTargetProgID

            Dim oSearchProfileExSetttings As Integer = oSearchController.SearchProfileExSettings

            If oSearchProfileExSetttings = 0 Then
                oSearchProfileExSetttings = 7
            End If

            Dim oSearch As WMSearch

            Select Case oSearchType.ToUpper()
                Case Constants.SEARCH_TYPE_QUICK_SEARCH
                    Dim oQuickSearch As New WMQuickSearch With {
                        .WMSession = Session,
                        .SearchProfilePath = oProfilePath
                    }
                    oQuickSearch.ClearSearch()
                    oQuickSearch.LoadSearchProfile(oProfileName)

                    oSearch = oQuickSearch.GetSearch()
                Case Constants.SEARCH_TYPE_INDEX_SEARCH
                    Dim oIndexSearch As New WMIndexSearch With {
                        .WMSession = Session,
                        .SearchProfilePath = oProfilePath
                    }
                    oIndexSearch.ClearSearch()
                    oIndexSearch.LoadSearchProfile(oProfileName)

                    oSearch = oIndexSearch.GetSearch()
                Case Constants.SEARCH_TYPE_OBJECTTYPE_SEARCH
                    Dim oObjecttypeSearch As New WMObjectTypeSearch With {
                        .WMSession = Session,
                        .SearchProfilePath = oProfilePath
                    }
                    oObjecttypeSearch.ClearSearch()
                    oObjecttypeSearch.LoadSearchProfile(oProfileName)

                    oSearch = oObjecttypeSearch.GetSearch()
                Case Else
                    _logger.Warn("{0} is not a valid search type", oSearchType)
                    Return oDatatable
            End Select

            Dim oSearchResults As WMObjects = oSearch.Execute()

            If oSearchResults.Count = 0 Then
                Return oDatatable
            End If

            For Each oSearchResult As WMObject In oSearchResults
                Dim path As String = oSearchResult.aPath
                Dim docId As Integer = oSearchResult.GetVariableValue(DocIdIndexName)

                oDatatable.Rows.Add(path, docId)
            Next
            oDatatable.AcceptChanges()

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

    Public Function GetVectorData(FilePath As String, IndexName As String, NewValues As Object, CheckDuplicates As Boolean) As String()
        Try
            Dim oWMObject = GetFileByPath(FilePath)
            Dim oObjectArray As Object() = GetVektorData_Combined(oWMObject, IndexName, NewValues, CheckDuplicates)
            Dim oStringArray As New List(Of String)

            For Each oObjectValue In oObjectArray
                oStringArray.Add(oObjectValue.ToString)
            Next

            Return oStringArray.ToArray
        Catch ex As Exception
            _logger.Error(ex)
            Return Nothing
        End Try
    End Function

    ''' <summary>
    ''' Gets an array of the actual vektorvalues of index, collated with the passed values
    ''' </summary>
    ''' <param name="WindreamObject">windream-file as WMObject</param>
    ''' <param name="IndexName">Indexname as String</param>
    ''' <param name="NewValues">The new values as Array</param>
    ''' <param name="CheckDuplikat">True if duplicates shall be prevented</param>
    ''' <exception cref="Exceptions.SessionException"></exception>
    Public Function GetVektorData_Combined(ByVal WindreamObject As WMObject, IndexName As String, NewValues As Object(), CheckDuplikat As Boolean)
        Try
            Dim oAnzahl As Integer = 0
            Dim oValueArray()
            'Jeden Wert des Vektorfeldes durchlaufen
            Dim oWMValue = WindreamObject.GetVariableValue(IndexName)
            If oWMValue Is Nothing = False Then
                'Nochmals prüfen ob wirklich Array
                If oWMValue.GetType.ToString.Contains("System.Object") Then
                    'Keine Duplikatprüfung also einfach neues Array füllen
                    If CheckDuplikat = False Then
                        For Each ovalue As Object In oWMValue
                            'Das Array anpassen
                            ReDim Preserve oValueArray(oAnzahl)
                            'Den Wert im Array speichern
                            oValueArray(oAnzahl) = ovalue.ToString
                            oAnzahl += 1
                        Next
                        'Und jetzt den/die Neuen Wert(e) anfügen
                        For Each oNewValue As Object In NewValues
                            If oNewValue Is Nothing = False Then
                                'Das Array anpassen
                                ReDim Preserve oValueArray(oAnzahl)
                                'Den Wert im Array speichern
                                oValueArray(oAnzahl) = oNewValue.ToString
                                oAnzahl += 1
                            End If
                        Next
                    Else
                        _logger.Debug("Duplicates shall be checked...")
                        'Duplikat Prüfung an, also nur anhängen wenn Wert <>
                        For Each oValue As Object In oWMValue
                            If oValue Is Nothing = False Then
                                'Erst einmal die ALten Werte schreiben
                                ReDim Preserve oValueArray(oAnzahl)
                                'Den Wert im Array speichern
                                oValueArray(oAnzahl) = oValue.ToString
                                _logger.Debug("Value (" & oAnzahl & ") " & oValue.ToString)
                                oAnzahl += 1
                            End If
                        Next
                        'Jetzt die Neuen Werte auf Duplikate überprüfen
                        For Each NewValue As Object In NewValues
                            If NewValue Is Nothing = False Then
                                If oValueArray.Contains(NewValue) = False Then
                                    _logger.Debug("New Value (" & oAnzahl & ") " & NewValue.ToString)
                                    'Das Array anpassen
                                    ReDim Preserve oValueArray(oAnzahl)
                                    'Den Wert im Array speichern
                                    oValueArray(oAnzahl) = NewValue.ToString
                                    oAnzahl += 1
                                Else
                                    _logger.Debug("Value '" & NewValue.ToString & "' bereits in Vektorfeld enthalten")
                                End If
                            End If
                        Next
                    End If
                End If
            Else
                _logger.Debug("Vektorfeld ist noch leer....")
                'Den/die Neuen Wert(e) anfügen
                For Each oNewValue As Object In NewValues
                    If oNewValue Is Nothing = False Then
                        If CheckDuplikat = True Then
                            If oValueArray Is Nothing = False Then
                                If oValueArray.Contains(oNewValue) = False Then
                                    'Das Array anpassen
                                    ReDim Preserve oValueArray(oAnzahl)
                                    'Den Wert im Array speichern
                                    oValueArray(oAnzahl) = oNewValue.ToString
                                    oAnzahl += 1
                                Else
                                    _logger.Debug("Value '" & oNewValue.ToString & "' bereits in Array enthalten")
                                End If
                            Else 'Dererste Wert, also hinzufügen
                                'Das Array anpassen
                                ReDim Preserve oValueArray(oAnzahl)
                                'Den Wert im Array speichern
                                oValueArray(oAnzahl) = oNewValue.ToString
                                oAnzahl += 1
                            End If
                        Else
                            'Das Array anpassen
                            ReDim Preserve oValueArray(oAnzahl)
                            'Den Wert im Array speichern
                            oValueArray(oAnzahl) = oNewValue.ToString
                            oAnzahl += 1
                        End If
                    End If
                Next
            End If
            _logger.Debug("Return ValueArray: length " & oValueArray.Length)
            Return oValueArray
        Catch ex As Exception
            _logger.Error(ex)
            Return Nothing
        End Try
    End Function

    ''' <summary>
    ''' Sets objecttype of a folder
    ''' </summary>
    ''' <param name="FolderPath"></param>
    ''' <param name="Objecttype"></param>
    ''' <returns></returns>
    Public Function SetFolderObjecttype(FolderPath As String, Objecttype As String) As Boolean
        If TestSessionLoggedIn() = False Then
            Return False
        End If

        Try
            FolderPath = GetNormalizedPath(FolderPath)

            If TestFolderExists(FolderPath) = False Then
                _logger.Warn("Folder {0} does not exist!", FolderPath)
                Return False
            End If

            Dim oWMFolder As WMObject = GetObjectByPath(FolderPath, WMEntityFolder)

            If LockObject(oWMFolder) = False Then
                _logger.Warn("Folder {0} could not be locked", FolderPath)
            End If

            If oWMFolder.aObjectType.aName <> Constants.OBJECT_TYPE_DEFAULT Then
                _logger.Warn("Objecttype for folder {0} has already been set!", FolderPath)
            End If

            Dim oObjecttype As WMObject = GetObjectByName(Objecttype, WMEntityObjectType)

            If oObjecttype Is Nothing Then
                _logger.Warn("Objecttype {0} does not exist!", Objecttype)
                Return False
            End If

            oWMFolder.aObjectType = oObjecttype
            oWMFolder.Save()

            If UnlockObject(oWMFolder) Then
                _logger.Warn("Folder {0} could not be unlocked", FolderPath)
            End If

            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Public Function RemoveFile(Path As String) As Boolean
        If TestSessionLoggedIn() = False Then
            _logger.Warn("TestSession = False!")
            Return Nothing
        End If

        Try
            Dim oWMObject As WMObject = GetFileByPath(Path)

            If oWMObject Is Nothing Then
                _logger.Debug("File so far not existing in WM")
                Return True
            End If
            _logger.Info($"Deleting WMObject [{Path}]")
            oWMObject.Delete()
            _logger.Info($"[RemoveFile] - File [{Path}] has been deleted!")
            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Public Function RemoveVectorIndexValue(Path As String, IndexName As String, ValueToDelete As String) As Boolean
        If TestSessionLoggedIn() = False Then
            Return False
        End If

        Try
            Dim oWMObject As WMObject = Session.GetWMObjectByName(WMEntityAttribute, Path)

            If oWMObject Is Nothing Then
                _logger.Warn("Could not find document {0}", Path)
                Return False
            End If

            Dim oVectorValues = oWMObject.GetVariableValue(IndexName)
            Dim oType As Integer = GetIndexType(IndexName)

            If Helpers.IsVectorIndex(oType) = False Then
                _logger.Warn("Index {0} is not a vector index", IndexName)
                Return False
            End If

            If oVectorValues Is Nothing Then
                _logger.Warn("Could not values of index {0}", IndexName)
                Return False
            End If

            Dim oNewValues As New List(Of Object)
            oNewValues = oVectorValues.Except(New List(Of Object) From {ValueToDelete}).ToList()

            ' BEGIN WRITE INDEX    
            If LockObject(oWMObject, WMObjectEditModeIndexEdit) = False Then
                _logger.Warn("File {0} could not be locked")
                Return False
            End If

            oWMObject.SetVariableValue(IndexName, oNewValues.ToArray())
            oWMObject.Save()

            UnlockObject(oWMObject)

            Return True
            ' END WRITE INDEX
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Public Function SetFileIndex(Path As String, IndexName As String, Value As String, ObjectType As String) As Boolean
        If TestSessionLoggedIn() = False Then
            Return False
        End If

        If TestFileExists(Path) = False Then
            _logger.Warn("File '{0}' does not exist", Path)
            Return False
        End If

        Dim oWMObject As IWMObject6 = GetFileByPath(Path)

        If LockObject(oWMObject, WMObjectEditModeIndexEdit) = False Then
            _logger.Warn("File {0} could not be locked")
            Return False
        End If

        If oWMObject.aObjectType.aName = Constants.OBJECT_TYPE_DEFAULT Then
            oWMObject.aObjectType = GetObjectByName(ObjectType, WMEntityObjectType)
        End If

        Try
            Dim oType As Integer = GetIndexType(IndexName)
            Dim oConvertedValue As Object
            If oType < 3000 Then
                oConvertedValue = Helpers.ConvertIndexValue(oType, Value)
            Else
                oConvertedValue = Helpers.ConvertVectorType(oType, Value)
            End If
            oWMObject.SetVariableValue(IndexName, oConvertedValue)
            oWMObject.Save()

            If UnlockObject(oWMObject) = False Then
                _logger.Warn("File {0} could not be unlocked", Path)
            End If

            Return True
        Catch ex As Exception
            _logger.Error(ex)
            UnlockObject(oWMObject)
            Return False
        End Try
    End Function

    Public Function SetFileIndex(Path As String, IndexName As String, Values As List(Of String), ObjectType As String) As Boolean
        If TestSessionLoggedIn() = False Then
            Return False
        End If

        If TestFileExists(Path) = False Then
            _logger.Warn("File '{0}' does not exist", Path)
            Return False
        End If
        Dim oWMObject As IWMObject6

        Try
            oWMObject = GetFileByPath(Path)
        Catch ex As Exception
            _logger.Warn("Could not create a WMObject for path '{0}'!!", Path)
            _logger.Warn(ex.Message)
            Return False
        End Try
        _logger.Debug("SetFileIndex '{0}' ... ", IndexName)
        If LockObject(oWMObject, WMObjectEditModeIndexEdit) = False Then
            _logger.Warn("File {0} could not be locked")
            Return False
        End If

        If oWMObject.aObjectType.aName = Constants.OBJECT_TYPE_DEFAULT Then
            oWMObject.aObjectType = GetObjectByName(ObjectType, WMEntityObjectType)
        End If

        Try
            Dim oType As Integer = GetIndexType(IndexName)
            Dim oConvertedValues As New List(Of String)
            Dim oArray As Object

            ReDim oArray(Values.Count - 1)

            For oIndex = 0 To Values.Count - 1
                Dim oValue As Object = Helpers.ConvertIndexValue(oType, Values.Item(oIndex))
                oArray(oIndex) = oValue
            Next

            oWMObject.SetVariableValue(IndexName, oArray)
            oWMObject.Save()

            If UnlockObject(oWMObject) = False Then
                _logger.Warn("File {0} could not be unlocked", Path)
            End If

            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Public Function ExportFile(WMObject As WMObject, ExportPath As String) As Boolean
        Try
            Dim oWMObject As IWMObject6 = DirectCast(WMObject, IWMObject6)

            Dim oFilenameFull As String = oWMObject.aName
            Dim oFilenameExport As String
            Dim oSplitIndex = oFilenameFull.LastIndexOf(".")
            Dim oVersion = 1

            Dim oFilename = oFilenameFull.Substring(0, oSplitIndex)
            Dim oExtension = oFilenameFull.Substring(oSplitIndex)

            _logger.Debug("Preparing export of file {0}..", oFilenameFull)
            _logger.Debug("Filename: {0}", oFilename)
            _logger.Debug("Extension: {0}", oExtension)

            ' build the file path in case the exported file doesn't already exist
            oFilenameExport = BuildExportPath(ExportPath, oFilename, oExtension)

            ' Add version until we find the version that does NOT exist
            Do While File.Exists(oFilenameExport)
                oVersion += 1
                oFilenameExport = BuildExportPath(ExportPath, oFilename, oExtension, oVersion)
            Loop

            _logger.Debug("File will be exported to {0}", oFilenameExport)

            _logger.Debug("Opening file stream..")
            Dim oStream As WMStream = oWMObject.OpenStream("BinaryObject", WMObjectStreamOpenMode.WMObjectStreamOpenModeRead)
            Dim oWMFileIO As New WMFileIO() With {
                .aWMStreamEx = oStream,
                .aWMStream = oStream,
                .bstrOriginalFileName = oFilenameExport
            }

            _logger.Debug("Exporting file..")
            oWMFileIO.ExportOriginal(True)

            _logger.Debug("Cleaning up..")
            oStream.Flush()
            oStream.Close()

            _logger.Debug("File exported to {0}", oFilenameExport)
            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Private Function BuildExportPath(BasePath As String, FilenameWithoutExtension As String, Extension As String, Optional Version As Integer = 1)
        Dim oFilename

        If Version = 1 Then
            oFilename = FilenameWithoutExtension & Extension
        Else
            oFilename = FilenameWithoutExtension & "_" & Version & Extension
        End If

        Return Path.Combine(BasePath, oFilename)
    End Function

    Public Function Export_WMFile(WMPath As String, Exportpath As String)
        Try
            If Not Exportpath.EndsWith("\") Then
                Exportpath &= "\"
            End If

            Dim oWMObject As WMObject = GetFileByPath(WMPath)

            _logger.Debug("(Export_WMFile)Working on file: " & oWMObject.aName)


            Dim ExportFileIO = New WMOTOOLLib.WMFileIO ' CreateObject("WMOTOOLLib.WMFileIO") ' New WMOTOOLLib.WMFileIO 
            _logger.Debug("(Export_WMFile)ExportFileIO created...")
            ' Stream Interface bereitstellen
            oWMObject.LockFor(WMObjectEditModeFileSystem)
            Try
                If Not oWMObject.aLocked Then
                    oWMObject.lock()
                End If
            Catch ex As Exception
                _logger.Error(ex)
                Return False
            End Try

            Dim oWMStream = oWMObject.OpenStream("BinaryObject", WMObjectEditModeTypedData)
            '### VERSIONIERUNG ###
            Dim version As Integer = 2
            'Dim Stammname As String = System.IO.Path.GetFileNameWithoutExtension(Quelle)
            Dim Filename = oWMObject.aName.Substring(0, oWMObject.aName.LastIndexOf("."))
            Dim Extension = oWMObject.aName.Substring(oWMObject.aName.LastIndexOf("."))
            Dim tempFilename As String = Exportpath & Filename & Extension
            'Überprüfen ob File existiert
            Do While IO.File.Exists(tempFilename) = True
                tempFilename = Exportpath & Filename & "_" & version & Extension
                version = version + 1
            Loop
            _logger.Debug("Exportfilename is: " & tempFilename)
            ' den Dateiinhalt der neuen Datei zuweisen
            ExportFileIO.aWMStream = oWMStream
            ExportFileIO.bstrOriginalFileName = tempFilename
            'Das eigentliche kopieren
            ExportFileIO.ExportOriginal(True)
            ' close the windream file stream
            oWMStream.Close()
            oWMObject.Save()
            oWMObject.unlock()
            _logger.Info($"WMFile has been exported to {tempFilename} ")

            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function
    Public Function Export_WMFile_DocID(WMPath As String, Exportpath As String, DocId As Integer)
        Try


            If Not Exportpath.EndsWith("\") Then
                Exportpath &= "\"
            End If
            Dim Extension = WMPath.Substring(WMPath.LastIndexOf("."))
            Dim oTempFilename As String = Exportpath & DocId & Extension
            _logger.Info($"(Export_WMFile_DocID)Working on file [{WMPath}] ")

            If IO.File.Exists(oTempFilename) Then
                _logger.Info($"(Export_WMFile_DocID) DocID [{DocId}] already existing!! No action necessary!")
                Return True
            End If

            Dim oWMObject As WMObject



            Try
                oWMObject = GetFileByPath(WMPath)

            Catch ex As Exception
                _logger.Error(ex)
                _logger.Warn("No object created: " & WMPath)
                Return False
            End Try
            Dim ExportFileIO = New WMOTOOLLib.WMFileIO ' CreateObject("WMOTOOLLib.WMFileIO") ' New WMOTOOLLib.WMFileIO 
            _logger.Debug("(Export_WMFile_DocID)ExportFileIO created...")
            Dim oWMStream = oWMObject.OpenStream("BinaryObject", 1)
            '### VERSIONIERUNG ###
            Dim version As Integer = 2

            _logger.Debug($"Checking (FileExists) on [{oTempFilename}]... ")
            'Überprüfen ob File existiert
            Do While IO.File.Exists(oTempFilename) = True
                oTempFilename = Exportpath & DocId & "_" & version & Extension
                version = version + 1
            Loop
            _logger.Debug($"(Export_WMFile_DocID)Exportfilename is [{oTempFilename}] ")
            ' den Dateiinhalt der neuen Datei zuweisen
            ExportFileIO.aWMStream = oWMStream
            ExportFileIO.bstrOriginalFileName = oTempFilename
            'Das eigentliche kopieren
            ExportFileIO.ExportOriginal(True)

            Dim oCounter = 0
            Dim oError As Boolean = False
            Do While IO.File.Exists(oTempFilename) = False
                oCounter += 1
                If oCounter = 30000 Then
                    _logger.Warn($"WMStream took too long...Check the file [{WMPath}]")
                    oError = True
                    Exit Do
                End If
            Loop
            If oError = True Then
                Return False
            End If


            'close the windream file stream
            oWMStream.Close()
            _logger.Info($"WMFile DocID [{DocId}] has been exported to [{oTempFilename}]")
            Return True
        Catch ex As Exception
            _logger.Error(ex)
            _logger.Info("Unexpected error in Export_WMFile: " & ex.Message)
            Return False
        End Try
    End Function
    Public Function VersionWMFilename(pPath As String, pExt As String)
        Return _fileSystem.GetVersionedFilename(pPath)

        'Dim rNewFilepath As String = pPath
        'pPath = GetNormalizedPath(pPath)
        'Dim oPath = pPath.Substring(0, pPath.LastIndexOf("\"))
        'Dim oFilename = pPath.Substring(pPath.LastIndexOf("\") + 1, pPath.Length - pPath.LastIndexOf("\") - 1)
        'Dim oCheck = oFilename
        'Dim oSplit As List(Of String) = oFilename.Split("~").ToList()
        'oFilename = oFilename.Replace(pExt, "")
        'Dim oCount As Integer = 2
        'Do While TestFileExists(rNewFilepath) = True
        '    oFilename = oFilename.Replace(pExt, "")
        '    Dim oVersion = "~" + (oCount - 1).ToString
        '    oFilename = oFilename.Replace(oVersion, "")
        '    oFilename = oFilename & "~" & oCount & pExt
        '    oCount += 1
        '    rNewFilepath = oPath + "\" + oFilename
        'Loop
        'Return rNewFilepath
    End Function
    Public Function TestFolderExists(Path As String) As Boolean
        Return TestObjectExists(GetNormalizedPath(Path), WMEntityFolder)
    End Function

    Public Function TestFileExists(Path As String) As Boolean
        Return TestObjectExists(GetNormalizedPath(Path), WMEntityDocument)
    End Function

    Public Function TestUserExists(Username As String) As Boolean
        Return TestObjectExists(Username, WMEntityUser)
    End Function

    Public Function TestGroupExists(Groupname As String) As Boolean
        Return TestObjectExists(Groupname, WMEntityGroups)
    End Function

    Public Function TestIndexTypeIsVectorIndex(IndexType As Integer) As Boolean
        Return Helpers.IsVectorIndex(IndexType)
    End Function

    Public Function TestIndexNameIsVectorIndex(IndexName As String) As Boolean
        Dim oIndexType As Integer = GetIndexType(IndexName)
        Return Helpers.IsVectorIndex(oIndexType)
    End Function
#End Region

#Region "Private Methods"
    Private Function GetNormalizedBasePath(BasePath As String) As String
        If BasePath.EndsWith("\") Then
            Return BasePath
        Else
            Return BasePath & "\"
        End If
    End Function

    Private Function GetObjectTypes() As WMObjects
        Dim oObjectTypes As WMObjects

        Try
            oObjectTypes = Session.GetWMObjectTypes(WMEntityDocument)
            Return oObjectTypes
        Catch ex As Exception
            _logger.Error(ex)
            Return Nothing
        End Try
    End Function

    Private Function GetObjectByName(ObjectName As String, ObjectType As WMEntity) As WMObject
        If TestSessionLoggedIn() = False Then
            Return Nothing
        End If

        If TestObjectExists(ObjectName, ObjectType) = False Then
            _logger.Warn("GetObjectByName: Object {0} does not exist!", ObjectName)
            Return Nothing
        End If

        Try
            Dim oWMObject As WMObject = Session.GetWMObjectByName(ObjectType, ObjectName)
            Return oWMObject
        Catch ex As Exception
            _logger.Error(ex)
            Return Nothing
        End Try
    End Function

    Private Function GetObjectByPath(ObjectPath As String, ObjectType As WMEntity) As WMObject
        If TestSessionLoggedIn() = False Then
            Return Nothing
        End If

        If TestObjectExists(ObjectPath, ObjectType) = False Then
            _logger.Warn("GetObjectByPath: Object {0} does not exist!", ObjectPath)
            Return Nothing
        End If

        Try
            Dim oNormalizedPath = GetNormalizedPath(ObjectPath)
            Dim oWMObject As WMObject = Session.GetWMObjectByPath(ObjectType, oNormalizedPath)
            Return oWMObject
        Catch ex As Exception
            _logger.Error(ex)
            Return Nothing
        End Try
    End Function

    Private Function TestSessionLoggedIn() As Boolean
        Try
            If Session.aLoggedin Then
                Return True
            Else
                _logger.Warn("There is no active WM-Session for user {0}", _sessionUsername)
                Return False
            End If
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Private Function TestObjectExists(ObjectName As String, ObjectType As WMEntity) As Boolean
        If TestSessionLoggedIn() = False Then
            Return False
        End If
        Try
            Dim oObjectId = 0
            Dim oObjectDbId = 0

            Return Session.WMObjectExists(ObjectType, ObjectName, oObjectId, oObjectDbId)
        Catch ex As Exception
            _logger.Error(ex, "Error while checking existence of WMObject {0} of type {1}", ObjectName, ObjectType.ToString)
            Return False
        End Try
    End Function
#End Region
End Class


