using CommonLang.Concurrent;
using CommonLang.IO;
using MPQ;
using MPQ.Updater;
using System;
using System.IO;

namespace CommonMPQ.SharpZipLib
{
    public class SharpZipLibMPQDirver : MPQDirver
    {
        public override bool RunUnzipSingle(MPQUpdater updater, MPQUpdater.RemoteFileInfo zip, MPQUpdater.RemoteFileInfo mpq, AtomicLong process)
        {
            return Unzip.SharpZipLib_RunUnzipMPQ(updater, zip, mpq, process);
        }
    }
    public class Unzip
    {
        public static int BUFF_SIZE = 1024 * 1024 * 16;

        public static bool SharpZipLib_DecompressZ(ArraySegment<byte> src, ArraySegment<byte> dst)
        {
            using (var input = new MemoryStream(src.Array, src.Offset, src.Count))
            {
                using (var zstream = new Zip.Compression.Streams.InflaterInputStream(input, new Zip.Compression.Inflater(false), Math.Min(dst.Count, BUFF_SIZE)))
                {
                    IOUtil.ReadToEnd(zstream, dst.Array, dst.Offset, dst.Count);
                }
            }
            return true;
        }

        public static bool SharpZipLib_RunUnzipMPQ(MPQUpdater updater, MPQUpdater.RemoteFileInfo zip_file, MPQUpdater.RemoteFileInfo mpq_file, AtomicLong current_unzip_bytes)
        {
            using (FileStream fis = new FileStream(zip_file.file.FullName, FileMode.Open, FileAccess.Read))
            {
                using (FileStream fos = new FileStream(mpq_file.file.FullName, FileMode.Create, FileAccess.Write))
                {
                    try
                    {
                        if (MPQUpdater.ZIP_EXT.ToLower().EndsWith(".zip"))
                        {
                            using (var zipf = new CommonMPQ.SharpZipLib.Zip.ZipFile(fis))
                            {
                                var e = zipf.GetEnumerator();
                                if (e.MoveNext())
                                {
                                    var ze = (CommonMPQ.SharpZipLib.Zip.ZipEntry)(e.Current);
                                    Stream zipin = zipf.GetInputStream(ze);
                                    if (IOUtil.ReadTo(zipin, fos, mpq_file.size, (int readed) =>
                                    {
                                        current_unzip_bytes += readed;
                                        return !updater.IsDisposing;
                                    }, 1024 * 1024) == false)
                                    { return false; }
                                }
                                zipf.Close();
                            }
                        }
                        else if (MPQUpdater.ZIP_EXT.ToLower().EndsWith(".mgz"))
                        {
                            var gstream = new CommonMPQ.SharpZipLib.GZip.GZipInputStream(fis);
                            if (IOUtil.ReadTo(gstream, fos, mpq_file.size, (int readed) =>
                            {
                                current_unzip_bytes += readed;
                                return !updater.IsDisposing;
                            }, 1024 * 1024) == false)
                            { return false; }
                            gstream.Close();
                        }
                        else if (MPQUpdater.ZIP_EXT.ToLower().EndsWith(".z"))
                        {
                            var gstream = new CommonMPQ.SharpZipLib.Zip.Compression.Streams.InflaterInputStream(fis);
                            if (IOUtil.ReadTo(gstream, fos, mpq_file.size, (int readed) =>
                            {
                                current_unzip_bytes += readed;
                                return !updater.IsDisposing;
                            }, 1024 * 1024) == false)
                            { return false; }
                            gstream.Close();
                        }
                        return true;
                    }
                    finally
                    {
                        fos.Close();
                        fis.Close();
                    }
                }
            }
        }
    }
}