Imports System.Collections.Specialized
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports Quartz
Imports Quartz.Impl
Imports Quartz.Impl.Matchers
Imports Quartz.Logging

Public Class Scheduler
    Inherits BaseClass

    Private ReadOnly _Factory As StdSchedulerFactory
    Private ReadOnly _MSSQL As MSSQLServer
    Private _Scheduler As IScheduler
    Private ReadOnly _JobListener As JobListener

    Private ReadOnly _Props = New NameValueCollection From {
        {"quartz.serializer.type", "binary"},
        {"quartz.threadPool.maxConcurrency", 1}
    }

    Private Const JOB_GROUP As String = "DatatableJobs"

    Public Sub New(pLogConfig As LogConfig, pMSSQL_Config As MSSQLServer, pTableStore As DataSet)
        MyBase.New(pLogConfig)

        _Factory = New StdSchedulerFactory(_Props)
        _MSSQL = pMSSQL_Config
        _JobListener = New JobListener(pLogConfig, _MSSQL, pTableStore)

        Logging.LogProvider.SetCurrentLogProvider(New LogProvider(Logger))
    End Sub

    Public Async Sub Start()
        ' Get new scheduler
        _Scheduler = Await _Factory.GetScheduler()

        ' configure it
        _Scheduler.ListenerManager.AddJobListener(_JobListener,
                                                  GroupMatcher(Of JobKey).GroupEquals(JOB_GROUP))

        ' start it
        Await _Scheduler.Start()

        Dim oCronjobs As DataTable = Await GetCronJobs()

        Try
            If oCronjobs IsNot Nothing Then
                Logger.Debug("Loaded {0} cron jobs", oCronjobs.Rows.Count)

                For Each oRow As DataRow In oCronjobs.Rows
                    Dim oDefinition As String = oRow.Item("CRON_DEFINITION")
                    Dim oTitle As String = oRow.Item("TITLE")
                    Dim oGuid As Integer = oRow.Item("GUID")

                    Dim oCronTrigger As ITrigger
                    Dim oInitTrigger As ITrigger

                    Dim oJob As IJobDetail
                    Dim oInitJob As IJobDetail

                    Dim oJobData As New JobDataMap From {
                        {"LogConfig", LogConfig},
                        {"MSSQL", _MSSQL},
                        {"CronJobId", oGuid},
                        {"CronJobTitle", oTitle}
                    }

                    Dim oIdentity As String = $"CRON-JOB-{oGuid}"

                    oCronTrigger = TriggerBuilder.Create().
                        WithIdentity(oIdentity & "-TRIGGER", JOB_GROUP).
                        WithCronSchedule(oDefinition).
                        Build()

                    oJob = JobBuilder.Create(Of DatatableJob)().
                        WithIdentity(oIdentity, JOB_GROUP).
                        UsingJobData(oJobData).
                        Build()

                    Await _Scheduler.ScheduleJob(oJob, oCronTrigger)

                    ' Also create variant of the job that runs immediately, once

                    Dim oInitIdentity As String = $"CRON-JOB-INIT-{oGuid}"

                    oInitTrigger = TriggerBuilder.Create().
                        WithIdentity(oInitIdentity & "-TRIGGER", JOB_GROUP).
                        StartNow().
                        Build()

                    oInitJob = JobBuilder.Create(Of DatatableJob)().
                        WithIdentity(oInitIdentity, JOB_GROUP).
                        UsingJobData(oJobData).
                        Build()

                    Await _Scheduler.ScheduleJob(oInitJob, oInitTrigger)

                    Logger.Debug("Scheduled a new job for Cron Job [{0}]", oTitle)
                Next
            Else
                Logger.Warn("CronJobs could not be fetched!")
            End If
        Catch ex As Exception
            Logger.Error(ex)
            Logger.Warn("Unexpected Error while setting up scheduler: " & ex.Message)
        End Try
    End Sub
    Public Async Function GetCronJobs() As Task(Of DataTable)
        Try
            Dim oSQL As String = "SELECT * FROM TBAPPSERV_CRON_JOB WHERE ACTIVE = 1"
            Dim oDatatable As DataTable = Await _MSSQL.GetDatatableAsync(oSQL)

            Return oDatatable
        Catch ex As Exception
            Return Nothing
        End Try
    End Function

    Public Async Function GetCronJobDetails(CronJobId As Integer) As Task(Of DataTable)
        Try
            Dim oSQL As String = $"SELECT * FROM TBAPPSERV_CRON_DETAIL WHERE CRON_ID = {CronJobId}"
            Dim oDatatable As DataTable = Await _MSSQL.GetDatatableAsync(oSQL)

            Return oDatatable
        Catch ex As Exception
            Return Nothing
        End Try
    End Function

    Public Async Sub [Stop]()
        Await _Scheduler.Shutdown()
    End Sub
End Class
