using System;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;

namespace Updater.Helpers
{
    public class ZipHelper
    {
        /// <summary>Extracts the specified zip file with its directory hierarchy</summary>
        /// <param name="file">Zip file to be extracted</param>
        /// <param name="folder">New folder that the zip will be extracted into</param>
        /// <param name="delete">Delete or keep the original zip after extracting</param>
        public static void Extract(string file, string folder, bool delete)
        {
            if (!file.ToLower().EndsWith(".zip"))
                throw new ApplicationException("Check your file format");

            if (!File.Exists(file))
                throw new ApplicationException("Zip file does not exist");

            if (!Directory.Exists(folder))
                Directory.CreateDirectory(folder);

            using (ZipInputStream zipInputStream = new ZipInputStream(File.OpenRead(file)))
            {
                ZipEntry zipEntry;

                while ((zipEntry = zipInputStream.GetNextEntry()) != null)
                {
                    string zipDirectory = Path.GetDirectoryName(zipEntry.Name);
                    string zipFile = Path.GetFileName(zipEntry.Name);
                    if (zipDirectory.Length > 0)
                        Directory.CreateDirectory(folder + Path.DirectorySeparatorChar + zipDirectory);

                    if (!string.IsNullOrEmpty(zipFile))
                    {
                        DecompressAndWriteFile(folder + Path.DirectorySeparatorChar + zipEntry.Name, zipInputStream);
                    }
                }
            }
        }

        private static void DecompressAndWriteFile(string destination, ZipInputStream source)
        {
            FileStream wstream = null;

            try
            {
                // create a stream to write the file to
                wstream = File.Create(destination);

                const int block = 2048; // number of bytes to decompress for each read from the source

                byte[] data = new byte[block]; // location to decompress the file to

                // now decompress and write each block of data for the zip file entry
                while (true)
                {
                    int size = source.Read(data, 0, data.Length);

                    if (size > 0)
                        wstream.Write(data, 0, size);
                    else
                        break; // no more data
                }
            }
            finally
            {
                if (wstream != null)
                    wstream.Close();
            }
        }
    }
}