using ICSharpCode.SharpZipLib.Zip;
using SocketTransfer;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace Bellwether.Utility
{
    public class UpdateProcess
    {
        public event EventHandler OnUpdateReady;
        public event EventHandler OnUpdateComplete;

        private string kioskIP;
        private int kioskPort;
        private SocketServer socketServer;
        private int updateFileCount = 0;
        private BackgroundWorker unzipWorker;

        private string zipName = "Temp.zip";
        private static string tempFolder = @"Temp\";
        private static string tempFolderPath = Path.Combine(Directory.GetCurrentDirectory(), @"Temp\");
        private string segmentsFilePath = tempFolderPath + @"\Data[{0}].cut";

        private string dataPath = Path.Combine(Directory.GetCurrentDirectory(), "Data");

        public static readonly Dictionary<PageType, string> PageFolderName
            = new Dictionary<PageType, string>() {
                { PageType.History, "History" },
                { PageType.Product, "Product" },
                { PageType.CSR, "CSR" },
            };

        public UpdateProcess()
        {
            if (GlobalFunction.CheckNetworkStatus())
            {
                try
                {
                    CreateSocketFunction();
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show("位址設定錯誤!!~ " + Properties.Settings.Default["SocketIP"].ToString() + ex.Message.ToString());
                    Application.Current.MainWindow.Close();
                }
            }
        }


        public void StartUpdateProcess()
        {
            //移動檔案並覆蓋
            if (MoveFileCheck())
            {
                socketServer.NotifyMessage("Success");
            }
            else
            {
                socketServer.NotifyMessage("Fail");
            }

            OnUpdateComplete.Invoke(this, null);
            //清除 Temp 資料夾內的所有檔案
            ClearFolderDataByPath(Path.Combine(Directory.GetCurrentDirectory(), tempFolder));

            //showStoryboard.Begin();
            //ReloadPage();
        }

        private void UpdateFileStart()
        {
            //hideStoryboard.Begin();
            OnUpdateReady?.Invoke(this, null);
        }

        private void unzipWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //合併
            if (MergerFileToZip())
            {
                //解壓縮
                DecompressFile();
                //將所有檔案刪除 (.zip & .cut)
                DeleteZipAndCutFile();
            }
            Thread.Sleep(5000);
        }

        private void unzipWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //檔案下載完畢~處理程序開始~ (直接更新)
            UpdateFileStart();
        }

        private void MoveFileDirect(string fromFilePath, string toFilePath)
        {
            File.Copy(fromFilePath, toFilePath, true);
        }

        private void MoveDirectoryDirect(string fromDirectory, string toDirectory)
        {
            Directory.Move(fromDirectory, toDirectory);
        }

        private void MoveImageOrMediaFile(string fromFileFolder, string toFileFolder)
        {
            if (Directory.Exists(fromFileFolder))
            {
                string[] files = Directory.GetFiles(fromFileFolder);

                foreach (string file in files)
                {
                    MoveFileDirect(file, toFileFolder + System.IO.Path.GetFileName(file));
                }
            }
        }

        private void ClearFolderDataByPath(string willClearFolder)
        {
            if (Directory.Exists(willClearFolder))
            {
                string[] files = Directory.GetFiles(willClearFolder);
                string[] dirs = Directory.GetDirectories(willClearFolder);

                foreach (string file in files)
                {
                    File.Delete(file);
                }

                foreach (string file in dirs)
                {
                    Directory.Delete(file, true);
                }
            }
            else
            {
                Directory.CreateDirectory(willClearFolder);
            }
        }

        private List<string> GetIntrofolderListByPath(string tempIntroFolder)
        {
            List<string> result = new List<string>();
            List<string> routeList = new List<string>();

            if (Directory.Exists(tempIntroFolder))
            {
                routeList.AddRange(Directory.GetDirectories(tempIntroFolder));

                foreach (string item in routeList)
                {
                    result.Add(Path.GetFileNameWithoutExtension(item) + @"\");
                }
            }

            return result;
        }

        private void UpdateAboutFunctionbySource(string sourceFolder)
        {
            // 更新圖片 : 整個刪掉, 整個搬
            if (Directory.Exists(sourceFolder))
            {
                string targetDirectoryPath = Path.Combine(dataPath, "About");
                if (Directory.Exists(targetDirectoryPath))
                {
                    Directory.Delete(targetDirectoryPath, true);
                }

                //MoveDirectoryDirect(sourceFolder + Global.GlobalFunction.enviromentFolderName + Global.GlobalFunction.enviromentImageFolderName,
                //    Global.GlobalFunction.dataFolderPath + Global.GlobalFunction.enviromentFolderName + Global.GlobalFunction.enviromentImageFolderName);
                MoveDirectoryDirect(sourceFolder,
                    targetDirectoryPath);
            }
        }

        private void UpdateFrontPageFunctionbySource(string sourceFolder)
        {
            if (Directory.Exists(sourceFolder))
            {
                string targetDirectoryPath = Path.Combine(dataPath, "FrontPage");
                if (Directory.Exists(targetDirectoryPath))
                {
                    Directory.Delete(targetDirectoryPath, true);
                }

                MoveDirectoryDirect(sourceFolder,
                    targetDirectoryPath);
            }
        }

        private void UpdateHistoryWallFunctionBySource(string sourceFolder, PageType pageType)
        {
            string historySettingFolder = @"Setting\";
            string historyConfigJsonName = "ConfigSetting.ini";
            string historyInfoFolder = @"HistoryWallData\";
            string historyEventJsonName = "HistoryFile.ini";
            string historyThumbFolder = @"Thumb\";
            string historyImgFolder = @"HistoryImage\";

            // 該資料夾包含 HistoryWallData, HistoryImage, Setting, Thumb 四個資料夾
            // 1. 更新 ini
            if (File.Exists(Path.Combine(sourceFolder, historySettingFolder, historyConfigJsonName)))
            {
                MoveFileDirect(Path.Combine(sourceFolder, historySettingFolder, historyConfigJsonName),
                    Path.Combine(dataPath, PageFolderName[pageType], historySettingFolder, historyConfigJsonName));
            }

            if (File.Exists(Path.Combine(sourceFolder, historyInfoFolder, historyEventJsonName)))
            {
                MoveFileDirect(Path.Combine(sourceFolder, historyInfoFolder, historyEventJsonName),
                    Path.Combine(dataPath, PageFolderName[pageType], historyInfoFolder, historyEventJsonName));
            }

            // 更新 bg 及 logo
            if (Directory.Exists(Path.Combine(sourceFolder, historyThumbFolder)))
            {
                string[] files = Directory.GetFiles(Path.Combine(sourceFolder, historyThumbFolder));

                foreach (string file in files)
                {
                    MoveFileDirect(file, Path.Combine(dataPath, PageFolderName[pageType], historyThumbFolder, System.IO.Path.GetFileName(file)));
                    //Global.GlobalFunction.dataFolderPath + Global.GlobalFunction.historyFolder + Global.GlobalFunction.historyThumbFolder + System.IO.Path.GetFileName(file));
                }
            }

            // 更新圖片 : 整個刪掉, 整個搬
            if (Directory.Exists(Path.Combine(sourceFolder, historyImgFolder)))
            {
                //if (Directory.Exists(Global.GlobalFunction.dataFolderPath + Global.GlobalFunction.historyFolder + Global.GlobalFunction.historyImgFolder))
                //{
                //    Directory.Delete(Global.GlobalFunction.dataFolderPath + Global.GlobalFunction.historyFolder + Global.GlobalFunction.historyImgFolder, true);
                //}
                string imgFolderPath = Path.Combine(dataPath, PageFolderName[pageType], historyImgFolder);
                if (Directory.Exists(imgFolderPath))
                {
                    Directory.Delete(imgFolderPath, true);
                }

                MoveDirectoryDirect(Path.Combine(sourceFolder, historyImgFolder),
                    imgFolderPath);
            }
        }

        private void UpdateImageFunctionBySource(string sourceFolder)
        {
            // 更新圖片 : 整個刪掉, 整個搬
            if (Directory.Exists(sourceFolder))
            {
                string targetDirectoryPath = Path.Combine(dataPath, "Image");
                if (Directory.Exists(targetDirectoryPath))
                {
                    Directory.Delete(targetDirectoryPath, true);
                }

                MoveDirectoryDirect(sourceFolder, targetDirectoryPath);
            }
        }

        private void UpdatePPTFunctionBySource(string sourceFolder)
        {
            // 更新圖片 : 整個刪掉, 整個搬
            if (Directory.Exists(sourceFolder))
            {
                string targetDirectoryPath = Path.Combine(dataPath, "PPT");
                if (Directory.Exists(targetDirectoryPath))
                {
                    Directory.Delete(targetDirectoryPath, true);
                }

                MoveDirectoryDirect(sourceFolder, targetDirectoryPath);
            }
        }

        private bool MoveFileCheck()
        {
            bool result = true;

            try
            {
                string tempDataPath = Path.Combine(tempFolderPath, "Data");
                if (Directory.Exists(tempDataPath))
                {
                    string checkPath;

                    checkPath = Path.Combine(tempDataPath, "setting.ini");
                    if (File.Exists(checkPath))
                    {
                        MoveFileDirect(checkPath, Path.Combine(dataPath, "setting.ini"));
                    }
                    checkPath = Path.Combine(tempDataPath, "FrontPage");
                    if (Directory.Exists(checkPath))
                    {
                        UpdateFrontPageFunctionbySource(checkPath);
                    }

                    checkPath = Path.Combine(tempDataPath, "History");
                    if (Directory.Exists(checkPath))
                    {
                        UpdateHistoryWallFunctionBySource(checkPath, PageType.History);
                    }
                    checkPath = Path.Combine(tempDataPath, "Product");
                    if (Directory.Exists(checkPath))
                    {
                        UpdateHistoryWallFunctionBySource(checkPath, PageType.Product);
                    }
                    checkPath = Path.Combine(tempDataPath, "CSR");
                    if (Directory.Exists(checkPath))
                    {
                        UpdateHistoryWallFunctionBySource(checkPath, PageType.CSR);
                    }
                }
                else
                {
                    result = false;
                }
            }
            catch (Exception e)
            {
                result = false;
            }

            return result;
        }

        private void CreateSocketFunction()
        {
            DetectTempFolder();

            //取得IP 與 Port
            kioskIP = Properties.Settings.Default["SocketIP"].ToString();
            kioskPort = int.Parse(Properties.Settings.Default["SocketPort"].ToString());

            socketServer = new SocketServer(kioskIP, kioskPort, tempFolder);
            socketServer.ReceiveSegmentFileFinish += new ReceiveSegmentFileFinishHandler(socketServer_ReceiveSegmentFileFinish);
            socketServer.ReceiveFileFail += new ReceiveFileFailHandler(socketServer_ReceiveFileFail);
            socketServer.StartListen();
        }

        #region socket 後臺通知
        private void socketServer_ReceiveFileFail()
        {
            socketServer.StopListen();
            socketServer.Close();
            socketServer = null;
            CreateSocketFunction();
        }

        private void socketServer_ReceiveSegmentFileFinish(string file)
        {
            if (socketServer.FileReceiveCount == socketServer.FileTransferCount)
            {
                //當前取的檔案數量
                updateFileCount = socketServer.FileTransferCount;
                //合併~解壓縮~
                unzipWorker = new BackgroundWorker();
                unzipWorker.WorkerSupportsCancellation = true;
                unzipWorker.DoWork += new DoWorkEventHandler(unzipWorker_DoWork);
                unzipWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(unzipWorker_RunWorkerCompleted);
                unzipWorker.RunWorkerAsync();
            }
        }
        #endregion

        private void DetectTempFolder()
        {
            if (Directory.Exists(tempFolder))
            {
                //刪除子資料夾
                foreach (string d in Directory.GetDirectories(tempFolder))
                {
                    System.IO.Directory.Delete(d, true);
                }
            }
            else
            {
                Directory.CreateDirectory(tempFolder);
            }
        }

        private bool MergerFileToZip()
        {
            bool result = false;
            int index = 1;
            int datas = 0;
            int bufferSize = 1048576;
            FileStream fileStream = File.OpenWrite(tempFolder + @"/" + zipName);
            byte[] binaryData = new byte[bufferSize];

            while (File.Exists(String.Format(segmentsFilePath, index.ToString())))
            {
                string curFilePath = String.Format(segmentsFilePath, index.ToString());
                {
                    FileStream fs = File.OpenRead(curFilePath);
                    datas = fs.Read(binaryData, 0, bufferSize);
                    while (datas > 0)
                    {
                        fileStream.Write(binaryData, 0, datas);
                        datas = fs.Read(binaryData, 0, bufferSize);
                    }

                    fs.Flush();
                    fs.Close();
                    //計數當前 .cut 數量
                    index++;
                }
            }

            fileStream.Flush();
            fileStream.Close();


            if (updateFileCount == index - 1)
            {
                //完整合併
                result = true;
            }

            return result;
        }

        private void DecompressFile()
        {
            //解壓縮
            using (ZipInputStream s = new ZipInputStream(File.OpenRead(tempFolder + "/" + zipName)))
            {
                ZipEntry theEntry;
                while ((theEntry = s.GetNextEntry()) != null)
                {
                    string filePath = tempFolder + "/" + theEntry.Name;
                    if (!Directory.Exists(System.IO.Path.GetDirectoryName(filePath)))
                    {
                        Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filePath));
                    }
                    if (filePath != String.Empty)
                    {
                        using (FileStream streamWriter = File.Create(filePath))
                        {
                            int size = 2048;
                            byte[] data = new byte[2048];
                            while (true)
                            {
                                size = s.Read(data, 0, data.Length);
                                if (size > 0)
                                {
                                    streamWriter.Write(data, 0, size);
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        private void DeleteZipAndCutFile()
        {
            string[] fileList = Directory.GetFiles(tempFolder);

            foreach (string filename in fileList)
            {
                if (File.Exists(filename))
                {
                    File.Delete(filename);
                }
            }
        }
    }
}
