'  
'   Rebex Sample Code License
' 
'   Copyright 2025, REBEX CR s.r.o.
'   All rights reserved.
'   https://www.rebex.net/
' 
'   Permission to use, copy, modify, and/or distribute this software for any
'   purpose with or without fee is hereby granted.
' 
'   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
'   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
'   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
'   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
'   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
'   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
'   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
'   OTHER DEALINGS IN THE SOFTWARE.
' 

Imports System
Imports System.Data
Imports System.IO
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls
Imports System.Text

Imports Rebex.IO
Imports Rebex.IO.Compression

Partial Public Class [Default]
    Inherits System.Web.UI.Page
    ''' <summary>
    ''' Retrieves the ZIP archive file uploaded from the web page and extract its content into the target folder.
    ''' </summary>
    Private Sub ExtractUploadedFile()
        ' construct physical path to the target folder
        Dim targetFolder As String = GetTargetFolder()

        ' check the uploaded file
        If FileUploadControl.PostedFile.ContentLength <= 0 Then
            Throw New SampleException("No data uploaded.")
        End If

        Dim fileName As String = Path.GetFileName(FileUploadControl.PostedFile.FileName)
        Dim filePath As String = SafePathCombine(targetFolder, fileName)

        ' create the target folder
        Directory.CreateDirectory(targetFolder)

        ' upload archive file first
        FileUploadControl.PostedFile.SaveAs(filePath)

        ' unzip the archive
        Dim res As ArchiveOperationResult = ZipArchive.ExtractAll(filePath, targetFolder, TransferMethod.Copy, ActionOnExistingFiles.OverwriteAll)
        UploadedFiles.Text = res.FilesAffected.ToString()

        ' delete the archive file
        File.Delete(filePath)

        ' show results
        ArchiveFileName.Text = fileName
        ShowFileList()
    End Sub

    ''' <summary>
    ''' Deletes folder <see cref="GetTargetFolder"/> and all its content.
    ''' </summary>
    Private Sub CleanUpTargetFolder()
        Dim targetFolder As String = GetTargetFolder()

        Try
            If Directory.Exists(targetFolder) Then
                Directory.Delete(targetFolder, True)
            End If
        Catch ex As UnauthorizedAccessException
            Throw New SampleException(String.Format("Unable to clean up folder '{0}'. " + ex.Message, targetFolder), ex)
        Catch ex As IOException
            Throw New SampleException(String.Format("Unable to clean up folder '{0}'. " + ex.Message, targetFolder), ex)
        End Try
    End Sub

#Region "Event handlers"

    Protected Sub PerformUpload_Click(ByVal sender As Object, ByVal e As EventArgs)
        Try
            ' optionally clean up the folder first
            If CleanUpBeforeUpload.Checked Then
                CleanUpTargetFolder()
            End If

            ' process the upload
            ExtractUploadedFile()

            ' on success proceed to the next step (next panel)
            UploadFormPanel.Visible = False
            UploadedFilesPanel.Visible = True
            PnlReset.Visible = True
        Catch ex As SampleException
            ' display an error reported by our method
            ErrorMessage.Visible = True
            ErrorMessage.Text = ex.Message
        Catch ex As ZipException
            ' display an error reported by the ZIP component
            ErrorMessage.Visible = True
            ErrorMessage.Text = ex.Message
        Catch ex As Exception
            ' display all other errors
            ErrorMessage.Visible = True
            ErrorMessage.Text = "Error while processing the upload: " + ex.Message.ToString()
        End Try
    End Sub

    Protected Sub CleanUp_Click(ByVal sender As Object, ByVal e As EventArgs)
        Try
            ' perform the cleanup
            CleanUpTargetFolder()

            ' on success proceed to the next step (next panel)
            UploadedFilesPanel.Visible = False
            CleanupCompletedPanel.Visible = True
        Catch ex As SampleException
            ' display an error reported by our method
            ErrorMessage.Visible = True
            ErrorMessage.Text = ex.Message
        Catch ex As Exception
            ' display all other errors
            ErrorMessage.Visible = True
            ErrorMessage.Text = "Error while cleaning up the target folder: " + ex.Message.ToString()
        End Try
    End Sub

#End Region

#Region "Helper methods"

    ''' <summary>
    ''' Constructs the physical path to the folder to which the ZIP archive should be extracted.<br/>
    ''' The folder is also used as temporary storage for uploaded archive files.
    ''' </summary>
    ''' <returns>Target folder path.</returns>
    Public Function GetTargetFolder() As String
        Dim targetSubfolder As String = TargetFolder.Text
        If String.IsNullOrEmpty(targetSubfolder) Then
            Throw New SampleException("Target folder not specified.")
        End If

        Return SafePathCombine(Path.GetTempPath(), targetSubfolder)
    End Function

    ''' <summary>
    ''' Show list of files in the target folder into the scrollable div on the web page.
    ''' </summary>
    Private Sub ShowFileList()
        Dim targetFolder As String = GetTargetFolder()

        Dim listing As New StringBuilder()
        For Each filePath As String In Directory.GetFiles(targetFolder, "*", SearchOption.AllDirectories)
            listing.AppendFormat("{0}<br/>", Server.HtmlEncode(filePath))
        Next

        DivFilesList.InnerHtml = listing.ToString()
    End Sub

    ''' <summary>
    ''' Safely combines two path strings, making sure that the combined path is not outside the first path.
    ''' </summary>
    ''' <param name="path1">The first path.</param>
    ''' <param name="path2">The second path.</param>
    ''' <returns>Combined path.</returns>
    Private Shared Function SafePathCombine(ByVal path1 As String, ByVal path2 As String) As String
        Dim path3 As String = Path.Combine(path1, path2)
        Dim fullPath3 As String = Path.GetFullPath(path3).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar
        Dim fullPath1 As String = Path.GetFullPath(path1).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar

        If Not fullPath3.StartsWith(fullPath1) Then
            Throw New SampleException("The combined path is outside the first path.")
        End If

        Return path3
    End Function

#End Region

End Class
