using System;
using System.Net;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;

namespace SHNEditor
{
    class Download
    {
        private Stopwatch DownloadTimer;

        public String FileName { get; set; }
        public String SavePath { get; set; }
        public Uri Address { get; set; }
        public ProgressBar Progress { get; set; }
        public Label Information { get; set; }
        public Boolean HasErrored;
        public Boolean IsFinished;

        WebClient DownloadClient;

        public void StartDownload()
        {
            try
            {
                DownloadClient = new WebClient();
                DownloadClient.DownloadFileCompleted += DownloadClient_DownloadFileCompleted;
                DownloadClient.DownloadProgressChanged += DownloadClient_DownloadProgressChanged;

                DownloadTimer = new Stopwatch();
                DownloadTimer.Start();

                DownloadClient.DownloadFileAsync(Address, SavePath);
            }
            catch (Exception) { HasErrored = true; }
        }

        private void DownloadClient_DownloadProgressChanged(Object Sender, DownloadProgressChangedEventArgs Arguments)
        {
            Int64 Completed = Arguments.BytesReceived;
            Int64 FileSize = Arguments.TotalBytesToReceive;
            Int32 ProgressPercentage = Arguments.ProgressPercentage;

            String KBSpeed = ConvertSize(Convert.ToInt64((Completed / DownloadTimer.Elapsed.TotalSeconds)));

            Progress.BeginInvoke((Action)(() => { Progress.Value = ProgressPercentage; }));
            Information.BeginInvoke((Action)(() => { Information.Text = String.Format("Downloading {0}: {1}% [{2}/{3}] :: {4}/s", FileName, ProgressPercentage, ConvertSize(Completed), ConvertSize(FileSize), KBSpeed); }));
        }

        private void DownloadClient_DownloadFileCompleted(Object Sender, AsyncCompletedEventArgs Arguments)
        {
            if (Arguments.Error != null) { HasErrored = true; }
            else
            {
                Progress.BeginInvoke((Action)(() => { Progress.Value = 100; }));
                Information.BeginInvoke((Action)(() => { Information.Text = String.Format("Downloaded {0} Successfully.", FileName); }));

                IsFinished = true;
            }
        }

        private static String ConvertSize(Int64 Amount)
        {
            String[] Suffix = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };

            Int64 Bytes = Math.Abs(Amount);

            Int32 Place = Convert.ToInt32(Math.Floor(Math.Log(Bytes, 1024)));

            Double Number = Math.Round(Bytes / Math.Pow(1024, Place), 1);

            return String.Format("{0} {1}", Convert.ToString(Math.Sign(Amount) * Number), Suffix[Place]);
        }
    }
}
