Imports System.ComponentModel
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Base

Public Class ClassInitLoader
    Inherits BaseClass

    Private _Worker As BackgroundWorker
    Private _CurrentStep As InitStep

    Public Steps As New List(Of InitStep)
    Public Event ProgressChanged As EventHandler(Of InitProgress)
    Public Event InitCompleted As EventHandler(Of RunWorkerCompletedEventArgs)

    Public Sub New(LogConfig As LogConfig)
        MyBase.New(LogConfig)
    End Sub

    Public Sub AddStep(Name As String, Action As Action(Of Object), Optional Fatal As Boolean = False)
        Steps.Add(New InitStep() With {
            .Name = Name,
            .Action = Action,
            .Fatal = Fatal
        })
    End Sub

    Public Function Run() As Boolean
        _Worker = New BackgroundWorker With {
            .WorkerReportsProgress = True
        }

        AddHandler _Worker.DoWork, AddressOf DoWork
        AddHandler _Worker.ProgressChanged, Sub(sender As Object, e As ProgressChangedEventArgs)
                                                Dim oProgress As New InitProgress() With {
                                                    .CurrentStep = _CurrentStep,
                                                    .CurrentPercent = e.ProgressPercentage
                                                }
                                                RaiseEvent ProgressChanged(sender, oProgress)
                                            End Sub
        AddHandler _Worker.RunWorkerCompleted, Sub(sender As Object, e As RunWorkerCompletedEventArgs)
                                                   RaiseEvent InitCompleted(sender, e)
                                               End Sub

        _Worker.RunWorkerAsync(My.Application)

        Return True
    End Function

    Private Sub DoWork(sender As Object, e As DoWorkEventArgs)
        Dim oMyApplication As My.MyApplication = DirectCast(e.Argument, My.MyApplication)
        Dim oStepCounter = 0

        For Each oStep In Steps
            _CurrentStep = oStep

            Try
                oStep.Action.Invoke(oMyApplication)

                My.Application.Settings = oMyApplication.Settings
                My.Application.User = oMyApplication.User
                My.Application.Modules = oMyApplication.Modules
                My.Application.ModulesActive = oMyApplication.ModulesActive
                My.Application.ClipboardWatcher = oMyApplication.ClipboardWatcher

            Catch ex As Exception
                Logger.Error(ex)
                Logger.Warn("Init Step '{0}' failed!", oStep.Name)

                If oStep.Fatal Then
                    Logger.Warn("Fatal error in '{0}'. Init will be aborted!", oStep.Name)
                    Throw ex
                End If
            End Try

            oStepCounter += 1

            Dim oPercentComplete As Integer = Math.Truncate(oStepCounter / Steps.Count * 100)
            _Worker.ReportProgress(oPercentComplete)

            Threading.Thread.Sleep(100)
        Next

        e.Result = oMyApplication
    End Sub

    Public Class InitProgress
        Public CurrentStep As InitStep
        Public CurrentPercent As Integer
    End Class

    Public Class InitStep
        ''' <summary>
        ''' Human Readable Name of init step
        ''' </summary>
        Public Name As String
        ''' <summary>
        ''' The function to execute
        ''' </summary>
        Public Action As Action(Of Object)
        ''' <summary>
        ''' Should init be aborted if this step fails?
        ''' </summary>
        Public Fatal As Boolean
    End Class

    Public Class InitException
        Inherits ApplicationException

        Public Sub New(Message As String, InnerException As Exception)
            MyBase.New(Message, InnerException)
        End Sub

        Public Sub New(Message As String)
            MyBase.New(Message)
        End Sub
    End Class
End Class