using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using System.IO;

/// <summary>
/// Formularz Web pozwalający na przeglądanie i pobieranie plików z serwera.
/// Użytkownik może również wysyłać pliki oraz tworzyć foldery.
/// </summary>
public partial class FileBrowser : System.Web.UI.Page
{
    /// <summary>
    /// Pobranie ścieżki foldera do wyświetlania i generowanie listy plików
    /// </summary>
    protected void Page_Load(object sender, EventArgs e)
    {
        string currentRoot = RetrievePathOfFolderToDisplay();
        litLocation.Text = currentRoot;
        GenerateListing(currentRoot);
    }

    /// <summary>
    /// Wyświetlenie zawartości podanego folderu.
    /// </summary>
    private void GenerateListing(string rootpath)
    {
        // na początek czyszczenie kontrolki PlaceHolder
        myPlaceHolder.Controls.Clear();

        // wyznaczenie ścieżki w celu odczytania folderów i plików
        string path = Server.MapPath("") + "/" + rootpath;

        DirectoryInfo dirInfo = new DirectoryInfo(path);

        // dodanie łącza "przejdź w górę" jeżeli jest potrzebne
        MakeUpOneLevelLink(rootpath);

        // pobranie listy wszystkich folderów
        DirectoryInfo[] folders = dirInfo.GetDirectories();
        // przeglądanie kolejnych folderów i ich wyświetlanie
        foreach (DirectoryInfo folder in folders)
        {
            DisplayFolder(folder, rootpath);
        }

        // pobranie listy wszystkich plików w bieżącej ścieżce
        FileInfo[] files = dirInfo.GetFiles();
        // przeglądanie kolejnych plików
        foreach (FileInfo file in files)
        {
            DisplayFile(file, rootpath);
        }
    }

    /// <summary>
    /// Pobranie ścieżki folderu do wyświetlenia
    /// </summary>
    private string RetrievePathOfFolderToDisplay()
    {
        string localpath = Request.QueryString["local"];
        // jeżeli nie ma żadnego ciągu, ustawiamy jako główny katalog uploads
        if (localpath == null)
            return "uploads";
        else
            // usunięcie kodowania URL niezbędnego w ciągu zapytania
            return Server.UrlDecode(localpath);
    }

    /// <summary>
    /// Wyświetlenie odpowiednich kontrolek dla przekazanego folderu
    /// </summary>
    private void DisplayFolder(DirectoryInfo folder, string rootpath)
    {
        // Pobranie nazwy folderu bez ścieżki
        string shortfolder = Path.GetFileName(folder.FullName);

        // dodanie ikony folderu
        Image img = new Image();
        img.ImageUrl = "images/mime_folder.gif";
        myPlaceHolder.Controls.Add(img);

        // Dodanie spacji niełamiącej
        LiteralControl space1 = new LiteralControl("&nbsp;");
        myPlaceHolder.Controls.Add(space1);

        // dodanie łącza folderu, dzięki czemu użytkownik może do niego przejść
        HyperLink lnk = new HyperLink();
        lnk.Text = shortfolder;
        lnk.NavigateUrl = "FileBrowser.aspx?local=" + Server.UrlEncode(rootpath + "/" + shortfolder);
        myPlaceHolder.Controls.Add(lnk);

        LiteralControl br1 = new LiteralControl("<br/>");
        myPlaceHolder.Controls.Add(br1);
    }

    /// <summary>
    /// Wyświetlenie odpowiednich kontrolek dla przekazanego pliku
    /// </summary>
    private void DisplayFile(FileInfo file, string rootpath)
    {
        // Pobranie nazwy pliku bez ścieżki
        string shortname = Path.GetFileName(file.FullName);

        // dodanie ikony pliku
        Image img = new Image();
        img.ImageUrl = GetIconForExtension(file);
        myPlaceHolder.Controls.Add(img);

        // Dodanie spacji niełamiącej
        LiteralControl space2 = new LiteralControl("&nbsp;");
        myPlaceHolder.Controls.Add(space2);

        // Dodanie łącza do pliku, dzięki czemu użytkownik może go pobrać lub wyświetlić 
        HyperLink lnk = new HyperLink();
        lnk.Text = shortname;
        // Łącze folderu musi przekazywać nazwę folderu.
        // Ponieważ nazwa folderu może zawierać znaki,
        // które nie są dozwolone w ciągu zapytania, należy je zakodować
        lnk.NavigateUrl = Server.UrlDecode(rootpath) + "/" + shortname;
        myPlaceHolder.Controls.Add(lnk);

        // dodanie wielkości pliku w KB
        long kb = file.Length / 1000;
        LiteralControl size = new LiteralControl(" [" + kb + " KB]");
        myPlaceHolder.Controls.Add(size);

        // dodanie nowego wiersza
        LiteralControl br2 = new LiteralControl("<br/>");
        myPlaceHolder.Controls.Add(br2);
    }

