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

Public Class JobRunner
    Private _LogConfig As LogConfig
    Private _Logger As DigitalData.Modules.Logging.Logger
    Private _firebird As Firebird
    Private _mssql As MSSQLServer

    Private _Props As New NameValueCollection From {
        {"quartz.serializer.type", "binary"},
        {"quartz.threadPool.threadCount", 10}
    }
    Private _factory As StdSchedulerFactory
    Private _scheduler As IScheduler

    Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer, Firebird As Firebird)
        _LogConfig = LogConfig
        _Logger = LogConfig.GetLogger()
        _firebird = Firebird
        _mssql = MSSQL
        Try
            Dim directory As New IO.DirectoryInfo(_LogConfig.LogDirectory)

            For Each file As IO.FileInfo In directory.GetFiles
                If (Now - file.CreationTime).Days > 29 Then
                    file.Delete()
                Else
                    Exit For
                End If


            Next
        Catch ex As Exception

        End Try
    End Sub

    Public Async Sub Start()
        Try
            Logging.LogProvider.SetCurrentLogProvider(New LogProvider(_Logger))

            _Logger.Info("Starting JobRunner")

            Dim oProps As New NameValueCollection From {
                {"quartz.serializer.type", "binary"}
            }
            _factory = New StdSchedulerFactory(oProps)
            _scheduler = Await _factory.GetScheduler()

            _Logger.Info("Starting Scheduler..")
            Await _scheduler.Start()

            ' [START] Job Scheduling
            Await ScheduleJob(Of ADJob)("ADSync", My.Settings.ADSYNC_CONFIG)
            Await ScheduleJob(Of TestJob)("TestJob", My.Settings.TEST_CONFIG)
            Await ScheduleJob(Of GraphQLJob)("GraphQLJob", My.Settings.GRAPHQL_CONFIG)
            ' [END] Job Scheduling

        Catch ex As Exception
            _Logger.Warn("Job Failed.")
            _Logger.Error(ex)
        End Try
    End Sub

    Public Async Function ScheduleJob(Of T As Quartz.IJob)(JobName As String, JobConfigString As String) As Task
        Dim oJobIdentity As String = JobName
        Dim oTriggerIdentity As String = JobName & "-Trigger"
        Dim oJobConfig As JobConfig = JobConfigParser.ParseConfig(JobConfigString)
        Dim oJobData As New JobDataMap From {
            {"LogConfig", _LogConfig},
            {"Firebird", _firebird},
            {"MSSQL", _mssql},
            {"Args", oJobConfig.Arguments}
        }

        Dim oJob = JobBuilder.Create(Of T)().
            WithIdentity(oJobIdentity).
            UsingJobData(oJobData).
            Build()

        Dim oTrigger = TriggerBuilder.Create().
            WithIdentity(oTriggerIdentity).
            StartNow().
            WithCronSchedule(oJobConfig.CronExpression).
            Build()

        If oJobConfig.Enabled Then
            Await _scheduler.ScheduleJob(oJob, oTrigger)

            _Logger.Info("Job {0} scheduled.", JobName)
        Else
            _Logger.Info("Job {0} is disabled.", JobName)
        End If

        ' If StartImmediately is True, start Job after 10 Seconds
        If oJobConfig.StartImmediately Then
            Dim oDebugJob = JobBuilder.Create(Of T)().
                WithIdentity(oJobIdentity & "-DEBUG").
                UsingJobData(oJobData).
                Build()

            Dim oDebugTrigger = TriggerBuilder.Create().
                WithIdentity(oTriggerIdentity & "-DEBUG").
                StartAt(DateBuilder.FutureDate(10, IntervalUnit.Second)).
                Build()

            _Logger.Info("Job {0} will start in 10 Seconds.", JobName)
            Await _scheduler.ScheduleJob(oDebugJob, oDebugTrigger)
        End If
    End Function

    Public Async Sub [Stop]()
        _Logger.Info("Stopping JobRunner")
        Await _scheduler.Shutdown()
    End Sub

    Private Class LogProvider
        Implements ILogProvider

        Private _Logger As Modules.Logging.Logger

        Public Sub New(Logger As DigitalData.Modules.Logging.Logger)
            MyBase.New()
            _Logger = Logger
        End Sub



        Private Function GetLogger(name As String) As Logging.Logger Implements ILogProvider.GetLogger
            Return Function(level, func, exception, parameters)
                       If exception IsNot Nothing Then
                           _Logger.Error(exception)
                       ElseIf level >= LogLevel.Debug AndAlso func IsNot Nothing Then
                           _Logger.Debug(func(), parameters)
                       ElseIf level >= LogLevel.Info AndAlso func IsNot Nothing Then
                           _Logger.Info(func(), parameters)
                       End If

                       Return True
                   End Function
        End Function

        Private Function OpenNestedContext(message As String) As IDisposable Implements ILogProvider.OpenNestedContext
            _Logger.Warn("OpenNestedContext is not implemented")
            Throw New NotImplementedException()
        End Function

        Public Function OpenMappedContext(key As String, value As Object, Optional destructure As Boolean = False) As IDisposable Implements ILogProvider.OpenMappedContext
            _Logger.Warn("OpenMappedContext is not implemented")
            Throw New NotImplementedException()
        End Function
    End Class
End Class
