/**********************************************************************************************************************/
        public List <Tuple <string, string> > Synchronize(string configPath, int networkRetries, string synchronizerConfigurationPath, bool useNotification, Option <MCADCommon.LogCommon.DisposableFileLogger> logger, ref Option <string> mailFrom)
        {
            bool disposeLog = false;
            List <Tuple <string, string> > filesToMove = new List <Tuple <string, string> >();

            try
            {
                NotifyIcon trayIcon = new NotifyIcon();
                trayIcon.Text           = "Fetching files to synchronize.";
                trayIcon.Icon           = VaultEagleLib.Properties.Resources.Eagle;
                trayIcon.BalloonTipText = "Fetching files to synchronize.";

                ContextMenu trayMenu = new ContextMenu();

                trayIcon.ContextMenu = trayMenu;
                trayIcon.Visible     = true;
                if (useNotification)
                {
                    trayIcon.ShowBalloonTip(4000);
                }
                errors = new List <string>();
                // Fetch configuration file, mail on failure.
                Option <ADSK.File> configurationFile = Option.None;
                string             path;
                logger.IfSomeDo(l => l.Trace("Before downloading configuration."));
                if (synchronizerConfigurationPath.StartsWith("$"))
                {
                    configurationFile = DownloadConfiguration(configPath, networkRetries, synchronizerConfigurationPath, logger, errors);
                    if (configurationFile.IsNone)
                    {
                        return(filesToMove);
                    }
                    path = Path.Combine(configPath, configurationFile.Get().Name);
                }
                else
                {
                    path = Environment.ExpandEnvironmentVariables(synchronizerConfigurationPath);
                }
                logger.IfSomeDo(l => l.Trace("After downloading configuration."));


                VaultEagleLib.SynchronizerSettings configuration = VaultEagleLib.SynchronizerSettings.Read(networkRetries, logger, path);
                if (logger.IsNone && configuration.LogFile.IsSome)
                {
                    logger     = new MCADCommon.LogCommon.DisposableFileLogger(MCADCommon.LogCommon.DisposableFileLogger.CreateLogFilePath(configuration.configPath, configuration.LogFile.Get()), configuration.LogLevel).AsOption();
                    disposeLog = true;
                }

                //   Option<Logg
                //  if (configuration.LogFile.IsSome)
                logger.IfSomeDo(l => l.Info("Synchronizing vault files."));

                // Fetch files to sync, mail on failure.
                //  List<FileFolder> filesAndFoldersToUpdate = /*new List<FileFolder>();*/FetchingFilesFromVaultToSynchronize(ref mailInfo, lastSyncTime, logger, errors, configuration);
                if (configuration.OverrideMailSender.IsSome)
                {
                    mailFrom = configuration.OverrideMailSender;
                }
                /*List<Tuple<ADSK.File, string, bool, bool>>*/ List <VaultEagleLib.Model.DataStructures.DownloadItem> filesToUpdate = FindFilesChangedSinceLastSync(connection, configuration.UseLastSync, configuration.LastSyncTime, configuration.VaultRoot, networkRetries, trayIcon, configuration.Items.ToArray(), logger);

                foreach (VaultEagleLib.SynchronizationItem item in configuration.Items)
                {
                    foreach (Tuple <string, string> tempFileAndFinalPath in item.TempFilesAndFinalPath)
                    {
                        filesToMove.Add(tempFileAndFinalPath);
                    }
                }

                string now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                logger.IfSomeDo(l => l.Info("Synchronizing: " + filesToUpdate.Count + " files."));
                //  if (filesToUpdate.Count > 0)
                {
                    trayIcon.Text = "Downloaded 0 of " + filesToUpdate.Count + " files.";

                    try
                    {
                        errors.AddRange(SynchronizeFiles(networkRetries, logger, errors, configuration, filesToUpdate, trayIcon));
                        List <VaultEagleLib.Model.DataStructures.DownloadFile> downloadedFiles = filesToUpdate.OfType <VaultEagleLib.Model.DataStructures.DownloadFile>().ToList();
                        foreach (string getAndRun in configuration.GetAndRun)
                        {
                            // string test1 = filesToUpdate[filesToUpdate.Count - 1].Item2.Replace(configuration.VaultRoot, "$").Replace("\\", "/") + "/" + filesToUpdate[filesToUpdate.Count - 1].Item1.Name;
                            if (downloadedFiles.Any(f => getAndRun.Equals(f.VaultFileName(configuration.VaultRoot))))
                            {
                                VaultEagleLib.Model.DataStructures.DownloadFile file = downloadedFiles.Where(f => getAndRun.Equals(f.VaultFileName(configuration.VaultRoot))).First();
                                VaultEagle.VaultUtils.HandleNetworkErrors(() =>
                                {
                                    System.Diagnostics.Process proc = new System.Diagnostics.Process();
                                    proc.StartInfo.FileName         = file.LocalFileName;
                                    proc.Start();
                                    proc.WaitForExit();
                                }, networkRetries);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.IfSomeDo(l => l.Error(ex.Message));
                        errors.Add("Failure synchronizing files.");
                    }

                    if (errors.Count == 0 && configuration.LastSyncFile.IsSome)
                    {
                        if (!VaultUtils.HandleNetworkErrors(() => System.IO.Directory.Exists(configuration.configPath), networkRetries))
                        {
                            VaultUtils.HandleNetworkErrors(() => System.IO.Directory.CreateDirectory(configuration.configPath), networkRetries);
                        }

                        if (VaultUtils.HandleNetworkErrors(() => System.IO.File.Exists(Path.Combine(configuration.configPath, configuration.LastSyncFile.Get() + ".txt")), networkRetries))
                        {
                            VaultUtils.HandleNetworkErrors(() => System.IO.File.Delete(Path.Combine(configuration.configPath, configuration.LastSyncFile.Get() + ".txt")), networkRetries);
                        }

                        try
                        {
                            using (TextWriter tw = new StreamWriter(VaultUtils.HandleNetworkErrors(() => System.IO.File.Create(Path.Combine(configuration.configPath, configuration.LastSyncFile.Get() + ".txt")), networkRetries)))
                                tw.WriteLine(now);
                        }
                        catch { }
                    }
                    if (useNotification)
                    {
                        if (errors.Count > 0)
                        {
                            trayIcon.BalloonTipText = "Errors synchronizing files.";
                            if (useNotification)
                            {
                                trayIcon.ShowBalloonTip(2000);
                            }
                        }
                        else
                        {
                            trayIcon.BalloonTipText = "Finished synchronizing files.";
                            if (useNotification)
                            {
                                trayIcon.ShowBalloonTip(2000);
                            }
                        }
                    }
                }
                trayIcon.DisposeUnlessNull(ref trayIcon);
            }
            catch (Exception ex)
            {
                logger.IfSomeDo(l => l.Error(ex.Message));
            }
            logger.IfSomeDo(l => l.Trace("Synchronizing complete."));
            if (disposeLog && logger.IsSome)
            {
                logger.Get().Dispose();
            }


            return(filesToMove);
        }
        private List <string> SynchronizeFiles(int networkRetries, Option <MCADCommon.LogCommon.DisposableFileLogger> logger, List <string> errors, VaultEagleLib.SynchronizerSettings configuration, List <VaultEagleLib.Model.DataStructures.DownloadItem> filesAndFoldersToUpdate, NotifyIcon notify)
        {
            List <string> failedFiles = new List <string>();

            if (filesAndFoldersToUpdate.Count > 0)
            {
                int batchSize     = 1000;
                int maxPageNumber = Convert.ToInt32(Math.Floor(filesAndFoldersToUpdate.Count / (batchSize + 0.0)));
                for (int i = 0; i <= maxPageNumber; i++)
                {
                    IEnumerable <VaultEagleLib.Model.DataStructures.DownloadItem> filesToSynchronize = GetBatch(i, filesAndFoldersToUpdate, batchSize);
                    logger.IfSomeDo(l => l.Trace("Fetched: " + filesToSynchronize.Count() + " files to download."));

                    failedFiles.AddRange(SynchronizeFileBatches(filesToSynchronize.ToList(), configuration.Items.ToArray(), logger, networkRetries));

                    notify.Text = "downloaded " + (i * batchSize).ToString() + " of " + filesAndFoldersToUpdate.Count + " files.";// +" synchronized files of " + filesAndFoldersToUpdate.Count.ToString() + ".";
                    logger.IfSomeDo(l => l.Info(filesToSynchronize.Count() + " files downloaded."));
                }
            }
            foreach (VaultEagleLib.SynchronizationItem item in configuration.Items)
            {
                item.DeleteFiles(configuration.VaultRoot, networkRetries);
                item.MirrorFolders(configuration.VaultRoot, networkRetries);
                item.RunFiles(configuration.VaultRoot, filesAndFoldersToUpdate.OfType <VaultEagleLib.Model.DataStructures.DownloadFile>().ToList(), networkRetries);
                item.CreateEmptyFolders(configuration.VaultRoot, networkRetries);
            }
            return(failedFiles);
        }
        public static SynchronizerSettings Read(int networkRetries, Option <MCADCommon.LogCommon.DisposableFileLogger> logger, string configurationPath = "")
        {
            SynchronizerSettings configuration = new SynchronizerSettings();
            FileInfo             configurationFile;

            if (!String.IsNullOrWhiteSpace(configurationPath))
            {
                configurationFile = new FileInfo(configurationPath);
            }
            else
            {
                configurationFile = ConfigurationFile;
            }

            if (!configurationFile.Exists)
            {
                configurationFile = new FileInfo(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), configurationPath));
            }

            if (configurationFile.Exists)
            {
                XmlDocument document = new XmlDocument();
                document.Load(configurationFile.FullName);

                configuration.configPath = Environment.ExpandEnvironmentVariables(MCAD.XmlCommon.XmlTools.ReadString(document.DocumentElement, "configuration_path"));

                try
                {
                    configuration.GetAndRun = MCAD.XmlCommon.XmlTools.ReadStringValues(document.DocumentElement, "run_files", "get_and_run");
                }
                catch
                {
                    configuration.GetAndRun = new List <string>();
                }
                configuration.VaultRoot = Environment.ExpandEnvironmentVariables(MCAD.XmlCommon.XmlTools.ReadString(document.DocumentElement, "vault_root"));
                List <SynchronizationItem> items = new List <SynchronizationItem>();
                foreach (string syncItem in MCAD.XmlCommon.XmlTools.ReadStringValues(document.DocumentElement, "synchronization_commands", "synchronization_command"))
                {
                    try
                    {
                        items.Add(SynchronizationItem.ReadString(syncItem));
                    }
                    catch (Exception ex) { logger.IfSomeDo(l => l.Error(ex.Message)); }
                }

                List <SynchronizationItem> RemoveItemsNotLegal = new List <SynchronizationItem>();
                foreach (SynchronizationItem item in items)
                {
                    try
                    {
                        if (!item.HasIllegalItems(configuration.VaultRoot))
                        {
                            RemoveItemsNotLegal.Add(item);
                        }
                    }
                    catch (Exception ex) { logger.IfSomeDo(l => l.Error(ex.Message)); }
                }



                configuration.Items = RemoveItemsNotLegal;

                configuration.LastSyncFile = MCAD.XmlCommon.XmlTools.SafeReadString(document.DocumentElement, "last_sync_file");
                configuration.UseLastSync  = false;
                if ((configuration.LastSyncFile.IsSome) && (VaultEagle.VaultUtils.HandleNetworkErrors(() => File.Exists(Path.Combine(configuration.configPath, configuration.LastSyncFile.Get() + ".txt")), networkRetries)))
                {
                    configuration.UseLastSync = true;
                    try { configuration.LastSyncTime = DateTime.ParseExact(VaultEagle.VaultUtils.HandleNetworkErrors(() => File.ReadLines(Path.Combine(configuration.configPath, configuration.LastSyncFile.Get() + ".txt")).First(), networkRetries), "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture); }
                    catch { configuration.LastSyncTime = DateTime.ParseExact("1990-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture); }
                }
                else
                {
                    configuration.LastSyncTime = DateTime.ParseExact("1990-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
                }

                configuration.OverrideMailSender = MCAD.XmlCommon.XmlTools.SafeReadString(document.DocumentElement, "override_mail_sender");
                configuration.LogLevel           = MCADCommon.LogCommon.Utils.ParseLogLevel(MCAD.XmlCommon.XmlTools.SafeReadString(document.DocumentElement, "log_level").IsSome ? MCAD.XmlCommon.XmlTools.ReadString(document.DocumentElement, "log_level") : "Info");
                configuration.LogFile            = MCAD.XmlCommon.XmlTools.SafeReadString(document.DocumentElement, "log_name");
                try
                {
                    configuration.SavedLogCount = MCAD.XmlCommon.XmlTools.SafeReadString(document.DocumentElement, "saved_log_count").IsSome ? Convert.ToInt32(MCAD.XmlCommon.XmlTools.ReadString(document.DocumentElement, "saved_log_count")) : 60;
                }
                catch
                {
                    configuration.SavedLogCount = 60;
                }
            }
            else
            {
                configuration.configPath = "";
            }

            return(configuration);
        }