// Full fidelity read-write

        public static CanvasDocument LoadFromSource(string directory2, ErrorContainer errors)
        {
            if (File.Exists(directory2))
            {
                if (directory2.EndsWith(".msapp", StringComparison.OrdinalIgnoreCase))
                {
                    throw new ArgumentException($"Must point to a source directory, not an msapp file ({directory2}");
                }
            }

            if (!Directory.Exists(directory2))
            {
                throw new InvalidOperationException($"No directory {directory2}");
            }
            var dir = new DirectoryReader(directory2);
            var app = new CanvasDocument();

            // Do the manifest check (and version check) first.
            // MAnifest lives in top-level directory.
            foreach (var file in dir.EnumerateFiles("", "*.json"))
            {
                switch (file.Kind)
                {
                case FileKind.CanvasManifest:
                    var manifest = file.ToObject <CanvasManifestJson>();

                    if (manifest.FormatVersion != CurrentSourceVersion)
                    {
                        errors.FormatNotSupported($"This tool only supports {CurrentSourceVersion}, the manifest version is {manifest.FormatVersion}");
                        throw new DocumentException();
                    }

                    app._properties  = manifest.Properties;
                    app._header      = manifest.Header;
                    app._publishInfo = manifest.PublishInfo;
                    app._screenOrder = manifest.ScreenOrder;
                    break;

                case FileKind.Templates:
                    foreach (var kvp in file.ToObject <Dictionary <string, CombinedTemplateState> >())
                    {
                        app._templateStore.AddTemplate(kvp.Key, kvp.Value);
                    }
                    break;

                case FileKind.ComponentReferences:
                    var refs = file.ToObject <ComponentDependencyInfo[]>();
                    app._libraryReferences = refs;
                    break;
                }
            }
            if (app._header == null)
            {
                // Manifest not found.
                errors.FormatNotSupported($"Can't find CanvasManifest.json file - is sources an old version?");
                throw new DocumentException();
            }

            // Load template files, recreate References/templates.json
            LoadTemplateFiles(errors, app, Path.Combine(directory2, PackagesDir), out var templateDefaults);

            foreach (var file in dir.EnumerateFiles(AssetsDir))
            {
                if (file._relativeName == "Resources.json")
                {
                    app._resourcesJson = file.ToObject <ResourcesJson>();
                    continue;
                }
                app.AddAssetFile(file.ToFileEntry());
            }

            foreach (var file in dir.EnumerateFiles(EntropyDir))
            {
                switch (file.Kind)
                {
                case FileKind.Entropy:
                    app._entropy = file.ToObject <Entropy>();
                    break;

                case FileKind.AppCheckerResult:
                    app._appCheckerResultJson = file.ToObject <AppCheckerResultJson>();
                    break;

                case FileKind.Checksum:
                    app._checksum = file.ToObject <ChecksumJson>();
                    app._checksum.ClientBuildDetails = _buildVerJson;
                    break;

                default:
                    errors.GenericWarning($"Unexpected file in Entropy, discarding");
                    break;
                }
            }


            foreach (var file in dir.EnumerateFiles(OtherDir))
            {
                // Special files like Header / Properties
                switch (file.Kind)
                {
                case FileKind.Unknown:
                    // Track any unrecognized files so we can save back.
                    app.AddFile(file.ToFileEntry());
                    break;

                default:
                    // Shouldn't find anything else not unknown in here, but just ignore them for now
                    errors.GenericWarning($"Unexpected file in Other, discarding");
                    break;
                }
            } // each loose file in '\other'


            app.GetLogoFile();

            LoadDataSources(app, dir, errors);
            LoadSourceFiles(app, dir, templateDefaults, errors);

            foreach (var file in dir.EnumerateFiles(ConnectionDir))
            {
                // Special files like Header / Properties
                switch (file.Kind)
                {
                case FileKind.Connections:
                    app._connections = file.ToObject <IDictionary <string, ConnectionJson> >();
                    break;
                }
            }


            // Defaults.
            // - DynamicTypes.Json, Resources.Json , Templates.Json - could all be empty
            // - Themes.json- default to


            app.OnLoadComplete(errors);

            return(app);
        }
        // Full fidelity read-write

        public static CanvasDocument LoadFromSource(string directory2, ErrorContainer errors)
        {
            if (File.Exists(directory2))
            {
                if (directory2.EndsWith(".msapp", StringComparison.OrdinalIgnoreCase))
                {
                    errors.BadParameter($"Must point to a source directory, not an msapp file ({directory2}");
                }
            }

            Utilities.VerifyDirectoryExists(errors, directory2);

            if (errors.HasErrors)
            {
                return(null);
            }

            var    dir = new DirectoryReader(directory2);
            var    app = new CanvasDocument();
            string appInsightsInstumentationKey = null;

            // Do the manifest check (and version check) first.
            // MAnifest lives in top-level directory.
            foreach (var file in dir.EnumerateFiles("", "*.json"))
            {
                switch (file.Kind)
                {
                case FileKind.CanvasManifest:
                    var manifest = file.ToObject <CanvasManifestJson>();

                    if (manifest.FormatVersion != CurrentSourceVersion)
                    {
                        errors.FormatNotSupported($"This tool only supports {CurrentSourceVersion}, the manifest version is {manifest.FormatVersion}");
                        throw new DocumentException();
                    }

                    app._properties  = manifest.Properties;
                    app._header      = manifest.Header;
                    app._publishInfo = manifest.PublishInfo;
                    app._screenOrder = manifest.ScreenOrder;
                    break;

                case FileKind.Templates:
                    foreach (var kvp in file.ToObject <Dictionary <string, CombinedTemplateState> >())
                    {
                        app._templateStore.AddTemplate(kvp.Key, kvp.Value);
                    }
                    break;

                case FileKind.ComponentReferences:
                    var refs = file.ToObject <ComponentDependencyInfo[]>();
                    app._libraryReferences = refs;
                    break;

                case FileKind.AppInsightsKey:
                    var appInsights = file.ToObject <AppInsightsKeyJson>();
                    appInsightsInstumentationKey = appInsights.InstrumentationKey;
                    break;
                }
            }
            if (appInsightsInstumentationKey != null)
            {
                app._properties.InstrumentationKey = appInsightsInstumentationKey;
            }
            if (app._header == null)
            {
                // Manifest not found.
                errors.FormatNotSupported($"Can't find CanvasManifest.json file - is sources an old version?");
                throw new DocumentException();
            }

            // Load template files, recreate References/templates.json
            LoadTemplateFiles(errors, app, Path.Combine(directory2, PackagesDir), out var templateDefaults);

            foreach (var file in dir.EnumerateFiles(EntropyDir))
            {
                switch (file.Kind)
                {
                case FileKind.Entropy:
                    app._entropy = file.ToObject <Entropy>();
                    break;

                case FileKind.AppCheckerResult:
                    app._appCheckerResultJson = file.ToObject <AppCheckerResultJson>();
                    break;

                case FileKind.Checksum:
                    app._checksum = file.ToObject <ChecksumJson>();
                    app._checksum.ClientBuildDetails = _buildVerJson;
                    break;

                default:
                    errors.GenericWarning($"Unexpected file in Entropy, discarding");
                    break;
                }
            }

            // The resource entries for sample data is sharded into individual json files.
            // Add each of these entries back into Resrouces.json
            var resources = new List <ResourceJson>();

            app._resourcesJson = new ResourcesJson()
            {
                Resources = new ResourceJson[0]
            };
            foreach (var file in dir.EnumerateFiles(AssetsDir, "*", false))
            {
                var fileEntry = file.ToFileEntry();
                if (fileEntry.Name.GetExtension() == ".json")
                {
                    // If its a json file then this must be one of the sharded files from Resources.json
                    resources.Add(file.ToObject <ResourceJson>());
                }
            }

            // Add the resources from sharded files to _resourcesJson.Resources
            if (resources.Count > 0)
            {
                app._resourcesJson.Resources = resources.ToArray();
            }

            // We have processed all the json files in Assets directory, now interate through all tge files to add the asset files.
            foreach (var file in dir.EnumerateFiles(AssetsDir))
            {
                // Skip adding the json files which were created to contain the information for duplicate asset files.
                // The name of the such json files is of the format - <assetFileName>.<assetFileExtension>.json (eg. close_1.jpg.json)
                var fileName = file._relativeName;
                var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);

                // Check if the original extension was .json and the remaining file name has still got an extension,
                // Then this is an additional file that was created to contain information for duplicate assets.
                if (Path.HasExtension(fileNameWithoutExtension) && Path.GetExtension(fileName) == ".json")
                {
                    var localAssetInfoJson = file.ToObject <LocalAssetInfoJson>();
                    app._localAssetInfoJson.Add(localAssetInfoJson.NewFileName, localAssetInfoJson);
                }
                // Add non json files to _assetFiles
                else if (Path.GetExtension(fileName) != ".json")
                {
                    app.AddAssetFile(file.ToFileEntry());
                }
            }

            app.GetLogoFile();

            // Add the entries for local assets back to resrouces.json
            TranformResourceJson.AddLocalAssetEntriesToResourceJson(app);

            foreach (var file in dir.EnumerateFiles(OtherDir))
            {
                // Special files like Header / Properties
                switch (file.Kind)
                {
                case FileKind.Unknown:
                    // Track any unrecognized files so we can save back.
                    app.AddFile(file.ToFileEntry());
                    break;

                default:
                    // Shouldn't find anything else not unknown in here, but just ignore them for now
                    errors.GenericWarning($"Unexpected file in Other, discarding");
                    break;
                }
            } // each loose file in '\other'

            LoadDataSources(app, dir, errors);
            LoadSourceFiles(app, dir, templateDefaults, errors);

            foreach (var file in dir.EnumerateFiles(ConnectionDir))
            {
                // Special files like Header / Properties
                switch (file.Kind)
                {
                case FileKind.Connections:
                    app._connections = file.ToObject <IDictionary <string, ConnectionJson> >();
                    break;
                }
            }


            // Defaults.
            // - DynamicTypes.Json, Resources.Json , Templates.Json - could all be empty
            // - Themes.json- default to


            app.OnLoadComplete(errors);

            return(app);
        }