Imports DigitalData.Modules.Database
Imports DigitalData.Modules.EDMI.API
Imports DigitalData.Modules.EDMI.API.Constants
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language.Utils

Public Class DatabaseWithFallback
    Private ReadOnly _Logger As Logger
    Private ReadOnly _Client As Client
    Private ReadOnly _DatabaseEDM As MSSQLServer
    Private ReadOnly _DatabaseIDB As MSSQLServer

    ''' <summary>
    ''' Options for GetDatatable
    ''' </summary>
    Public Class GetDatatableOptions
        Public ReadOnly FallbackSQL
        Public ReadOnly FallbackType

        ''' <summary>
        ''' Filter expression for the cached Datatable
        ''' </summary>
        Public Property FilterExpression As String = ""
        ''' <summary>
        ''' Columns to sort the cached Datatable by
        ''' </summary>
        Public Property SortByColumn As String = ""
        ''' <summary>
        ''' Force the fallback, skipping the service completely
        ''' </summary>
        Public Property ForceFallback As Boolean = False
        ''' <summary>
        ''' Connection Id to use, references TBDD_CONNECTION
        ''' </summary>
        Public Property ConnectionId As Integer = 0

        ''' <summary>
        ''' Creates a new options object for GetDatatable options
        ''' </summary>
        ''' <param name="pFallbackSQL">SQL Command to execute as fallback</param>
        ''' <param name="pFallbackType">Named Database to use for the fallback SQL Command</param>
        Public Sub New(pFallbackSQL As String, pFallbackType As Constants.DatabaseType)
            FallbackSQL = pFallbackSQL
            FallbackType = pFallbackType
        End Sub
    End Class

    Public Sub New(LogConfig As LogConfig, Client As Client, DatabaseECM As MSSQLServer, DatabaseIDB As MSSQLServer)
        _Logger = LogConfig.GetLogger()
        _Client = Client
        _DatabaseEDM = DatabaseECM
        _DatabaseIDB = DatabaseIDB
    End Sub

    ''' <summary>
    ''' Returns a Datatable by trying to fetch a cached version from the service, then querying the database through the service and querying the database directly as fallback. 
    ''' </summary>
    ''' <param name="pDataTableName">Name of the Cached Datatable</param>
    ''' <param name="pOptions">Options object</param>
    Public Function GetDatatable(pDataTableName As String, pOptions As GetDatatableOptions) As DataTable
        Return GetDatatable(pDataTableName, pOptions.FallbackSQL, pOptions.FallbackType, pOptions.FilterExpression, pOptions.SortByColumn, pOptions.ForceFallback, pOptions.ConnectionId)
    End Function

    ''' <summary>
    ''' Returns a datatable directly from the database.
    ''' </summary>
    ''' <param name="pOptions">Options object</param>
    Public Function GetDatatable(pOptions As GetDatatableOptions) As DataTable
        Dim oForceFallback = True
        Return GetDatatable("FORCE_FALLBACK", pOptions.FallbackSQL, pOptions.FallbackType, pOptions.FilterExpression, pOptions.SortByColumn, oForceFallback, pOptions.ConnectionId)
    End Function

    ''' <summary>
    ''' Returns a Datatable by trying to fetch a cached version from the service, then querying the database through the service and querying the database directly as fallback.
    ''' </summary>
    ''' <param name="pDataTableName">Name of the Cached Datatable</param>
    ''' <param name="pFallbackSQL">SQL Command to execute as fallback</param>
    ''' <param name="pFallbackType">Named Database to use for the fallback SQL Command</param>
    ''' <param name="pFilterExpression">Filter expression for the cached Datatable</param>
    ''' <param name="pSortByColumn">Columns to sort the cached Datatable by</param>
    ''' <param name="pForceFallback">Force the fallback, skipping the service completely</param>
    ''' <param name="pConnectionId">Connection Id to use, references TBDD_CONNECTION</param>
    Public Function GetDatatable(pDataTableName As String, pFallbackSQL As String, pFallbackType As Constants.DatabaseType, Optional pFilterExpression As String = "", Optional pSortByColumn As String = "", Optional pForceFallback As Boolean = False, Optional pConnectionId As Integer = 0) As DataTable
        Try
            Dim oResult As DataTable = Nothing
            Dim oTableResult As TableResult = Nothing

            ' If there is no client, we assume there is no service (configured)
            If _Client Is Nothing Then
                Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
            End If

            ' If ForceFallback flag is set, we go to database immediately
            If pForceFallback Then
                Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
            End If

            ' If the table is not cached, we go to database immediately
            If Not IsTableCached(pDataTableName) Then
                Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
            End If

            ' If there is a proper ConnectionId, we go to database immediately
            If pConnectionId > 0 Then
                Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
            End If

            Try
                oTableResult = _Client.GetDatatableByName(pDataTableName, pFilterExpression, pSortByColumn)
            Catch ex As Exception
                _Logger.Error(ex)
                oTableResult = Nothing
            End Try

            If oTableResult Is Nothing OrElse oTableResult.OK = False Then
                _Logger.Warn("Datatable [{0}] could not be fetched from AppServer Cache. Falling back to direct Database Access.", pDataTableName)
                Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
            Else
                Return oTableResult.Table
            End If

        Catch ex As Exception
            _Logger.Error(ex)
            Return Nothing

        End Try
    End Function

    Private Function IsTableCached(pName As String) As Boolean
        If _Client Is Nothing Then
            Return False
        End If

        Return _Client.CachedTables.Contains(pName.ToUpper)
    End Function

    Private Function GetDatatableFromDatabase(SQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer)
        Try
            Select Case DatabaseType
                Case Constants.DatabaseType.ECM
                    Return _DatabaseEDM.GetDatatable(SQLCommand)

                Case Constants.DatabaseType.IDB
                    Return _DatabaseIDB.GetDatatable(SQLCommand)

                Case Else
                    Return Nothing

            End Select
        Catch ex As Exception
            _Logger.Error(ex)
            Return Nothing

        End Try
    End Function
End Class

