'2006 kleinma MSMVP
'www.vbforums.com

Imports System.Net
Imports System.IO

''' <summary>
''' Allows you to download a file while reporting progress
''' </summary>
''' <remarks></remarks>
Public Class WebFileDownloader
    Public Event AmountDownloadedChanged(ByVal iNewProgress As Long)
    Public Event FileDownloadSizeObtained(ByVal iFileSize As Long)
    Public Event FileDownloadComplete()
    Public Event FileDownloadFailed(ByVal ex As Exception)

    Private mCurrentFile As String = String.Empty

    ''' <summary>
    ''' Property that gets the current file being downloaded.
    ''' </summary>
    ''' <value>Returns String</value>
    ''' <returns>String.</returns>
    ''' <remarks></remarks>
    Public ReadOnly Property CurrentFile() As String
        Get
            Return mCurrentFile
        End Get
    End Property

    ''' <summary>
    ''' Starts the download of a file WITHOUT providing progress
    ''' </summary>
    ''' <param name="URL">The source file to read from the remote server.</param>
    ''' <param name="Location">The location to save the downloaded file.</param>
    ''' <returns>Returns weather or not the command was executed successfully.</returns>
    ''' <remarks></remarks>
    Public Function DownloadFile(ByVal URL As String, ByVal Location As String) As Boolean
        Try
            mCurrentFile = GetFileName(URL)
            Dim WC As New WebClient
            WC.DownloadFile(URL, Location)
            RaiseEvent FileDownloadComplete()
            Return True
        Catch ex As Exception
            RaiseEvent FileDownloadFailed(ex)
            Return False
        End Try
    End Function

    ''' <summary>
    ''' Returns the name of a file (Either remote or local) with the file extension.
    ''' </summary>
    ''' <param name="URL">Address of the file to retrieve the name from.</param>
    ''' <returns>Name of a file with extension.</returns>
    ''' <remarks></remarks>
    Private Function GetFileName(ByVal URL As String) As String
        Try
            Return URL.Substring(URL.LastIndexOf("/") + 1)
        Catch ex As Exception
            Return URL
        End Try
    End Function

    ''' <summary>
    ''' Starts the download of a file WITH progress provided threw an event. SHOULD BE RUN ON SEPERATE THREAD!
    ''' </summary>
    ''' <param name="URL"></param>
    ''' <param name="Location"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function DownloadFileWithProgress(ByVal URL As String, ByVal Location As String) As Boolean
        Dim FS As FileStream
        Try
            mCurrentFile = GetFileName(URL)
            Dim wRemote As WebRequest
            Dim bBuffer As Byte()
            ReDim bBuffer(256)
            Dim iBytesRead As Integer
            Dim iTotalBytesRead As Integer

            FS = New FileStream(Location, FileMode.Create, FileAccess.Write)
            wRemote = WebRequest.Create(URL)
            Dim myWebResponse As WebResponse = wRemote.GetResponse
            RaiseEvent FileDownloadSizeObtained(myWebResponse.ContentLength)
            Dim sChunks As Stream = myWebResponse.GetResponseStream
            Do
                iBytesRead = sChunks.Read(bBuffer, 0, 256)
                FS.Write(bBuffer, 0, iBytesRead)
                iTotalBytesRead += iBytesRead
                If myWebResponse.ContentLength < iTotalBytesRead Then
                    RaiseEvent AmountDownloadedChanged(myWebResponse.ContentLength)
                Else
                    RaiseEvent AmountDownloadedChanged(iTotalBytesRead)
                End If
            Loop While Not iBytesRead = 0
            sChunks.Close()
            FS.Close()
            RaiseEvent FileDownloadComplete()
            Return True
        Catch ex As Exception
            If Not (FS Is Nothing) Then
                FS.Close()
                FS = Nothing
            End If
            RaiseEvent FileDownloadFailed(ex)
            Return False
        End Try
    End Function

    ''' <summary>
    ''' Formats a number of bytes to an appropriate size (KB, MB, or GB)
    ''' </summary>
    ''' <param name="Size">Byte count to format</param>
    ''' <returns>String with formated byte count WITH label</returns>
    ''' <remarks></remarks>
    Public Shared Function FormatFileSize(ByVal Size As Long) As String
        Try
            Dim KB As Integer = 1024
            Dim MB As Integer = KB * KB
            ' Return size of file in kilobytes.
            If Size < KB Then
                Return (Size.ToString("D") & " bytes")
            Else
                Select Case Size / KB
                    Case Is < 1000
                        Return (Size / KB).ToString("N") & "KB"
                    Case Is < 1000000
                        Return (Size / MB).ToString("N") & "MB"
                    Case Is < 10000000
                        Return (Size / MB / KB).ToString("N") & "GB"
                End Select
            End If
        Catch ex As Exception
            Return Size.ToString
        End Try
    End Function
End Class

