Imports System.Runtime.CompilerServices
Imports System.Web

Public Module ModuleExtensions
    Public TEMP_DOCUMENT_FOLDER As String = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "Documents")
    Const UnixEraStartTicks As Long = 621355968000000000

    ' ======================================================
    ' === DATETIME
    ' ======================================================

    <Extension()>
    Public Function GetUnixTimestamp(pDate As Date) As Long
        Dim UnixEraTicks = pDate.Ticks - UnixEraStartTicks
        Return UnixEraTicks \ 10000
    End Function

    <Extension()>
    Public Function DateFromUnix(pTimestamp As Long) As Date
        Return New Date(UnixEraStartTicks + pTimestamp * 10000)
    End Function

    ' ======================================================
    ' === LIST
    ' ======================================================

    <Extension()>
    Public Function JoinToString(pList As IEnumerable(Of String), pSeparator As Char)
        Return String.Join(pSeparator, pList)
    End Function

    ' ======================================================
    ' === STRING
    ' ======================================================

    ''' <summary>
    ''' Truncates a string to the specified length if it exceeds that length.
    ''' </summary>
    ''' <param name="pString">The string</param>
    ''' <param name="pLength">The maximum string length</param>
    ''' <returns>The truncated string</returns>
    <Extension()>
    Public Function Truncate(pString As String, pLength As Integer) As String
        If String.IsNullOrEmpty(pString) Then Return pString
        Return pString.Substring(0, Math.Min(pLength, pString.Length))
    End Function

    ''' <summary>
    ''' Replaces single quotes in text for SQL Commands.
    ''' </summary>
    ''' <param name="pString">The string</param>
    ''' <returns>The escaped string.</returns>
    <Extension()>
    Public Function EscapeForSQL(pString As String) As String
        Return ObjectEx.NotNull(pString, String.Empty).Replace("'", "''")
    End Function

    ''' <summary>
    ''' Converts a string to boolean. Accepts true and 1 as truthy values
    ''' </summary>
    ''' <param name="pString">The input string</param>
    ''' <returns>True if input is true or 1, otherwise false.</returns>
    <Extension()>
    Public Function ToBoolean(pString As String) As Boolean
        If String.IsNullOrEmpty(pString) Then Return False
        Return (pString.Trim().ToLower() = "true") OrElse (pString.Trim() = "1")
    End Function

    ''' <summary>
    ''' Checks if a string is null or empty
    ''' </summary>
    ''' <param name="pString">The input string</param>
    ''' <returns>True string is null or empty, otherwise false.</returns>
    <Extension()>
    Public Function IsNullOrEmpty(pString As String) As Boolean
        Return String.IsNullOrEmpty(pString)
    End Function

    ''' <summary>
    ''' Checks if a string is NOT null or empty
    ''' </summary>
    ''' <param name="pString">The input string</param>
    ''' <returns>True string is null or empty, otherwise false.</returns>
    <Extension()>
    Public Function IsNotNullOrEmpty(pString As String) As Boolean
        If String.IsNullOrEmpty(pString) Then
            Return False
        Else
            Return True
        End If
    End Function

    ' ======================================================
    ' === DICTIONARY
    ' ======================================================

    <Extension()>
    Public Function ToURLQueryString(pDictionary As IDictionary(Of String, String)) As String
        Dim oQueryString = HttpUtility.ParseQueryString(String.Empty)

        For Each oItem As KeyValuePair(Of String, String) In pDictionary
            oQueryString.Add(oItem.Key, oItem.Value)
        Next

        Return oQueryString.ToString()
    End Function

    ' ======================================================
    ' === DATATABLE
    ' ======================================================

    <Extension()>
    Public Function ItemEx(Of T)(pRow As DataRow, pFieldName As String, Optional pDefaultValue As T = Nothing) As T
        Try
            If TableContainsColumn(pRow.Table, pFieldName) = False Then Return pDefaultValue
            Return ObjectEx.NotNull(pRow.Item(pFieldName), pDefaultValue)
        Catch ex As Exception
            Return Nothing
        End Try
    End Function

    <Extension()>
    Public Function ItemEx(Of T)(pRow As DataRow, pFieldIndex As Integer, Optional pDefaultValue As T = Nothing) As T
        Try
            If TableContainsColumn(pRow.Table, pFieldIndex) = False Then Return pDefaultValue
            Return ObjectEx.NotNull(pRow.Item(pFieldIndex), pDefaultValue)
        Catch ex As Exception
            Return Nothing
        End Try
    End Function

    <Extension()>
    Public Function FieldOrDefault(Of T)(pRow As DataRow, pFieldName As String, Optional pDefaultValue As T = Nothing) As T
        Return ItemEx(pRow, pFieldName, pDefaultValue)
    End Function

    <Extension()>
    Public Function FieldOrDefault(Of T)(pRow As DataRow, pFieldIndex As Integer, Optional pDefaultValue As T = Nothing) As T
        Return ItemEx(pRow, pFieldIndex, pDefaultValue)
    End Function

    <Extension()>
    Public Function First(pTable As DataTable) As DataRow
        Try
            If pTable Is Nothing OrElse pTable.Rows.Count = 0 Then
                Return Nothing
            End If
            Return pTable.Rows.Item(0)
        Catch ex As Exception
            Return Nothing
        End Try
    End Function

    Private Function TableContainsColumn(pTable As DataTable, pColumnName As String) As Boolean
        Try
            If pTable Is Nothing Then Return False
            If String.IsNullOrEmpty(pColumnName) Then Return False

            Return pTable.Columns.Contains(pColumnName)
        Catch ex As Exception
            Return False
        End Try
    End Function

    Private Function TableContainsColumn(pTable As DataTable, pColumnIndex As Integer) As Boolean
        Try
            If pTable Is Nothing Then Return False
            If String.IsNullOrEmpty(pColumnIndex) Then Return False

            Return pTable.Columns.Count > pColumnIndex
        Catch ex As Exception
            Return False
        End Try
    End Function
End Module