    /// <summary>
    /// Zwraca nazwę pliku dla odpowiedniej ikony typu pliku
    /// na podstawie rozszerzenia przekazanego pliku
    /// </summary>
    private string GetIconForExtension(FileInfo file)
    {
        string image = "images/"; 

        string ext = Path.GetExtension(file.FullName).ToLower();

        if (ext == ".txt")
            image += "mime_text.gif";
        else if (ext == ".doc")
            image += "mime_doc.gif";
        else if (ext == ".pdf")
            image += "mime_pdf.gif";
        else if (ext == ".gif" || ext == ".jpg" || ext == ".wmf")
            image += "mime_image.gif";
        else if (ext == ".html" || ext == ".htm" )
            image += "mime_html.gif";
        else
            image += "mime_unknown.gif";

        return image;
    }

    /// <summary>
    /// Utworzenie łącza "jeden poziom do góry" (jeżeli jest potrzebne dla bieżącego Makes the "go up a level" link (if needed for the 
    /// current folder) and adds it to the place holder
    /// </summary>
    private void MakeUpOneLevelLink(string currentFolder)
    {
        // Popbaranie poprzedniego folderu
        string previousFolder = GetPreviousFolder(currentFolder);
        // jeżeli istnieje poprzedni folder, dodanie łącza
        if (previousFolder != "")
        {
            Image imgBack = new Image();
            imgBack.ImageUrl = "images/mime_folder.gif";
            myPlaceHolder.Controls.Add(imgBack);

            HyperLink lnkBack = new HyperLink();
            lnkBack.Text = "..";
            lnkBack.NavigateUrl = "FileBrowser.aspx?local=" + Server.UrlEncode(previousFolder);
            myPlaceHolder.Controls.Add(lnkBack);

            LiteralControl br = new LiteralControl("<br/>");
            myPlaceHolder.Controls.Add(br);
        }
    }

    /// <summary>
    /// Pobranie poprzedniego folderu (z poziomu wyżej w hierarchii folderów)
    /// z przekazanej ścieżki. Jeżeli nie ma poprzedniego folderu, zwraca 
    /// pusty ciąg.
    /// </summary>
    private string GetPreviousFolder(string path)
    {
        int posOfLastSlash = path.LastIndexOf("/");
        if (posOfLastSlash < 0)
            return "";
        string stripped = path.Remove(posOfLastSlash);
        return stripped;
    }

    /// <summary>
    /// Procedura obsługi zdarzenia dla przycisku przesłania pliku
    /// </summary>
    protected void btnUpload_Click(object sender, EventArgs e)
    {
        // przezyłany plik jest umieszczany w bieżącym folderze
        string path = RetrievePathOfFolderToDisplay();
        if (fupTest.HasFile)
        {
            string fullname = Server.MapPath(path + "/" + fupTest.FileName);
            if (System.IO.File.Exists(fullname))
            {
                labMessage.Text = "Plik już istnieje - przesyłanie przerwane";
            }
            else
            {
                fupTest.SaveAs(fullname);
                labMessage.Text = "Udane przesłanie pliku";
                // powtórne utworzenie listy plików w celu pokazania przesłanego pliku
                GenerateListing(path);
            }
        }
        else
        {
            labMessage.Text = "Nie został podany plik";
        }

    }

    /// <summary>
    /// Procedura obsługi przycisku tworzenia nowego folderu
    /// </summary>
    protected void btnNewFolder_Click(object sender, EventArgs e)
    {        
        // pobranie lokalizacji nowego folderu
        string folderLocation = RetrievePathOfFolderToDisplay();
        string fullPath = Server.MapPath(folderLocation) + "/" + txtFolder.Text;
        // utworzenie folderu na serwerze
        Directory.CreateDirectory(fullPath);
        // powtórne utworzenie listy plików w celu pokazania nowego folderu
        GenerateListing(folderLocation);
    }
}
