Imports System.Drawing
Imports System.Runtime.CompilerServices
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Windows.Forms
''' <summary>
''' Provides common utility functions that do not require a specific context.
''' </summary>
Public Class Utils
    ''' <summary>
    ''' Generates a random short (8 characters) guid
    ''' </summary>
    ''' <returns>The generated guid as a String</returns>
    Public Shared Function ShortGUID() As String
        Return Guid.NewGuid().ToString().GetHashCode().ToString("x")
    End Function

    ''' <summary>
    ''' Converts a String value to the given Enum
    ''' </summary>
    ''' <typeparam name="T">The Enum Type</typeparam>
    ''' <param name="value">The string value to convert</param>
    Public Shared Function ToEnum(Of T)(value As String) As T
        Return [Enum].Parse(GetType(T), value)
    End Function

    ''' <summary>
    ''' Converts an Integer value to the given Enum
    ''' </summary>
    ''' <typeparam name="T">The Enum Type</typeparam>
    ''' <param name="value">The integer value to convert</param>
    Public Shared Function ToEnum(Of T)(value As Integer) As T
        Return [Enum].ToObject(GetType(T), value)
    End Function

    ''' <summary>
    ''' Converts a Long value to the given Enum
    ''' </summary>
    ''' <typeparam name="T">The Enum Type</typeparam>
    ''' <param name="value">The long value to convert</param>
    Public Shared Function ToEnum(Of T)(value As Long) As T
        Return [Enum].ToObject(GetType(T), value)
    End Function

    Public Shared Function ToBoolean(input As String) As Boolean
        If String.IsNullOrEmpty(input) Then Return False
        Return (input.Trim().ToLower() = "true") OrElse (input.Trim() = "1")
    End Function

    ''' <summary>
    ''' Checks a value for three different `null` values,
    ''' Nothing, Empty String, DBNull
    ''' 
    ''' Returns the original value if the value is not null, or `defaultValue`
    ''' </summary>
    ''' <typeparam name="T">The type of the value</typeparam>
    ''' <param name="value">The value</param>
    ''' <param name="defaultValue">The default Value</param>
    ''' <returns>The original value or the default value</returns>
    Public Shared Function NotNull(Of T)(ByVal value As T, ByVal defaultValue As T) As T
        If IsNothing(value) OrElse String.IsNullOrEmpty(value.ToString) OrElse IsDBNull(value) Then
            Return defaultValue
        Else
            Return value
        End If
    End Function

    ''' <summary>
    ''' Checks a Row value for three different `null` values,
    ''' Nothing, Empty String, DBNull
    ''' 
    ''' Returns the original value if the value is not null, or `defaultValue`
    ''' </summary>
    ''' <typeparam name="T">The type of the value</typeparam>
    ''' <param name="Row">The DataRow that contains the value</param>
    ''' <param name="Column">The column name</param>
    ''' <param name="DefaultValue">The default value</param>
    ''' <returns>The original value or the default value</returns>
    Public Shared Function NotNull(Of T)(ByVal Row As DataRow, Column As String, DefaultValue As T) As T
        Return NotNull(Row.Item(Column), DefaultValue)
    End Function

    ''' <summary>
    ''' Creates a "slug" from text that can be used as part of a valid URL.
    ''' Invalid characters are converted to hyphens. Punctuation that Is
    ''' perfect valid in a URL Is also converted to hyphens to keep the
    ''' result mostly text. Steps are taken to prevent leading, trailing,
    ''' And consecutive hyphens.
    ''' </summary>
    ''' <param name="s">The string to convert</param>
    Public Shared Function ConvertTextToSlug(ByVal s As String) As String
        Dim oBuilder As StringBuilder = New StringBuilder()
        Dim oWasHyphen As Boolean = True

        For Each oChar As Char In s

            If Char.IsLetterOrDigit(oChar) Then
                oBuilder.Append(Char.ToLower(oChar))
                oWasHyphen = False
            ElseIf Char.IsWhiteSpace(oChar) AndAlso Not oWasHyphen Then
                oBuilder.Append("-"c)
                oWasHyphen = True
            End If
        Next

        If oWasHyphen AndAlso oBuilder.Length > 0 Then oBuilder.Length -= 1
        Return oBuilder.ToString()
    End Function

    ''' <summary>
    ''' Removes Invalid characters from a string, suitable for file and path names
    ''' 
    ''' Removed characters are:
    ''' 
    ''' * Illegal File-characters
    ''' * Illegal Path-characters
    ''' * Unicode characters that classify as Emoji
    ''' * All characters above codepoint U+10000
    ''' 
    ''' See: 
    ''' https://stackoverflow.com/questions/46905176/detecting-all-emojis
    ''' https://stackoverflow.com/questions/28023682/how-do-i-remove-emoji-characters-from-a-string
    ''' </summary>
    ''' <returns></returns>
    Public Shared Function RemoveInvalidCharacters(pString As String) As String
        Dim oResult = pString

        Try
            ' Remove all Unicode above Codepoint U+10000
            oResult = Regex.Replace(oResult, InvalidChars.UnicodeSurrogates, String.Empty)

            ' Remove all Emojis (Version 13)
            oResult = Regex.Replace(oResult, InvalidChars.Emojis, String.Empty)

            ' Remove Invalid filename characters
            oResult = Regex.Replace(oResult, InvalidChars.Filenames, String.Empty)

            ' Remove Invalid filename characters
            oResult = Regex.Replace(oResult, InvalidChars.Paths, String.Empty)

            ' Remove Uneccessary characters
            oResult = Regex.Replace(oResult, "\s{2,}", " ")
            oResult = Regex.Replace(oResult, "\.{2,}", ".")

            ' Remove excess space chars
            oResult = oResult.Trim()

            Return oResult
        Catch ex As Exception
            Return oResult
        End Try
    End Function

    Public Shared Function TestContainsInvalidCharacters(pString As String) As Boolean
        Return Not pString.Equals(RemoveInvalidCharacters(pString))
    End Function

    ''' <summary>
    ''' Checks if a point is Visible on any screen
    ''' </summary>
    Public Shared Function IsVisibleOnAnyScreen(Location As Point) As Boolean
        Try
            Dim oRect As New Rectangle(Location, New Size(0, 0))

            For Each oScreen In Screen.AllScreens
                If oScreen.WorkingArea.IntersectsWith(oRect) Then
                    Return True
                End If
            Next

            Return False
        Catch ex As Exception
            Return False
        End Try
    End Function

    ''' <summary>
    ''' Checks if Size is not negative
    ''' </summary>
    Public Shared Function SizeIsVisible(Size As Size) As Boolean
        If Size.Width >= 0 And Size.Height >= 0 Then
            Return True
        End If

        Return False
    End Function

    ''' <summary>
    ''' Checks if Location is not negative
    ''' </summary>
    Public Shared Function LocationIsVisible(Location As Point) As Boolean
        If Location.X >= 0 And Location.Y >= 0 Then
            Return True
        End If

        Return False
    End Function

    Public Shared Function BytesToString(ByteCount As Long) As String
        Dim oSuffixes As New List(Of String) From {"B", "KB", "MB", "GB", "TB", "PB", "EB"}
        If ByteCount = 0 Then
            Return "0" & oSuffixes.First()
        End If
        Dim oBytes = Math.Abs(ByteCount)
        Dim oIndex = Convert.ToInt32(Math.Floor(Math.Log(oBytes, 1024)))
        Dim oNum = Math.Round(oBytes / Math.Pow(1024, oIndex), 1)
        Return (Math.Sign(ByteCount) * oNum).ToString() & oSuffixes.Item(oIndex)
    End Function
End Class
