Imports System.IO
Imports Newtonsoft.Json
Imports Pilz.GeneralEventArgs

Public Module ConfigurationSerializer

    Public Event GettingJsonSerializer(instance As Object, e As GetValueEventArgs(Of JsonSerializer))

    Private Function GetJsonSerializer(instance As SimpleConfiguration) As JsonSerializer
        Dim args As New GetValueEventArgs(Of JsonSerializer)(JsonSerializer.CreateDefault)
        RaiseEvent GettingJsonSerializer(instance, args)
        Return args.Value
    End Function

    ''' <summary>
    ''' Writes the given instance to a string and return it.
    ''' </summary>
    ''' <param name="instance">The configuration instance that should be serialized.</param>
    ''' <returns>The content of the configuration instance as string.</returns>
    Public Function WriteToString(instance As SimpleConfiguration) As String
        Dim tw As New StringWriter
        GetJsonSerializer(instance).Serialize(tw, instance)
        Dim txt = tw.ToString
        tw.Close()
        Return txt
    End Function

    ''' <summary>
    ''' Write the given instance to a given stream.
    ''' </summary>
    ''' <param name="instance">The configuration instance that should be serialized.</param>
    ''' <param name="stream">The stream where the content should be written to.</param>
    Public Sub WriteToStream(instance As SimpleConfiguration, stream As Stream)
        Dim sr As New StreamWriter(stream)
        sr.Write(WriteToString(instance))
    End Sub

    ''' <summary>
    ''' Writes the given instance to the given filePath as text file.
    ''' </summary>
    ''' <param name="instance">The configuration instance that should be serialized.</param>
    ''' <param name="filePath">The file path where the content should be written to. The file will be created or overwritten.</param>
    Public Sub WriteToFile(instance As SimpleConfiguration, filePath As String)
        Dim fs As New FileStream(filePath, FileMode.Create, FileAccess.ReadWrite)
        WriteToStream(instance, fs)
        fs.Close()
    End Sub

    ''' <summary>
    ''' Reads a configuratin from the given string and returns an instance of it.
    ''' </summary>
    ''' <typeparam name="T">The type of the configuration class to instance.</typeparam>
    ''' <param name="content">The content of the configuration as string.</param>
    ''' <returns></returns>
    Public Function ReadFromString(Of T As SimpleConfiguration)(content As String) As T
        Dim sr As New StringReader(content)
        Dim instance As T = GetJsonSerializer(Nothing).Deserialize(sr, GetType(T))
        sr.Close()
        Return instance
    End Function

    ''' <summary>
    ''' Read a configuration from the given string and put them to the given instance.
    ''' </summary>
    ''' <param name="instance">The instance to populate with the configuration.</param>
    ''' <param name="content">The content of the configuration as string.</param>
    Public Sub ReadFromString(instance As SimpleConfiguration, content As String)
        Dim sr As New StringReader(content)
        GetJsonSerializer(Nothing).Populate(sr, content)
        sr.Close()
    End Sub

    ''' <summary>
    ''' Reads a configuratin from the given string and returns an instance of it.
    ''' </summary>
    ''' <typeparam name="T">The type of the configuration class to instance.</typeparam>
    ''' <param name="stream">The stream with the content of the configuration.</param>
    ''' <returns></returns>
    Public Function ReadFromStream(Of T As SimpleConfiguration)(stream As Stream) As T
        Return ReadFromString(Of T)(GetContentOfStream(stream))
    End Function

    ''' <summary>
    ''' Read a configuration from the given string and put them to the given instance.
    ''' </summary>
    ''' <param name="instance">The instance to populate with the configuration.</param>
    ''' <param name="stream">The stream with the content of the configuration.</param>
    Public Sub ReadFromStream(instance As SimpleConfiguration, stream As Stream)
        ReadFromString(instance, GetContentOfStream(stream))
    End Sub

    ''' <summary>
    ''' Reads a configuratin from the given string and returns an instance of it.
    ''' </summary>
    ''' <typeparam name="T">The type of the configuration class to instance.</typeparam>
    ''' <param name="filePath">The path to the file with the content of the configuration.</param>
    ''' <returns></returns>
    Public Function ReadFromFile(Of T As SimpleConfiguration)(filePath As String) As T
        Return ReadFromString(Of T)(GetContentOfFile(filePath))
    End Function

    ''' <summary>
    ''' Read a configuration from the given string and put them to the given instance.
    ''' </summary>
    ''' <param name="instance">The instance to populate with the configuration.</param>
    ''' <param name="filePath">The path to the file with the content of the configuration.</param>
    Public Sub ReadFromFile(instance As SimpleConfiguration, filePath As String)
        ReadFromString(instance, GetContentOfFile(filePath))
    End Sub

    Private Function GetContentOfStream(stream As Stream) As String
        Dim sr As New StreamReader(stream)
        Return sr.ReadToEnd
    End Function

    Private Function GetContentOfFile(filePath As String) As String
        Dim fs As New FileStream(filePath, FileMode.Open, FileAccess.Read)
        Dim content = GetContentOfStream(fs)
        fs.Close()
        Return content
    End Function

End Module
