Imports System.Data.SqlClient
Imports DigitalData.Modules.Base.IDB
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Database.MSSQLServer.TransactionMode
Imports DigitalData.Modules.Logging

Namespace Methods.IDB.CheckInOutFile
    Public Class CheckInOutFileMethod
        Inherits BaseMethod

        Private Enum CheckOutResult
            CheckoutSuccessful
            AlreadyCheckedOut
            InternalError
        End Enum

        Private Enum CheckInResult
            CheckinSuccessful
            NotCheckedOut
            InternalError
        End Enum

        Private ReadOnly Connection As SqlConnection
        Private ReadOnly Transaction As SqlTransaction

        Public Sub New(pLogConfig As LogConfig, pDatabaseIDB As MSSQLServer, pDatabaseECM As MSSQLServer, pGlobalState As GlobalState)
            MyBase.New(pLogConfig, pDatabaseIDB, pDatabaseECM, pGlobalState)

            Connection = DatabaseIDB.GetConnection()
            Transaction = Connection.BeginTransaction()
        End Sub

        Public Function Run(pData As CheckInOutFileRequest) As CheckInOutFileResponse
            Try
                Dim oResult = False

                If pData.Action = CheckInOutFileAction.CheckOut Then
                    Select Case CheckOutFile(pData.ObjectId, pData.User.UserName, pData.Comment)
                        Case CheckOutResult.CheckoutSuccessful
                            oResult = True

                        Case CheckOutResult.AlreadyCheckedOut
                            LogAndThrow($"File '{pData.ObjectId}' is already checked out.")

                        Case CheckOutResult.InternalError
                            LogAndThrow($"Internal Error occurred while checking out file [{pData.ObjectId}].")

                    End Select

                ElseIf pData.Action = CheckInOutFileAction.CheckIn Then
                    Select Case CheckInFile(pData.ObjectId, pData.User.UserName)
                        Case CheckInResult.CheckinSuccessful
                            oResult = True

                        Case CheckInResult.NotCheckedOut
                            LogAndThrow($"File '{pData.ObjectId}' is not checked out.")

                        Case CheckInResult.InternalError
                            LogAndThrow($"Internal Error occurred while checking in file [{pData.ObjectId}].")

                    End Select

                Else
                    LogAndThrow("Invalid action supplied!")

                End If

                If oResult = False Then
                    LogAndThrow($"Could not Check In/Out file [{pData.ObjectId}]!")
                End If

                Return New CheckInOutFileResponse(pData.ObjectId)
            Catch ex As Exception
                Logger.Warn("Error occurred while checkin in/out file!")
                Logger.Error(ex)

                Logger.Info("Rolling back transaction.")
                Transaction?.Rollback()

                Return New CheckInOutFileResponse(ex)

            End Try
        End Function

        Private Function CheckOutFile(pObjectId As Long, pUsername As String, pComment As String) As CheckOutResult
            Try
                Dim oTable = TestFileIsCheckedOut(pObjectId)
                If oTable Is Nothing Then
                    Logger.Warn("File [{0}] could not be checked out because of an internal error!", pObjectId)
                    Return CheckOutResult.InternalError
                End If

                ' If there are rows, the file is already checked out (either by the calling user or somebody else)
                If oTable.Rows.Count > 0 Then
                    ' TODO: Return the person who has this file checked out
                    Logger.Warn("File [{0}] is already checked out!", pObjectId)
                    Return CheckOutResult.AlreadyCheckedOut
                End If

                Dim oSQL = $"INSERT INTO TBIDB_OBJECT_CHECK_IN_OUT (IDB_OBJ_ID, CHECKED_OUT_WHEN, COMMENT, ADDED_WHO) 
                        VALUES ({pObjectId}, GETDATE(), '{pComment}', '{pUsername}')"

                If DatabaseIDB.ExecuteNonQuery(oSQL) = True Then
                    Helpers.SetObjectState(pObjectId, FileStore.OBJECT_STATE_FILE_CHECKED_OUT, pUsername)
                    Logger.Info("File [{0}] checked out successfully!", pObjectId)

                    Return CheckOutResult.CheckoutSuccessful
                Else
                    Logger.Warn("File [{0}] could not be checked out because of an internal error!", pObjectId)
                    Return CheckOutResult.InternalError
                End If

            Catch ex As Exception
                Logger.Error(ex)
                Return False

            End Try
        End Function

        Private Function CheckInFile(pObjectId As Long, pUsername As String) As Boolean
            Try
                Dim oTable = TestFileIsCheckedOut(pObjectId)
                If oTable Is Nothing Then
                    Logger.Warn("File [{0}] could not be checked in because of an internal error!", pObjectId)
                    Return CheckOutResult.InternalError
                End If

                ' If there are no rows, the file is not checked out
                If oTable.Rows.Count = 0 Then
                    Logger.Warn("File [{0}] is not checked out!", pObjectId)
                    Return CheckInResult.NotCheckedOut
                End If

                Dim oSQL = $"UPDATE TBIDB_OBJECT_CHECK_IN_OUT 
                        SET CHECKED_IN_WHEN = GETDATE(), CHANGED_WHO = '{pUsername}'
                        WHERE IDB_OBJ_ID = {pObjectId} AND ADDED_WHO = '{pUsername}' AND CHECKED_IN_WHEN IS NULL"

                If DatabaseIDB.ExecuteNonQuery(oSQL) = True Then
                    Helpers.SetObjectState(pObjectId, FileStore.OBJECT_STATE_FILE_CHECKED_IN, pUsername)
                    Logger.Info("File [{0}] checked in successfully!", pObjectId)

                    Return CheckInResult.CheckinSuccessful
                Else
                    Logger.Warn("File [{0}] could not be checked in because of an internal error!", pObjectId)
                    Return CheckInResult.InternalError
                End If

            Catch ex As Exception
                Logger.Error(ex)
                Return False

            End Try
        End Function

        Private Function TestFileIsCheckedOut(pObjectId As Long) As DataTable
            Try
                Logger.Debug("Checking if file [{0}] is checked out.", pObjectId)
                Dim oSqlCheck = $"SELECT * FROM TBIDB_OBJECT_CHECK_IN_OUT WHERE IDB_OBJ_ID = {pObjectId} AND CHECKED_IN_WHEN IS NULL"
                Dim oTable As DataTable = DatabaseIDB.GetDatatable(oSqlCheck)

                Return oTable
            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing

            End Try
        End Function


    End Class

End Namespace