namespace St0rm.MapDownloader
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Net;
    using System.IO;
    using System.Text.RegularExpressions;
    using ICSharpCode.SharpZipLib.Zip;

    public class FtpManager
    {
        public const string URL = "ftp://maps.St0rm.net/";

        List<Map> _maps = new List<Map>();

        public static FtpManager Instance = new FtpManager();

        public void DownloadList()
        {
            lock (_maps)
            {
                System.Windows.Forms.CheckedListBox mapListBox = MainForm.Instance.MapList;
                mapListBox.Items.Clear();
                _maps.Clear();
                //-rw-r--r--   1 ftp      ftp       5069242 Dec 26 02:20 C&C_AI_Garden.zip
                Regex parser = new Regex(@"\S+\s+\d+\s+\S+\s+\S+\s+(\d+)\s+\S+\s+\d+\s+\S+\s+(\S+(.zip|.mix))");
                FtpWebRequest client = (FtpWebRequest)WebRequest.Create(URL);
                client.Method = WebRequestMethods.Ftp.ListDirectoryDetails;

                StreamReader reader = new StreamReader(client.GetResponse().GetResponseStream());
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    if (parser.IsMatch(line))
                    {
                        Match match = parser.Match(line);
                        string file = match.Groups[2].Value;
                        long size = long.Parse(match.Groups[1].Value);
                        string name = Regex.Match(file, @"(?:C&C_)?(.*)(.zip|.mix)$").Groups[1].Value;
                        Map map = new Map(name, file, size);
                        _maps.Add(map);
                        mapListBox.Items.Add(map);
                    }
                }
            }
        }

        public void DownloadAll(List<Map> maps)
        {
            int maps_installed = 0;
            long total_size = 0;
            long total_read = 0;
            MainForm.Instance.SetTotalBar(0);
            MainForm.Instance.SetFileBar(0);
            byte[] buf = new byte[1024 * 10];
            foreach (Map map in maps)
                total_size += map.FileSize;
            foreach (Map map in maps)
            {
                MainForm.Instance.Status = String.Format("Downloading {0}...", map.FileName);
                FtpWebRequest client = (FtpWebRequest)WebRequest.Create(URL + map.FileName);
                client.Method = WebRequestMethods.Ftp.DownloadFile;
                Stream instream = client.GetResponse().GetResponseStream();
                int read = 0;
                long file_read = 0;

                string tmp = Path.GetTempFileName();
                Stream outstream = new FileStream(tmp, FileMode.Create);

                while (instream.CanRead && (read = instream.Read(buf, 0, buf.Length)) > 0)
                {
                    file_read += read;
                    total_read += read;
                    outstream.Write(buf, 0, read);
                    if (read > 0)
                    {
                        MainForm.Instance.SetFileBar((int)(((double)file_read / map.FileSize) * 100));
                        MainForm.Instance.SetTotalBar((int)(((double)total_read / total_size) * 100));
                    }
                }
                outstream.Flush();
                outstream.Close();
                instream.Close();
                if (map.FileName.EndsWith(".mix", true, null))
                {
                    maps_installed++;
                    File.Move(tmp, Path.Combine(Config.InstallDirectory, map.FileName));
                    MainForm.Instance.MapList.Invoke((Action)(() => MainForm.Instance.MapList.Items.Remove(map)));
                }
                else
                {
                    ICSharpCode.SharpZipLib.Zip.ZipFile zip = new ICSharpCode.SharpZipLib.Zip.ZipFile(new FileStream(tmp, FileMode.Open));
                    try
                    {
                        foreach (object o in zip)
                        {
                            if (o.ToString().EndsWith(".mix", true, null))
                            {
                                ZipEntry entry = zip.GetEntry(o.ToString());
                                if (entry.IsDirectory)
                                    Directory.CreateDirectory(Path.Combine(Config.InstallDirectory, o.ToString()));
                                else
                                {
                                    FileStream fout = new FileStream(Path.Combine(Config.InstallDirectory, o.ToString()), FileMode.Create);
                                    MainForm.Instance.Status = String.Format("Extracting {0}...", o);
                                    Stream zin = zip.GetInputStream(zip.GetEntry(o.ToString()));
                                    read = 0;
                                    while (zin.CanRead && (read = zin.Read(buf, 0, buf.Length)) > 0)
                                    {
                                        fout.Write(buf, 0, read);
                                    }
                                    Console.WriteLine("Loop Exited");
                                    fout.Flush();
                                    fout.Close();
                                    zin.Close();
                                    maps_installed++;
                                    MainForm.Instance.MapList.Invoke((Action)(() => MainForm.Instance.MapList.Items.Remove(map)));
                                }
                            }

                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                    zip.Close();

                    //    new ICSharpCode.SharpZipLib.Zip.FastZip().ExtractZip(tmp, Config.InstallDirectory, "*.mix");

                }
            }
            MainForm.Instance.Status = String.Format("Downloaded and installed {0} maps!", maps_installed);
            MainForm.Instance.Downloadable(true);
            if (!MainForm.Instance.Visible) Environment.Exit(0);
        }
    }
}
