using System;
using System.IO;
using System.Collections.Generic;

namespace Addison_Wesley.Codebook.Filesystem
{
   public class FolderUtil
   {
      /// <summary>
      /// Delegát pro ukálost <see cref="FolderProgress"/>
      /// </summary>
      public delegate void FolderProgressHandler(string currentFolderPath);

      /// <summary>
      /// Zjistí velikost adresáře
      /// </summary>
      public class FolderSize
      {
         /// <summary>
         /// Cesta k adresáři
         /// </summary>
         public string FolderPath;

         /// <summary>
         /// Celková velikost všech souborů v adresáři a jeho podadresářích
         /// </summary>
         public long Size;

         /// <summary>
         /// Konstruktor
         /// </summary>
         /// <param name="folderPath">Cesta k adresáři</param>
         /// <param name="size">Celková velikost všech souborů v adresáři a jeho podadresářích</param>
         internal FolderSize(string folderPath, long size)
         {
            this.FolderPath = folderPath;
            this.Size = size;
         }
      }

      /// <summary>
      /// Specializovaný seznam pro objekty typu FolderSize
      /// </summary>
      public class FolderSizes : List<FolderSize>
      {
      }

      /// <summary>
      /// Zjistí velikost všech přímých podadresářů daného adresáře
      /// </summary>
      /// <param name="folderPath">Cesta k adresáři</param>
      /// <param name="progress">Reference na delegát typu FolderProgress,
      /// s jehož pomocí tato metoda hlásí postup</param>
      /// <returns>Vrátí odkaz na seznam objektů typu FolderSize</returns>
      public static FolderSizes GetSubFolderSizes(string folderPath,
         FolderProgressHandler progress)
      {
         // Objekt typu FolderSizes pro uložení velikostí adresářů
         FolderSizes fs = new FolderSizes();

         // Objekt typu DirectoryInfo pro daný adresář
         DirectoryInfo folder = new DirectoryInfo(folderPath);

         // Volání delegátu postupu
         if (progress != null)
            progress(folder.Name);

         // Zjištění celkové velikosti souborů v adresáři
         FileInfo[] files = folder.GetFiles();
         long folderSize = 0;
         for (int i = 0; i < files.Length; i++)
            folderSize += files[i].Length;

         // Jméno a velikost adresáře uložíme jako první prvek seznamu 
         fs.Add(new FolderSize(folderPath, folderSize));

         // Zjištění podadresářů
         DirectoryInfo[] subFolders = folder.GetDirectories();

         // Projdeme podadresáře
         for (int i = 0; i < subFolders.Length; i++)
         {
            // Zavoláme delegát postupu
            if (progress != null)
               progress(subFolders[i].Name);

            // Aktuální velikost
            folderSize = FolderUtil.GetFolderSize(subFolders[i]);

            // Uložíme jméno a velikost adresáře do seznamu
            fs.Add(new FolderSize(subFolders[i].FullName, folderSize));
         }

         // Vrátíme odkaz na seznam
         return fs;
      }

      /// <summary>
      /// Zjistí (rekurzivně) velikost všech souborů v daném adresáři a jeho podadresářích
      /// </summary>
      /// <param name="folder">Odkaz na objekt typu DirectoryInfo, který reprezentuje daný adresář</param>
      /// <returns>Vrátí celkovou velikost všech souborů v bajtech</returns>
      public static long GetFolderSize(DirectoryInfo folder)
      {
         // proměnná pro uložení dosud zjištěného součtu
         // velikostí souborů v daném (pod-)adresáři
         long folderSize = 0;

         // Zjištění součtu velikostí souborů v daném adresáři
         FileInfo[] files = folder.GetFiles();
         for (int i = 0; i < files.Length; i++)
         {
            folderSize += files[i].Length;
         }

         // Zjištění podadresářů a rekurzivní volání této metody
         // umožní výpočet hodnoty proměnné folderSize         
         DirectoryInfo[] subFolders = folder.GetDirectories();
         for (int i = 0; i < subFolders.Length; i++)
         {
            folderSize += FolderUtil.GetFolderSize(subFolders[i]);
         }

         // Vrácení zjištěné velikosti adresáře
         return folderSize;
      }

      /// <summary>
      /// Vrátí celkovou velikost souborů v daném adresáři a jeho podadresářích
      /// </summary>
      /// <param name="folderPath">Cesta k adresáři</param>
      /// <returns>Vrátí celkovou velikost souborů v bajtech</returns>
      public static long GetFolderSize(string folderPath)
      {
          // Volání rekurzivní metody pro zjištění velikosti adresáře
         return FolderUtil.GetFolderSize(new DirectoryInfo(folderPath));
      }
   }
}
