'  
'   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.IO
Imports System.Data
Imports System.Collections
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls

Imports Rebex.IO
Imports Rebex.IO.Compression

Partial Public Class BrowseArchive
    Inherits System.Web.UI.Page
#Region "Properties"

    ''' <summary>
    ''' Name of the browsed ZIP file.
    ''' </summary>
    Protected ReadOnly Property ArchiveFileName() As String
        Get
            If _archiveFileName Is Nothing Then
                _archiveFileName = Request(UrlParameter.ArchiveFileName)
            End If
            Return _archiveFileName
        End Get
    End Property
    Private _archiveFileName As String

    ''' <summary>
    ''' Full physical path of the browsed ZIP file.
    ''' </summary>
    Private ReadOnly Property PhysicalArchivePath() As String
        Get
            Return Path.Combine(Server.MapPath(Constants.SampleFilesVirtualDirectory), ArchiveFileName)
        End Get
    End Property

    ''' <summary>
    ''' Current directory within the browsed ZIP file.
    ''' </summary>
    Private ReadOnly Property CurrentPath() As String
        Get
            If _currentPath Is Nothing Then
                ' get path from URL
                _currentPath = Request(UrlParameter.Path)

                ' set path to the root directory
                If String.IsNullOrEmpty(_currentPath) Then
                    _currentPath = Path.DirectorySeparatorChar.ToString()
                End If
            End If
            Return _currentPath
        End Get
    End Property
    Private _currentPath As String

    ''' <summary>
    ''' Command to be performed (taken from URL).
    ''' </summary>
    Public ReadOnly Property Command() As String
        Get
            If _command Is Nothing Then
                ' get command from URL
                _command = Request(UrlParameter.Command)

                ' handle default command
                If String.IsNullOrEmpty(_command) Then
                    _command = UrlParameterCommand.List
                End If
            End If
            Return _command
        End Get
    End Property
    Private _command As String

#End Region

    Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs)
        ' the following intializations cannot be performed in ASPX code
        CloseArchiveImage.ImageUrl = Util.GetIcon(IconType.Close)
        GoToParentDirectoryImage.ImageUrl = Util.GetIcon(IconType.DirectoryUp)
    End Sub

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
        ' check the mandatory arguments
        If String.IsNullOrEmpty(ArchiveFileName) Then
            ErrorMessage.Text = String.Format("No archive file has been defined in url argument '{0}'<br/>Please, go back to the <a href='Default.aspx'>list of archive files</a> and choose an archive.", UrlParameter.ArchiveFileName)
            ErrorMessage.Visible = True
        Else
            ' Fill properties of misc. page controls
            PreparePage()

            ' Perform operation specified by the command from URL
            ProcessCommand()
        End If
    End Sub

    ''' <summary>
    ''' Fill properties of miscelaneous page controls.
    ''' </summary>
    Private Sub PreparePage()
        ' fill literals in page header
        ArchiveFileNameControl.Text = ArchiveFileName
        CurrentPathControl.Text = CurrentPath

        ' set URL for UpDirectory toolbar link

        ' are we in the root directory?
        If CurrentPath = Path.DirectorySeparatorChar.ToString() Then
            ' we are - don't show the UpDirectory link
            GoToParentDirectoryListItem.Visible = False
        Else
            ' not in root folder - show the UpDirectory link
            GoToParentDirectoryListItem.Visible = True
            GoToParentDirectory.NavigateUrl = AssembleParameterUrl(UrlParameterCommand.List, CurrentPath.Substring(0, CurrentPath.LastIndexOf(Path.DirectorySeparatorChar)))
        End If
    End Sub

    ''' <summary>
    ''' Performs operation specified by the command from URL.
    ''' </summary>
    Private Sub ProcessCommand()
        ' choose the appropriate action according to the requested command
        Select Case Command
            Case UrlParameterCommand.List
                ShowFileList()
                Exit Select
            Case UrlParameterCommand.Download
                DownloadFile()
                Exit Select
            Case Else
                Throw New InvalidOperationException(String.Format("Unknown command '{0}'.", Command))
        End Select
    End Sub

    ''' <summary>
    ''' Gets the list of items in the current path of the current ZIP archive and binds it to the grid.
    ''' </summary>
    Private Sub ShowFileList()
        ' open the current ZIP archive
        Using archive As New ZipArchive(PhysicalArchivePath, ArchiveOpenMode.Open, ArchiveAccessMode.Read)
            ' gets the list of files and directories in the current path of the current ZIP archive
            Dim items As ZipItemCollection = archive.GetItems(Path.Combine(CurrentPath, "*"), TraversalMode.NonRecursive)

            ' sort the collection by item path (directories first)
            items.Sort()

            ' bind the items to the grid
            ArchiveFilesGridView.DataSource = items
            ArchiveFilesGridView.DataBind()
        End Using
    End Sub

    ''' <summary>
    ''' Sends the selected file from ZIP archive to the HTTP response stream.
    ''' </summary>
    Private Sub DownloadFile()
        ' open the current ZIP archive
        Using archive As New ZipArchive(PhysicalArchivePath, ArchiveOpenMode.Open, ArchiveAccessMode.Read)
            ' clear response stream and set the response header and content type
            Response.Clear()
            Response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}", Path.GetFileName(CurrentPath)))
            Response.ContentType = "application/octet-stream"

            ' extract (decompress) the file from the archive directly to the response stream
            archive.ExtractFile(CurrentPath, Response.OutputStream)
        End Using

        ' close the current HTTP response and stop executing this page
        Response.[End]()
    End Sub

#Region "Web page helpers"

    ''' <summary>
    ''' Returns a URL query string for this page that specifies the desired action.
    ''' </summary>
    ''' <param name="commandType">Command to perform.</param>
    ''' <param name="path">Path to a ZIP directory or file.</param>
    ''' <returns>A URL query string.</returns>
    Protected Function AssembleParameterUrl(ByVal commandType As String, ByVal path As String) As String
        Return String.Format("?{0}={1}&{2}={3}&{4}={5}", UrlParameter.ArchiveFileName, Uri.EscapeDataString(ArchiveFileName), UrlParameter.Command, commandType, UrlParameter.Path, _
         Uri.EscapeDataString(path))
    End Function

    ''' <summary>
    ''' Determines the action URL for the specified ZIP item.
    ''' </summary>
    ''' <param name="item">ZIP item.</param>
    ''' <returns>Action URL for the specified ZIP item.</returns>
    Protected Function GetUrl(ByVal item As ZipItem) As String
        If item Is Nothing Then
            Return String.Empty
        End If

        ' return 'list' URLs for directories and 'download' URLs for files
        Select Case item.ItemType
            Case ArchiveItemType.Directory
                Return AssembleParameterUrl(UrlParameterCommand.List, item.Path)
            Case ArchiveItemType.File

                Return AssembleParameterUrl(UrlParameterCommand.Download, item.Path)
            Case Else

                Throw New InvalidOperationException(String.Format("Unknown ZipItemType '{0}'.", item.ItemType))
        End Select
    End Function

#End Region
End Class
