﻿Imports System.IO
Imports System.Collections.Generic
Imports System.Net
Imports System.Text
Imports System.Web


Public Class srFax

    Private access_id As String
    Private access_pwd As String
    Private serverUrl As String = "https://secure.srfax.com/SRF_SecWebSvc.php"

    Private lastStatus As Boolean
    Private lastResponse As String

    Public Sub New(id As String, pwd As String)
        access_id = id
        access_pwd = pwd
    End Sub


    Public Function Queue_Fax(parameters As Dictionary(Of String, String)) As Boolean
        Dim requiredFields As String() = {"sCallerID", "sSenderEmail", "sFaxType", "sToFaxNumber"}
        Dim optionalFields As String() = {"sResponseFormat", "sAccountCode", "sRetries", "sCoverPage", "sCPFromName", "sCPToName",
            "sCPOrganization", "sCPSubject", "sCPComments", "sFileName_*", "sFileContent_*", "sNotifyURL",
            "sFaxFromHeader", "sQueueFaxDate", "sQueueFaxTime"}

        _validateRequiredVariables(requiredFields, parameters)

        Dim postVariables As Dictionary(Of String, String) = _preparePostVariables(requiredFields, optionalFields, parameters)

        postVariables.Add("action", "Queue_Fax")
        postVariables.Add("access_id", access_id)
        postVariables.Add("access_pwd", access_pwd)

        Dim result As String = _processRequest(postVariables)

        _processResponse(result)

        Return lastStatus

    End Function

    Public Function Get_FaxStatus(parameters As Dictionary(Of String, String)) As Boolean
        Dim requiredFields As String() = {"sFaxDetailsID"}
        Dim optionalFields As String() = {"sResponseFormat"}

        _validateRequiredVariables(requiredFields, parameters)

        Dim postVariables As Dictionary(Of String, String) = _preparePostVariables(requiredFields, optionalFields, parameters)

        postVariables.Add("action", "Get_FaxStatus")
        postVariables.Add("access_id", access_id)
        postVariables.Add("access_pwd", access_pwd)

        Dim result As String = _processRequest(postVariables)

        _processResponse(result)

        Return lastStatus
    End Function

    Public Function Get_MultiFaxStatus(parameters As Dictionary(Of String, String)) As Boolean
        Dim requiredFields As String() = {"sFaxDetailsID"}
        Dim optionalFields As String() = {"sResponseFormat"}

        _validateRequiredVariables(requiredFields, parameters)

        Dim postVariables As Dictionary(Of String, String) = _preparePostVariables(requiredFields, optionalFields, parameters)

        postVariables.Add("action", "Get_MultiFaxStatus")
        postVariables.Add("access_id", access_id)
        postVariables.Add("access_pwd", access_pwd)

        Dim result As String = _processRequest(postVariables)

        _processResponse(result)

        Return lastStatus
    End Function


    Public Function Get_Fax_Inbox(parameters As Dictionary(Of String, String)) As Boolean

        Dim requiredFields As String() = {}
        Dim optionalFields As String() = {"sResponseFormat", "sPeriod", "sStartDate", "sEndDate", "sViewedStatus", "sIncludeSubUsers",
            "sFaxDetailsID"}


        Dim postVariables As Dictionary(Of String, String) = _preparePostVariables(requiredFields, optionalFields, parameters)

        postVariables.Add("action", "Get_Fax_Inbox")
        postVariables.Add("access_id", access_id)
        postVariables.Add("access_pwd", access_pwd)

        Dim result As String = _processRequest(postVariables)

        _processResponse(result)

        Return lastStatus

    End Function

    Public Function Get_Fax_Outbox(parameters As Dictionary(Of String, String)) As Boolean

        Dim requiredFields As String() = {}
        Dim optionalFields As String() = {"sResponseFormat", "sPeriod", "sStartDate", "sEndDate", "sIncludeSubUsers", "sFaxDetailsID"}


        Dim postVariables As Dictionary(Of String, String) = _preparePostVariables(requiredFields, optionalFields, parameters)

        postVariables.Add("action", "Get_Fax_Outbox")
        postVariables.Add("access_id", access_id)
        postVariables.Add("access_pwd", access_pwd)

        Dim result As String = _processRequest(postVariables)

        _processResponse(result)

        Return lastStatus

    End Function

    Public Function Retrieve_Fax(parameters As Dictionary(Of String, String)) As Boolean
        Dim requiredFields As String() = {"sFaxFileName|sFaxDetailsID", "sDirection"}
        Dim optionalFields As String() = {"sFaxFormat", "sMarkasViewed", "sResponseFormat", "sSubUserID"}

        _validateRequiredVariables(requiredFields, parameters)

        Dim postVariables As Dictionary(Of String, String) = _preparePostVariables(requiredFields, optionalFields, parameters)

        postVariables.Add("action", "Retrieve_Fax")
        postVariables.Add("access_id", access_id)
        postVariables.Add("access_pwd", access_pwd)

        Dim result As String = _processRequest(postVariables)

        _processResponse(result)

        Return lastStatus
    End Function

    Public Function Update_Viewed_Status(parameters As Dictionary(Of String, String)) As Boolean
        Dim requiredFields As String() = {"sFaxFileName|sFaxDetailsID", "sDirection", "sMarkasViewed"}
        Dim optionalFields As String() = {"sResponseFormat"}

        _validateRequiredVariables(requiredFields, parameters)

        Dim postVariables As Dictionary(Of String, String) = _preparePostVariables(requiredFields, optionalFields, parameters)

        postVariables.Add("action", "Update_Viewed_Status")
        postVariables.Add("access_id", access_id)
        postVariables.Add("access_pwd", access_pwd)

        Dim result As String = _processRequest(postVariables)

        _processResponse(result)

        Return lastStatus

    End Function

    Public Function Delete_Fax(parameters As Dictionary(Of String, String)) As Boolean
        Dim requiredFields As String() = {"sDirection", "sFaxFileName_*|sFaxDetailsID_*"}
        Dim optionalFields As String() = {"sResponseFormat"}

        _validateRequiredVariables(requiredFields, parameters)

        Dim postVariables As Dictionary(Of String, String) = _preparePostVariables(requiredFields, optionalFields, parameters)

        postVariables.Add("action", "Delete_Fax")
        postVariables.Add("access_id", access_id)
        postVariables.Add("access_pwd", access_pwd)

        Dim result As String = _processRequest(postVariables)

        _processResponse(result)

        Return lastStatus

    End Function

    Public Function Stop_Fax(parameters As Dictionary(Of String, String)) As Boolean
        Dim requiredFields As String() = {"sFaxDetailsID"}
        Dim optionalFields As String() = {"sResponseFormat"}

        _validateRequiredVariables(requiredFields, parameters)

        Dim postVariables As Dictionary(Of String, String) = _preparePostVariables(requiredFields, optionalFields, parameters)

        postVariables.Add("action", "Stop_Fax")
        postVariables.Add("access_id", access_id)
        postVariables.Add("access_pwd", access_pwd)

        Dim result As String = _processRequest(postVariables)

        _processResponse(result)

        Return lastStatus

    End Function

    Public Function Get_Fax_Usage(parameters As Dictionary(Of String, String)) As Boolean
        Dim requiredFields As String() = {}
        Dim optionalFields As String() = {"sResponseFormat", "sPeriod", "sStartDate", "sEndDate", "sIncludeSubUsers"}

        _validateRequiredVariables(requiredFields, parameters)

        Dim postVariables As Dictionary(Of String, String) = _preparePostVariables(requiredFields, optionalFields, parameters)

        postVariables.Add("action", "Get_Fax_Usage")
        postVariables.Add("access_id", access_id)
        postVariables.Add("access_pwd", access_pwd)

        Dim result As String = _processRequest(postVariables)

        _processResponse(result)

        Return lastStatus

    End Function

    Public Function Get_Last_Response() As String
        Return lastResponse
    End Function

    Public Function Get_Last_Status() As Boolean
        Return lastStatus
    End Function

    '******************INTERNAL FUNCTIONS********************************



    Private Sub _processResponse(response As String)
        If response.IndexOf("Success") <> -1 Then
            lastStatus = True
        Else
            lastStatus = False
        End If

        lastResponse = response

        Return

    End Sub

    Private Function _processRequest(postVariables As Dictionary(Of String, String)) As String
        Dim queryString As String = _prepareQueryString(postVariables)
        Dim result As String = ""

        System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

        Using wc As New WebClient()
            wc.Headers(HttpRequestHeader.ContentType) = "application/x-www-form-urlencoded"
            result = wc.UploadString(serverUrl, queryString)
        End Using

        Return result
    End Function


    Private Function _prepareQueryString(postVariables As Dictionary(Of String, String)) As String
        Dim queryString As String = ""

        For Each entry As KeyValuePair(Of String, String) In postVariables
            queryString += (Convert.ToString(entry.Key.ToString() + "=") & UrlEncode(entry.Value.ToString())) + "&"
        Next

        ' remove last &
        queryString = queryString.Remove(queryString.Length - 1)

        Return queryString

    End Function

    Public Shared Function UrlEncode(str As String) As String


        Dim sb As New StringBuilder()

        Dim byStr As Byte() = System.Text.Encoding.UTF8.GetBytes(str)

        For i As Integer = 0 To byStr.Length - 1



            sb.Append("%" + byStr(i).ToString("X2"))
        Next

        Return (sb.ToString())

    End Function

    Private Function _preparePostVariables(requiredFields As String(), optionalFields As String(), parameters As Dictionary(Of String, String)) As Dictionary(Of String, String)
        Dim postVariables As New Dictionary(Of String, String)()

        Dim list As New List(Of String)()
        list.AddRange(requiredFields)
        list.AddRange(optionalFields)

        Dim inputVariables As String() = list.ToArray()


        For Each field As String In inputVariables
            If field.EndsWith("*") AndAlso field.IndexOf("|"c) = -1 Then
                ' non-piped wildcard
                Dim fieldPrefix As String = field.Replace("*", "")
                Dim wildCards As Dictionary(Of String, String) = _getWildcardVaribles(fieldPrefix, parameters)

                postVariables = _mergeDictionaries(postVariables, wildCards)
            Else
                If field.IndexOf("|"c) <> -1 Then
                    ' piped, non-wildcard
                    Dim pipedFields As String() = field.Split("|"c)

                    For Each pipedField As String In pipedFields
                        If pipedField.EndsWith("*") Then
                            ' piped wildcard
                            Dim fieldPrefix As String = pipedField.Replace("*", "")
                            Dim wildCards As Dictionary(Of String, String) = _getWildcardVaribles(fieldPrefix, parameters)
                            postVariables = _mergeDictionaries(postVariables, wildCards)
                        Else
                            If parameters.ContainsKey(pipedField) Then
                                Dim value As String = parameters(pipedField)
                                If value.Length > 0 Then
                                    postVariables.Add(pipedField, value)
                                End If
                            End If
                        End If


                    Next
                Else
                    'non-special fieldname
                    If parameters.ContainsKey(field) Then
                        postVariables.Add(field, parameters(field))
                    End If
                End If

            End If
        Next


        Return postVariables
    End Function


    Private Function _getWildcardVaribles(fieldPrefix As String, parameters As Dictionary(Of String, String)) As Dictionary(Of String, String)
        Dim wildCards As New Dictionary(Of String, String)()
        Dim done As Boolean = False
        Dim suffix As Integer = 1

        While Not done
            Dim field As String = fieldPrefix & suffix

            If parameters.ContainsKey(field) Then
                Dim value As String = parameters(field)

                If value.Length > 0 Then
                    ' add variable to the collection
                    wildCards.Add(field, value)
                Else
                    ' field value is empty, so finish
                    done = True
                End If
            Else
                done = True
            End If

            suffix += 1

            ' fail safe to ensure no infinite loops
            If suffix > 1000 Then
                done = True

            End If
        End While

        Return wildCards

    End Function

    Private Sub _validateRequiredVariables(requiredVariables As String(), parameters As Dictionary(Of String, String))

        For Each field As String In requiredVariables

            Dim [error] As String = ""

            If field.EndsWith("*") AndAlso field.IndexOf("|") = -1 Then
                ' non piped wildcard variable.  check for first instance
                Dim fieldPrefix As String = field.Replace("*", "")
                Dim wildCard__1 As String = fieldPrefix & Convert.ToString("1")

                If Not parameters.ContainsKey(wildCard__1) Then
                    [error] = Convert.ToString("Required Field missing.  No values for ") & fieldPrefix
                Else
                    Dim value As String = parameters(wildCard__1)
                    If value.Length <= 0 Then
                        [error] = Convert.ToString("Required Field missing.  No values for ") & fieldPrefix
                    End If


                End If
            Else

                If field.IndexOf("|") <> -1 Then
                    ' piped separated variable.  At lease 1 must be present.
                    Dim pipedFields As String() = field.Split("|"c)
                    Dim checkSuccessful As Boolean = False

                    For Each pipedField As String In pipedFields
                        Dim trimmedPipedField As String = pipedField.Trim()

                        If trimmedPipedField.EndsWith("*") Then
                            ' piped value has a wildcard, look for first value
                            Dim prefix As String = trimmedPipedField.Replace("*", "")
                            Dim wildcard__2 As String = prefix & Convert.ToString("1")

                            If parameters.ContainsKey(wildcard__2) Then
                                ' parameter exists, check to make sure it has a value
                                Dim pVal As String = parameters(wildcard__2)
                                If pVal.Length > 0 Then
                                    checkSuccessful = True

                                End If

                            End If
                        Else
                            If parameters.ContainsKey(trimmedPipedField) Then
                                Dim pVal As String = parameters(trimmedPipedField)
                                If pVal.Length > 0 Then
                                    checkSuccessful = True
                                End If
                            End If
                        End If
                    Next

                    If Not checkSuccessful Then

                        [error] = "Required field missing.  You must provide at lease 1 of the following: " + String.Join(",", pipedFields)

                    End If
                Else
                    ' standard field, check if it exists

                    If Not parameters.ContainsKey(field) Then
                        [error] = (Convert.ToString("Required field ") & field) + " is missing!"
                    Else
                        ' ensure field value is not empty
                        Dim value As String = parameters(field)
                        If value.Length <= 0 Then
                            [error] = (Convert.ToString("Required field ") & field) + " is missing!"
                        End If

                    End If
                End If
            End If


            If [error].Length > 0 Then
                Throw (New Exception([error]))
                Return
            End If
        Next



        Return
    End Sub

    ' merges 2 dictionaries into one, stops duplicates
    Private Function _mergeDictionaries(d1 As Dictionary(Of String, String), d2 As Dictionary(Of String, String)) As Dictionary(Of String, String)
        Dim mergedDictionary As New Dictionary(Of String, String)()

        For Each entry As KeyValuePair(Of String, String) In d1
            If Not mergedDictionary.ContainsKey(entry.Key) Then
                mergedDictionary.Add(entry.Key, entry.Value)
            End If
        Next

        For Each entry As KeyValuePair(Of String, String) In d2
            If Not mergedDictionary.ContainsKey(entry.Key) Then
                mergedDictionary.Add(entry.Key, entry.Value)
            End If
        Next

        Return mergedDictionary
    End Function


End Class


