using System;
using System.Collections.Generic;
using System.Text;

using Xceed.Zip;
using System.IO;
using System.Windows.Forms;
using System.Net;
using System.Xml;
using Xceed.FileSystem;

namespace Engineer
{
    public class Updating
    {

        public static string ServerUpdatePath = "http://halotech.org/Engineer/Updating/";
        public static string UpdateXmlLocation = ServerUpdatePath + "Update.xml";

        static string localUpdateName = "\\update.zip";

        public UpdateInfo UpdatingInfo;

        public event DownloadProgressChangedEventHandler DownloadProgressChangedEventHandler;
        public event System.ComponentModel.AsyncCompletedEventHandler AsyncCompletedEventHandler;

        public event ByteProgressionEventHandler ByteProgressionEventHandler;
        public event ItemProgressionEventHandler ItemProgressionEventHandler;

        public static bool isUpdateAvaiable(UpdateInfo ui, double CurrentVersion)
        {
            //Return if its a newer version
            return (ui.UpdateVersion > CurrentVersion);
        }

        public void DownloadUpdate()
        {
            //Get out update information
            UpdatingInfo = GetUpdateInfo();

            //Create a webclient
            WebClient wc = new WebClient();
            wc.DownloadProgressChanged += DownloadProgressChangedEventHandler;
            wc.DownloadFileCompleted += AsyncCompletedEventHandler;

            //Begin our download
            wc.DownloadFileAsync(new Uri(ServerUpdatePath + UpdatingInfo.ZipURL), Application.StartupPath + localUpdateName);
        }

        public static UpdateInfo GetUpdateInfo()
        {
            //Create the update info struct
            UpdateInfo ui = new UpdateInfo();

            //Download our data and read it

            XmlDocument doc = new XmlDocument(); 
            doc.Load(UpdateXmlLocation);
            XmlElement root = doc.DocumentElement;

            XmlNode tmp = root.SelectSingleNode("//Engineer//version");
            ui.UpdateVersion = double.Parse(tmp.InnerText);

            tmp = root.SelectSingleNode("//Engineer//description");
            ui.UpdateDes = tmp.InnerText;

            tmp = root.SelectSingleNode("//Engineer//image");
            ui.UpdateImageLocation = tmp.InnerText;

            tmp = root.SelectSingleNode("//Engineer//changeLog");
            ui.Changes = new List<Change>();
            foreach (XmlNode node in tmp)
            {
                Change c = new Change();
                c.type = (ChangeType)Enum.Parse(typeof(ChangeType), node.Attributes["type"].Value, true);
                c.lvl = (ChangeLvl)Enum.Parse(typeof(ChangeLvl), node.Attributes["lvl"].Value, true);
                c.Des = node.Attributes["des"].Value;
                ui.Changes.Add(c);
            }

            tmp = root.SelectSingleNode("//Engineer//updateURL");
            ui.ZipURL = tmp.InnerText;

            tmp = root.SelectSingleNode("//Engineer//cleanSettings");
            ui.CleanSettings = bool.Parse(tmp.InnerText);

            //Return our update info
            return ui;
        }

        public void UnpackUpdate()
        {

            AbstractFile zipFile = new DiskFile(Application.StartupPath + localUpdateName);
            ZipArchive archive = new ZipArchive(zipFile);

            foreach (FileSystemItem childItem in archive.GetItems(true))
            {
                string name = childItem.FullName;
                if (File.Exists(Application.StartupPath + name))
                    File.Move(Application.StartupPath + name,
                        Application.StartupPath + name + ".old");
            }

            AbstractFolder dest = new DiskFolder(Application.StartupPath);

            ZipEvents events = new ZipEvents();
            events.ByteProgression += ByteProgressionEventHandler;
            events.ItemProgression += ItemProgressionEventHandler;

            archive.CopyFilesTo(events, null, dest, true, true, "*.*");

        }

        public void DeleteUpdate()
        {
            File.Delete(Application.StartupPath + localUpdateName);
        }

        public static void PerformCleanup()
        {
            DirectoryInfo di = new DirectoryInfo(Application.StartupPath);
            PerformCleanup(di);
        }

        public static void PerformCleanup(DirectoryInfo di)
        {
            DirectoryInfo[] ds = di.GetDirectories();
            for (int i = 0; i < ds.Length; i++)
            {
                PerformCleanup(ds[i]);
            }

            FileInfo[] fs = di.GetFiles();
            for (int i = 0; i < fs.Length; i++)
            {
                string ext = fs[i].Extension;
                if (ext == ".old")
                {
                    fs[i].Delete();
                }
            }
        }

        public struct UpdateInfo
        {
            public string ZipURL;
            public double UpdateVersion;
            public string UpdateDes;
            public string UpdateImageLocation;
            public List<Change> Changes;
            public bool CleanSettings;
        }

        public enum ChangeType
        {
            Added,
            Removed,
            Fixed,
            Updated
        }
        public enum ChangeLvl
        {
            High,
            Medium,
            Low
        }
        public struct Change
        {
            public ChangeType type;
            public ChangeLvl lvl;
            public string Des;
        }

    }
}