private async Task <object> ParseAsync()
        {
            if (sourcePath.DirectoryAreSame(destinationPath))
            {
                // TODO: implement
                throw new NotSupportedException("TODO");
            }

            OnProgress(this, 0.0, "Parsing source");

            try
            {
                ParseSummary summary = new ParseSummary();
                CopyItems    items   = await ParseItemsAsync(sourcePath, destinationPath, summary);

                dynamic result = new ExpandoObject();
                result.Summary = summary;
                result.Items   = items;
                return(result);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#else
                return(null);
#endif
            }
            finally
            {
                OnProgress(this, PARSE_PROGRESS_FACTOR, "Parsing complete");
            }
        }
        private async Task <CopyItems> ParseItemsAsync(string sourcePath, string destinationPath, ParseSummary summary)
        {
            List <string> ignore = new List <string>();

            if (IgnorePaths != null)
            {
                ignore.AddRange(IgnorePaths);
            }
            if (!sourcePath.DirectoryAreSame(destinationPath))
            {
                ignore.Add(destinationPath);
            }

            IEnumerable <MetaData> data;

            try
            {
                MetaParserConfig config = new MetaParserConfig()
                {
                    Recursive = Recursive, IgnorePaths = ignore
                };
                data = await MetaParser.ParseAsync(sourcePath, config);
            }
            catch (MetaParseException ex)
            {
                throw new MediaOrganizerException("Failed to parse meta data", ex);
            }

            PatternPathParser parser = new PatternPathParser(Locale);

            parser.Preload(data);

            CopyItems items = new CopyItems();

            items.sourcePath      = sourcePath;
            items.destinationPath = destinationPath;

            foreach (MetaData meta in data)
            {
                if (workerAborted)
                {
                    break;
                }

                string path = meta.Path;

                switch (meta.Type)
                {
                case MetaType.Directory:
                    summary.totalDirectories.Add(path);
                    continue;

                case MetaType.File:
                    summary.totalFiles.Add(path);
                    summary.ignored.Add(path);
                    continue;

                default:
                    summary.totalFiles.Add(path);
                    break;
                }

                CopyItem item = ParseItem(parser, destinationPath, meta);
                items.Add(item);
                summary.parsed.Add(path);
            }

            return(items);
        }