﻿Module RandomPassword

    Private Const NumberOfCharacters As Integer = 18
    Private Const NumberOfPasswords As Integer = 100000
    Private Const DisplayPasswords As Integer = 5
    Private ReadOnly RNG As New Random()


    Sub Main()
        TestPasswords(AddressOf ReadableGenerator, "Readable")
        TestPasswords(AddressOf ConcatenatingGenerator, "Concatenating")
        TestPasswords(AddressOf MemorySaverGenerator, "Memory Saver")
        TestPasswords(AddressOf LinqGenerator, "LINQ")
    End Sub

    Private Sub TestPasswords(ByVal generator As Func(Of String), ByVal name As String)
        Console.WriteLine("{0}:", name)
        Dim sw As Stopwatch = Stopwatch.StartNew()
        Dim passwords(DisplayPasswords - 1) As String
        For i As Integer = 1 To NumberOfPasswords
            passwords(i Mod DisplayPasswords) = generator()
        Next
        sw.Stop()

        For Each password As String In passwords
            Console.WriteLine("    {0}", password)
        Next
        Console.WriteLine("    -- Finished in {0}ms.", sw.ElapsedMilliseconds)
    End Sub

    Private Function ReadableGenerator() As String
        Dim alphabet As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
        Dim password As New Text.StringBuilder(NumberOfCharacters + 1)
        For i As Integer = 1 To NumberOfCharacters
            Dim index As Integer = RNG.Next(0, alphabet.Length)
            password.Append(alphabet(index))
        Next

        Return password.ToString()
    End Function

    Private Function ConcatenatingGenerator() As String
        Dim alphabet As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
        Dim password As String = ""
        For i As Integer = 1 To NumberOfCharacters
            Dim index As Integer = RNG.Next(0, alphabet.Length)
            password &= alphabet(index)
        Next

        Return password.ToString()
    End Function

    Private Function LinqGenerator() As String
        Dim alphabet As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
        Dim password As String = New String((alphabet.OrderBy(Function(c) Guid.NewGuid).Take(NumberOfCharacters)).ToArray())
        Return password
    End Function

    Private Const LowerAValue As Integer = 97
    Private Const UpperAValue As Integer = 65

    Private Function MemorySaverGenerator() As String
        Dim password As New Text.StringBuilder(NumberOfCharacters + 1)
        For i As Integer = 1 To NumberOfCharacters
            Dim index As Integer = RNG.Next(0, 52)
            If index <= 25 Then
                password.Append(Chr(index + LowerAValue))
            Else
                password.Append(Chr(index - 26 + UpperAValue))
            End If
        Next

        Return password.ToString()
    End Function

End Module
