//  
//   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.
// 

using System;
using System.IO;
using System.Data;
using System.Collections;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using Rebex.IO;
using Rebex.IO.Compression;

namespace Rebex.Samples
{
    public partial class BrowseArchive : System.Web.UI.Page
    {
        #region Properties

        /// <summary>
        /// Name of the browsed ZIP file.
        /// </summary>
        protected string ArchiveFileName
        {
            get
            {
                if (_archiveFileName == null)
                    _archiveFileName = Request[UrlParameter.ArchiveFileName];
                return _archiveFileName;
            }
        }
        private string _archiveFileName;

        /// <summary>
        /// Full physical path of the browsed ZIP file.
        /// </summary>
        private string PhysicalArchivePath
        {
            get
            {
                return Path.Combine(Server.MapPath(Constants.SampleFilesVirtualDirectory), ArchiveFileName);
            }
        }

        /// <summary>
        /// Current directory within the browsed ZIP file.
        /// </summary>
        private string CurrentPath
        {
            get
            {
                if (_currentPath == null)
                {
                    // get path from URL
                    _currentPath = Request[UrlParameter.Path];

                    // set path to the root directory
                    if (string.IsNullOrEmpty(_currentPath))
                        _currentPath = Path.DirectorySeparatorChar.ToString();
                }
                return _currentPath;
            }
        }
        private string _currentPath;

        /// <summary>
        /// Command to be performed (taken from URL).
        /// </summary>
        public string Command
        {
            get
            {
                if (_command == null)
                {
                    // get command from URL
                    _command = Request[UrlParameter.Command];

                    // handle default command
                    if (string.IsNullOrEmpty(_command))
                        _command = UrlParameterCommand.List;
                }
                return _command;
            }
        }
        private string _command;

        #endregion

        protected void Page_Init(object sender, EventArgs e)
        {
            // the following intializations cannot be performed in ASPX code
            CloseArchiveImage.ImageUrl = Util.GetIcon(IconType.Close);
            GoToParentDirectoryImage.ImageUrl = Util.GetIcon(IconType.DirectoryUp);
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            // check the mandatory arguments
            if (string.IsNullOrEmpty(ArchiveFileName))
            {
                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();
            }
        }

        /// <summary>
        /// Fill properties of miscelaneous page controls.
        /// </summary>
        private void 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())
            {
                // 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))
                );
            }
        }

        /// <summary>
        /// Performs operation specified by the command from URL.
        /// </summary>
        private void ProcessCommand()
        {
            // choose the appropriate action according to the requested command
            switch (Command)
            {
                case UrlParameterCommand.List:
                    ShowFileList();
                    break;
                case UrlParameterCommand.Download:
                    DownloadFile();
                    break;
                default:
                    throw new InvalidOperationException(string.Format("Unknown command '{0}'.", Command));
            }
        }

        /// <summary>
        /// Gets the list of items in the current path of the current ZIP archive and binds it to the grid.
        /// </summary>
        private void ShowFileList()
        {
            // open the current ZIP archive
            using (ZipArchive archive = new ZipArchive(PhysicalArchivePath, ArchiveOpenMode.Open, ArchiveAccessMode.Read))
            {
                // gets the list of files and directories in the current path of the current ZIP archive
                ZipItemCollection items = 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();
            }
        }

        /// <summary>
        /// Sends the selected file from ZIP archive to the HTTP response stream.
        /// </summary>
        private void DownloadFile()
        {
            // open the current ZIP archive
            using (ZipArchive archive = 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);
            }

            // close the current HTTP response and stop executing this page
            Response.End();
        }

        #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 string AssembleParameterUrl(string commandType, string path)
        {
            return string.Format("?{0}={1}&{2}={3}&{4}={5}",
                UrlParameter.ArchiveFileName, Uri.EscapeDataString(ArchiveFileName),
                UrlParameter.Command, commandType,
                UrlParameter.Path, Uri.EscapeDataString(path));
        }

        /// <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 string GetUrl(ZipItem item)
        {
            if (item == null)
                return string.Empty;

            // return 'list' URLs for directories and 'download' URLs for files
            switch (item.ItemType)
            {
                case ArchiveItemType.Directory:
                    return AssembleParameterUrl(UrlParameterCommand.List, item.Path);

                case ArchiveItemType.File:
                    return AssembleParameterUrl(UrlParameterCommand.Download, item.Path);

                default:
                    throw new InvalidOperationException(string.Format("Unknown ZipItemType '{0}'.", item.ItemType));
            }
        }

        #endregion
    }
}
