private void TryInitFileWatcher(SyncState ss)
        {
            Debug.WriteLine($"TryInitFileWatcher('{ss.Config.Source}')");

            if (ss.Watcher != null)
            {
                ss.Watcher.EnableRaisingEvents = false;
            }

            try
            {
                ss.Watcher = new FileSystemWatcher(Path.GetDirectoryName(ss.Config.Source));
            }
            catch (ArgumentException e)
            {
                Debug.WriteLine($"TryInitFileWatcher->Postpone({e.GetType().Name}, {e.Message})");
                ss.Watcher = null;
                ss.WatcherInitPostponed = true;
                return;
            }

            ss.WatcherInitPostponed = false;

            ss.Watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.CreationTime;
            ss.Watcher.Changed     += (ps, pe) =>
            {
                Debug.WriteLine($"FileWatcher->Changed({pe.FullPath})");
                if (Path.GetFullPath(ss.Config.Source) == Path.GetFullPath(pe.FullPath))
                {
                    Debug.WriteLine($"FileWatcher->Changed->Done({ss.Config.Source})");
                    ForceSyncSingle(ss.Config.Source);
                }
            };
            ss.Watcher.Created += (ps, pe) =>
            {
                Debug.WriteLine($"FileWatcher->Created({pe.FullPath})");
                if (Path.GetFullPath(ss.Config.Source) == Path.GetFullPath(pe.FullPath))
                {
                    Debug.WriteLine($"FileWatcher->Changed->Done({ss.Config.Source})");
                    ForceSyncSingle(ss.Config.Source);
                }
            };
            ss.Watcher.EnableRaisingEvents = true;
        }
        private bool ShouldSync(SyncState entry)
        {
            if (entry.Config.Comparison == CompareMode.ALWAYS)
            {
                return(true);
            }

            if (entry.Config.Comparison == CompareMode.FILETIME)
            {
                var mt1 = File.GetLastWriteTime(entry.Config.Source);
                var mt2 = File.GetLastWriteTime(entry.Config.Target);
                return(!mt1.Equals(mt2));
            }

            if (entry.Config.Comparison == CompareMode.CHECKSUM)
            {
                var cs1 = Hash(entry.Config.Source);
                var cs2 = Hash(entry.Config.Target);

                return(cs1 != cs2);
            }

            return(false);
        }
        private bool DoSyncSingle(SyncState entry)
        {
            Debug.WriteLine($"DoSyncSingle({entry.Config.Target})");

            try
            {
                if (!File.Exists(entry.Config.Source))
                {
                    if (entry.Config.ModeSourceNotFound == ErrorMode.ERROR)
                    {
                        entry.State = SyncStateEnum.ERROR;
                    }
                    else if (entry.Config.ModeSourceNotFound == ErrorMode.WARN)
                    {
                        entry.State = SyncStateEnum.WARNING;
                    }
                    else if (entry.Config.ModeSourceNotFound == ErrorMode.IGNORE)
                    {
                        entry.State = SyncStateEnum.OK;
                    }

                    Debug.WriteLine($"DoSyncSingle->FileNotFound()");

                    return(true);
                }

                if (entry.Config.UseFilewatcher && entry.WatcherInitPostponed)
                {
                    Debug.WriteLine($"DoSyncSingle->InitFileWatcher()");
                    TryInitFileWatcher(entry);
                }

                if (ShouldSync(entry))
                {
                    Debug.WriteLine($"DoSyncSingle->Copy({entry.Config.Target})");
                    try
                    {
                        File.Copy(entry.Config.Source, entry.Config.Target, true);
                    }
                    catch (Exception e)
                    {
                        if (entry.Config.ModeCopyFail == ErrorMode.ERROR)
                        {
                            entry.State = SyncStateEnum.ERROR;
                        }
                        if (entry.Config.ModeCopyFail == ErrorMode.WARN)
                        {
                            entry.State = SyncStateEnum.WARNING;
                        }
                        if (entry.Config.ModeCopyFail == ErrorMode.IGNORE)
                        {
                            entry.State = SyncStateEnum.OK;
                        }

                        Debug.WriteLine($"DoSyncSingle->CopyException({e.GetType().Name}, {e.Message})");
                        return(true);
                    }
                    entry.LastCopy = DateTime.Now;
                    entry.State    = SyncStateEnum.OK;
                    return(true);
                }

                entry.State = SyncStateEnum.OK;
                return(false);
            }
            catch (Exception e)
            {
                Debug.WriteLine($"DoSyncSingle->Exception({e.GetType().Name}, {e.Message})");

                entry.State = SyncStateEnum.ERROR;
                return(true);
            }
        }