public static IEnumerable<ImageJob> ProcessImageJobs(ImageJobs imageJobs)
 {
     return imageJobs
             .Images
             .Select(TryProcessImageJob)
             .SelectWhereValueExist(i => i);
 }
 /// <summary>
 /// Culls the deleted snapshots from ImageJobs and produces a new ImageJobs object
 /// with the remaining snapshots
 /// </summary>
 /// <param name="oldImageJobs">The old ImageJobs object</param>
 /// <param name="remainingSnapshots">The path to all of the remaining snapshots</param>
 /// <returns>A new ImageJobs object</returns>
 public static ImageJobs CoalesceDeletedSnapshots(
     ImageJobs oldImageJobs,
     IEnumerable<string> remainingSnapshots
     )
 {
     var setOfRemainingSnapshots = new HashSet<string>(remainingSnapshots);
     var newImageJobs = oldImageJobs.Images.Select(s => ProcessImageJob(s, setOfRemainingSnapshots));
     return new ImageJobs
     {
         Images = newImageJobs.ToArray(),
     };
 }
        /// <summary>
        /// Harvest all of the possible images for a given ImageJob
        /// </summary>
        /// <param name="imageJobs">The old ImageJobs object</param>
        /// <param name="mediaFilePaths">The path to every single media file</param>
        /// <returns>An new ImageJobs object with paths to the snapshots for every ImageJob</returns>
        public static ImageJobs HarvestCandidateImages(
            ImageJobs imageJobs,
            IEnumerable<string> mediaFilePaths
            )
        {
            IDictionary<TimeSpan, ImageJobGroup> imageGroups = ImageJobGrouper.GroupImageJobs(imageJobs);
            IDictionary<ImageJobGroup, IEnumerable<string>> mapFromGroupsToSnapshots =
                imageGroups.AsParallel().ToDictionary(kvp => kvp.Value, kvp => TakeSnapshots(kvp.Value, mediaFilePaths));

            return new ImageJobs
            {
                Images = UpdateImageJobs(mapFromGroupsToSnapshots).ToArray(),
            };
        }
        /// <summary>
        /// Delete the snapshots that are referenced in <paramref name="oldImageJobs"/> but
        /// not in <paramref name="newImageJobs"/>
        /// </summary>
        /// <param name="oldImageJobs">The old image job</param>
        /// <param name="newImageJobs">The new image job</param>
        public static void DeleteUnusedSnapshots(ImageJobs oldImageJobs, ImageJobs newImageJobs)
        {
            IEnumerable<string> masterSetOfFiles = from imageJob in oldImageJobs.Images
                                                   from snapshot in imageJob.ImageSnapshots
                                                   select snapshot;

            IEnumerable<string> snapshotsToKeep = from imageJob in newImageJobs.Images
                                                  from snapshot in imageJob.ImageSnapshots
                                                  select snapshot;

            var filesToRemove = masterSetOfFiles.Except(snapshotsToKeep);
            foreach (var fileToRemove in filesToRemove)
            {
                File.Delete(fileToRemove);
            }
        }
        /// <summary>
        /// Main method that executes on startup 
        /// </summary>
        /// <param name="args"></param>
        public static void Main(string[] args)
        {
            var imageJobs = CommonFunctions.TryReadStandardIn();
            if (imageJobs.IsNothing())
            {
                PrintHelp();
                return;
            }
            var processedImageJobs = ScrapeJobProcessor.ProcessImageJobs(imageJobs.Value);
            var newImageModel = new ImageJobs
            {
                Images = processedImageJobs.ToArray(),
            };

            Console.WriteLine(JsonConvert.SerializeObject(newImageModel));
            CommonFunctions.CloseAllStandardFileHandles();
        }
        public static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                PrintHelp();
                return;
            }

            IEnumerable<ImageSliceContext> processedSlices = ImageProcessor.ProcessFiles(args);
            IEnumerable<Maybe<ImageJob>> imageJobsMaybe = processedSlices.Select(Convert);
            var imageJobs = new ImageJobs
            {
                Images = imageJobsMaybe.SelectWhereValueExist(t => t).ToArray(),
            };
            Console.WriteLine(JsonConvert.SerializeObject(imageJobs, Formatting.None));

            CommonFunctions.CloseAllStandardFileHandles();
        }
        private static ImageJobs ShiftAllJobs(ImageJobs oldImageJobs, int secondsToShift)
        {
            var shiftedImageJobList = new List<ImageJob>();
            foreach (ImageJob job in oldImageJobs.Images)
            {
                shiftedImageJobList.Add(new ImageJob
                {
                    ImageSnapshots = job.ImageSnapshots,
                    OriginalFilePath = job.OriginalFilePath,
                    SliceImagePath = job.SliceImagePath,
                    SnapshotTimestamp = job.SnapshotTimestamp + new TimeSpan(0, 0, secondsToShift),
                });
            }

            return new ImageJobs
            {
                Images = shiftedImageJobList.ToArray(),
            };
        }
        /// <summary>
        /// The main function that executes for the Match process
        /// </summary>
        /// <param name="args"></param>
        public static void Main(string[] args)
        {
            Maybe<ImageJobs> imageJobsMaybe = CommonFunctions.TryReadStandardIn();
            if (imageJobsMaybe.IsNothing())
            {
                PrintHelp();
                return;
            }

            using (new TimingToken("Match", true))
            {
                IDictionary<ImageJob, IEnumerable<string>> jobToSnapshotMap = ImageMatcher.GetMatches(imageJobsMaybe.Value);
                ImageJob[] processedJobs = UpdateSnapshotResults(jobToSnapshotMap).ToArray();
                var processedImageJobs = new ImageJobs
                {
                    Images = processedJobs,
                };

                SnapshotDeleter.DeleteUnusedSnapshots(imageJobsMaybe.Value, processedImageJobs);
                Console.WriteLine(JsonConvert.SerializeObject(processedImageJobs));
            }
            CommonFunctions.CloseAllStandardFileHandles();
        }
        /// <summary>
        /// Groups ImageJobs by their timestamp 
        /// </summary>
        /// <param name="imageJobs">The ImageJobs object containing all of the individual ImageJob(s)</param>
        /// <returns>A map between timestamps and ImageJobGroups</returns>
        public static IDictionary<TimeSpan, ImageJobGroup> GroupImageJobs(ImageJobs imageJobs)
        {
            var groups = new Dictionary<TimeSpan, ImageJobGroup>();
            foreach (var imageJob in imageJobs.Images)
            {
                var focusTimeSpan = imageJob.SnapshotTimestamp;
                ImageJobGroup group;
                if (groups.TryGetValue(focusTimeSpan, out group) == false)
                {
                    group = new ImageJobGroup
                    {
                        Jobs = new HashSet<ImageJob>(),
                        Timestamp = focusTimeSpan,
                    };

                    groups.Add(focusTimeSpan, group);
                }

                group.Jobs.Add(imageJob);
            }

            return groups;
        }
 /// <summary>
 /// Detects the best matching snapshot for an ImageJob
 /// </summary>
 /// <param name="imageJobs">The ImageJobs to match</param>
 /// <returns>A dictionary between an ImageJob its matching snapshot</returns>
 public static IDictionary<ImageJob, IEnumerable<string>> GetMatches(ImageJobs imageJobs)
 {
     return imageJobs.Images.ToDictionary(i => i, TryFindMatchingSnapshots);
 }
        private async static Task<string> ProcessImageJobAsync(ImageJob imageJob, string folderOfMediaFiles)
        {
            var newImageJobs = new ImageJobs
            {
                Images = new[] { imageJob },
            };

            var serializedNewImageJobs = JsonConvert.SerializeObject(newImageJobs);

            using (var rip = new GeneralProcess(RIP, string.Format("\"{0}\"", folderOfMediaFiles)))
            {
                using (var dedup = new GeneralProcess(DEDUP))
                {
                    using (var match = new GeneralProcess(MATCH))
                    {
                        string ripOutput = await rip.ExecuteAsync(serializedNewImageJobs.ToMaybe());
                        string dedupOutput = await dedup.ExecuteAsync(ripOutput.ToMaybe());
                        string matchOutput = await match.ExecuteAsync(dedupOutput.ToMaybe());
                        MoveCompletedPhotos(matchOutput);
                        return matchOutput;
                    }
                }
            }
        }
 private static IEnumerable<string> GetAllImagePaths(ImageJobs imageJobs)
 {
     return new HashSet<string>(imageJobs.Images.SelectMany(s => s.ImageSnapshots));
 }
 /// <summary>
 /// Load all of the images from disk and resize them
 /// </summary>
 /// <param name="imageJobs"></param>
 /// <returns></returns>
 public static IEnumerable<SnapshotContext> LoadSnapshots(ImageJobs imageJobs)
 {
     return GetAllImagePaths(imageJobs)
         .Select(TryLoadSnapshot)
         .SelectWhereValueExist(i => i);
 }