private TResult GetSubstitutions <TResult>(ResourceInfo resourceInfo,
                                                   Func <IDictionary <string, string>, TResult> onSuccess,
                                                   Func <TResult> onError)
        {
            try
            {
                var subs = new Dictionary <string, string>
                {
                    { "{{resource_name}}", resourceInfo.ResourceName },
                    { "{{resource_name_plural}}", resourceInfo.ResourceNamePlural },
                    { "{{resource_name_variable}}", resourceInfo.ResourceNameVariable },
                    { "{{project_namespace_api}}", resourceInfo.APIProjectName },
                    { "{{project_namespace_business}}", resourceInfo.BusinessProjectName },
                    { "{{project_namespace_persistence}}", resourceInfo.PersistenceProjectName },
                    { "{{project_namespace_test}}", resourceInfo.APITestProjectName },
                };

                subs.Add("{{api_resource_definition}}", GetResourceDefinition(resourceInfo));
                subs.Add("{{persistence_document_definition}}", GetDocumentDefinition(resourceInfo));

                subs.Add("{{api_webid_validation}}", GetAPIWebIdValidation(resourceInfo));
                subs.Add("{{api_webid_params}}", GetAPIWebIdParams(resourceInfo));
                subs.Add("{{api_create_params}}", GetAPICreateParams(resourceInfo));
                subs.Add("{{api_getresponse_params}}", GetAPIGetResponseParams(resourceInfo));
                subs.Add("{{api_update_params}}", GetAPIUpdateParams(resourceInfo));

                subs.Add("{{business_create_params_with_types_ids}}", GetBusinessCreateParamsWithTypesIds(resourceInfo));
                subs.Add("{{business_create_params_with_types}}", GetBusinessCreateParamsWithTypes(resourceInfo));
                subs.Add("{{business_create_params_ids}}", GetBusinessCreateParamsIds(resourceInfo));
                subs.Add("{{business_create_params}}", GetBusinessCreateParams(resourceInfo));
                subs.Add("{{business_update_params}}", GetBusinessUpdateParams(resourceInfo));
                subs.Add("{{business_update_params_all}}", GetBusinessUpdateParamsAll(resourceInfo));
                subs.Add("{{business_update_params_id}}", GetBusinessUpdateParamsId(resourceInfo));
                subs.Add("{{business_create_params_with_StorageName}}", GetBusinessCreateParamsWithStorageName(resourceInfo));
                subs.Add("{{business_create_params_with_StorageName_id}}", GetBusinessCreateParamsWithStorageNameId(resourceInfo));
                subs.Add("{{business_info_param_definitions}}", GetBusinessInfoParamDefinitions(resourceInfo));
                subs.Add("{{business_resource_convert}}", GetBusinessResourceConvert(resourceInfo));

                subs.Add("{{persistence_params_with_types_with_comma_leader}}", $", {GetPersistenceParamsWithTypes(resourceInfo)}");
                subs.Add("{{persistence_params_with_types_with_comma_leader_id}}", $", {GetPersistenceParamsWithTypesId(resourceInfo)}");
                subs.Add("{{persistence_params_with_types}}", GetPersistenceParamsWithTypes(resourceInfo));
                subs.Add("{{persistence_params_with_types_id}}", GetPersistenceParamsWithTypesId(resourceInfo));
                subs.Add("{{persistence_params_with_types_with_comma_trailer}}", $"{GetPersistenceParamsWithTypes(resourceInfo)},");
                subs.Add("{{persistence_params_with_types_with_comma_trailer_id}}", $"{GetPersistenceParamsWithTypesId(resourceInfo)},");
                subs.Add("{{persistence_params_document_create}}", GetPersistenceParamsDocumentCreate(resourceInfo));
                subs.Add("{{persistence_params_convert_params}}", GetPersistenceConvertParams(resourceInfo));
                subs.Add("{{persistence_params_struct_params}}", GetPersistenceStructParams(resourceInfo));
                subs.Add("{{persistence_update_document_params}}", GetPersistenceDocumentParams(resourceInfo));
                subs.Add("{{persistence_update_document_params_id}}", GetPersistenceDocumentParamsId(resourceInfo));
                subs.Add("{{persistence_update_param_names}}", GetPersistenceUpdateParamNames(resourceInfo));
                subs.Add("{{persistence_update_document_sets}}", GetPersistenceUpdateDocumentSets(resourceInfo));
                subs.Add("{{persistence_update_save_delegate}}", GetPersistenceUpdateSaveDelegate(resourceInfo));



                subs.Add("{{apitest_post_params_with_types_leading_comma}}", GetApiTestPostParams(resourceInfo));
                subs.Add("{{apitest_post_resource_params}}", GetApiTestPostResourceParams(resourceInfo));

                return(onSuccess(subs));
            }
            catch (Exception ex)
            {
                MsgBox("GetSubstitutions", ex.Message);
                return(onError());
            }
        }
        private TResult WriteProjectFilesFromTemplates <TResult>(string templateFilePath, Project[] projectInfos, ResourceInfo resourceInfo,
                                                                 Func <TResult> onSuccess,
                                                                 Func <TResult> onError)
        {
            try
            {
                return(GetSubstitutions(resourceInfo,
                                        (substitutions) =>
                {
                    var outputApiPath = Path.GetDirectoryName(projectInfos.First(x => x.Name == resourceInfo.APIProjectName).FullName);
                    var outputBusinessPath = Path.GetDirectoryName(projectInfos.First(x => x.Name == resourceInfo.BusinessProjectName).FullName);
                    var outputPersistencePath = Path.GetDirectoryName(projectInfos.First(x => x.Name == resourceInfo.PersistenceProjectName).FullName);
                    var outputApiTestPath = Path.GetDirectoryName(projectInfos.First(x => x.Name == resourceInfo.APITestProjectName).FullName);

                    //API\Controllers\<Controller>.cs
                    var outputPath = Path.Combine(outputApiPath, $"Controllers\\{resourceInfo.ResourceName}Controller.cs");
                    var templatePath = Path.Combine(templateFilePath, "FileTemplates\\API\\Controllers\\Controller.txt");
                    WriteFileFromTemplate(templatePath, outputPath, substitutions, resourceInfo,
                                          () =>
                    {
                        AddFileToProject(projectInfos.First(x => x.Name == resourceInfo.APIProjectName), outputPath);
                        return true;
                    },
                                          () =>
                    {
                        return false;
                    });

                    //API\Resources\Resource.cs
                    outputPath = Path.Combine(outputApiPath, $"Resources\\{resourceInfo.ResourceName}\\{resourceInfo.ResourceName}.cs");
                    templatePath = Path.Combine(templateFilePath, "FileTemplates\\API\\Resources\\ResourceName\\Resource.txt");
                    WriteFileFromTemplate(templatePath, outputPath, substitutions, resourceInfo,
                                          () =>
                    {
                        AddFileToProject(projectInfos.First(x => x.Name == resourceInfo.APIProjectName), outputPath);
                        return true;
                    },
                                          () =>
                    {
                        return false;
                    });

                    //API\Resources\ResourceActions.cs
                    outputPath = Path.Combine(outputApiPath, $"Resources\\{resourceInfo.ResourceName}\\{resourceInfo.ResourceName}Actions.cs");
                    templatePath = Path.Combine(templateFilePath, "FileTemplates\\API\\Resources\\ResourceName\\ResourceActions.txt");
                    WriteFileFromTemplate(templatePath, outputPath, substitutions, resourceInfo,
                                          () =>
                    {
                        AddFileToProject(projectInfos.First(x => x.Name == resourceInfo.APIProjectName), outputPath);
                        return true;
                    },
                                          () =>
                    {
                        return false;
                    });

                    //API\Resources\ResourceOptions.cs
                    outputPath = Path.Combine(outputApiPath, $"Resources\\{resourceInfo.ResourceName}\\{resourceInfo.ResourceName}Options.cs");
                    templatePath = Path.Combine(templateFilePath, "FileTemplates\\API\\Resources\\ResourceName\\ResourceOptions.txt");
                    WriteFileFromTemplate(templatePath, outputPath, substitutions, resourceInfo,
                                          () =>
                    {
                        AddFileToProject(projectInfos.First(x => x.Name == resourceInfo.APIProjectName), outputPath);
                        return true;
                    },
                                          () =>
                    {
                        return false;
                    });

                    //Business\Business.cs
                    outputPath = Path.Combine(outputBusinessPath, $"{resourceInfo.ResourceNamePlural}.cs");
                    templatePath = Path.Combine(templateFilePath, "FileTemplates\\Business\\Business.txt");
                    WriteFileFromTemplate(templatePath, outputPath, substitutions, resourceInfo,
                                          () =>
                    {
                        AddFileToProject(projectInfos.First(x => x.Name == resourceInfo.BusinessProjectName), outputPath);
                        return true;
                    },
                                          () =>
                    {
                        return false;
                    });

                    //Persistence\Persistence.cs
                    outputPath = Path.Combine(outputPersistencePath, $"{resourceInfo.ResourceNamePlural}.cs");
                    templatePath = Path.Combine(templateFilePath, "FileTemplates\\Persistence\\Persistence.txt");
                    WriteFileFromTemplate(templatePath, outputPath, substitutions, resourceInfo,
                                          () =>
                    {
                        AddFileToProject(projectInfos.First(x => x.Name == resourceInfo.PersistenceProjectName), outputPath);
                        return true;
                    },
                                          () =>
                    {
                        return false;
                    });

                    //Persistence\Documents\Document.cs
                    outputPath = Path.Combine(outputPersistencePath, $"Documents\\{resourceInfo.ResourceName}Document.cs");
                    templatePath = Path.Combine(templateFilePath, "FileTemplates\\Persistence\\Documents\\Document.txt");
                    WriteFileFromTemplate(templatePath, outputPath, substitutions, resourceInfo,
                                          () =>
                    {
                        AddFileToProject(projectInfos.First(x => x.Name == resourceInfo.PersistenceProjectName), outputPath);
                        return true;
                    },
                                          () =>
                    {
                        return false;
                    });

                    //Api.Test\CRUD\CRUD.cs
                    outputPath = Path.Combine(outputApiTestPath, $"CRUD\\{resourceInfo.ResourceName}.cs");
                    templatePath = Path.Combine(templateFilePath, "FileTemplates\\Test\\CRUD\\CRUD.txt");
                    WriteFileFromTemplate(templatePath, outputPath, substitutions, resourceInfo,
                                          () =>
                    {
                        AddFileToProject(projectInfos.First(x => x.Name == resourceInfo.APITestProjectName), outputPath);
                        return true;
                    },
                                          () =>
                    {
                        return false;
                    });

                    //Api.Test\Helpers\ResourceHelper.cs
                    outputPath = Path.Combine(outputApiTestPath, $"Helpers\\{resourceInfo.ResourceName}Helpers.cs");
                    templatePath = Path.Combine(templateFilePath, "FileTemplates\\Test\\Helpers\\ResourceHelper.txt");
                    WriteFileFromTemplate(templatePath, outputPath, substitutions, resourceInfo,
                                          () =>
                    {
                        AddFileToProject(projectInfos.First(x => x.Name == resourceInfo.APITestProjectName), outputPath);
                        return true;
                    },
                                          () =>
                    {
                        return false;
                    });

                    return onSuccess();
                },
                                        () =>
                {
                    return onError();
                }));
            }
            catch (Exception ex)
            {
                MsgBox("Error in WriteProjectFilesFromTemplates", ex.Message);
                return(onError());
            }
        }
        public void UpdatePersistenceContext(ResourceInfo resourceInfo, Project[] projectInfos)
        {
            var    outputPersistencePath = Path.GetDirectoryName(projectInfos.First(x => x.Name == resourceInfo.PersistenceProjectName).FullName);
            var    contextFilePath       = Path.Combine(outputPersistencePath, "DataContext.cs");
            string text = File.ReadAllText(contextFilePath);

            var index = text.LastIndexOf('}');

            text  = text.Remove(index, 1);
            index = text.LastIndexOf('}');
            text  = text.Remove(index, 1);

            text += "\n";
            text += "\t\t";
            text += $"private {resourceInfo.ResourceNamePlural} {resourceInfo.ResourceNameVariable}s = default({resourceInfo.ResourceNamePlural});";
            text += "\n";
            text += "\t\t\t";
            text += $"public {resourceInfo.ResourceNamePlural} {resourceInfo.ResourceNamePlural}";
            text += "\n";
            text += "\t\t\t";
            text += "{";
            text += "\n";
            text += "\t\t\t\t";
            text += "get";
            text += "\n";
            text += "\t\t\t\t";
            text += "{";
            text += "\n";
            text += "\t\t\t\t\t";
            text += $"if (default({resourceInfo.ResourceNamePlural}) == {resourceInfo.ResourceNameVariable}s)";
            text += "\n";
            text += "\t\t\t\t\t\t";
            text += $"{resourceInfo.ResourceNameVariable}s = new {resourceInfo.ResourceNamePlural}(this);";
            text += "\n";
            text += "\t\t\t\t\t";
            text += $"return {resourceInfo.ResourceNameVariable}s;";
            text += "\n";
            text += "\t\t\t\t";
            text += "}";
            text += "\n";
            text += "\t\t\t";
            text += "}";
            text += "\n";
            text += "\t\t";
            text += "}";
            text += "\n";
            text += "}";

            /*
             * private CSMDRecordReviews appointmentReviews = default(CSMDRecordReviews);
             * public CSMDRecordReviews CSMDRecordReviews
             * {
             *  get
             *  {
             *      if (default(CSMDRecordReviews) == appointmentReviews)
             *          appointmentReviews = new CSMDRecordReviews(this);
             *      return appointmentReviews;
             *  }
             * }
             */


            File.WriteAllText(contextFilePath, text);
        }
        public void UpdateBusinessContext(ResourceInfo resourceInfo, Project[] projectInfos)
        {
            var    outputBusinessPath = Path.GetDirectoryName(projectInfos.First(x => x.Name == resourceInfo.BusinessProjectName).FullName);
            var    contextFilePath    = Path.Combine(outputBusinessPath, "Context.cs");
            string text = File.ReadAllText(contextFilePath);

            var index = text.LastIndexOf('}');

            text  = text.Remove(index, 1);
            index = text.LastIndexOf('}');
            text  = text.Remove(index, 1);

            text += "\n";
            text += "\t\t";
            text += $"private {resourceInfo.ResourceNamePlural} {resourceInfo.ResourceNameVariable}s;";
            text += "\n";
            text += "\t\t\t";
            text += $"public {resourceInfo.ResourceNamePlural} {resourceInfo.ResourceNamePlural}";
            text += "\n";
            text += "\t\t\t";
            text += "{";
            text += "\n";
            text += "\t\t\t\t";
            text += "get";
            text += "\n";
            text += "\t\t\t\t";
            text += "{";
            text += "\n";
            text += "\t\t\t\t\t";
            text += $"if (default({resourceInfo.ResourceNamePlural}) == {resourceInfo.ResourceNameVariable}s)";
            text += "\n";
            text += "\t\t\t\t\t\t";
            text += $"{resourceInfo.ResourceNameVariable}s = new {resourceInfo.ResourceNamePlural}(this, DataContext);";
            text += "\n";
            text += "\t\t\t\t\t";
            text += $"return {resourceInfo.ResourceNameVariable}s;";
            text += "\n";
            text += "\t\t\t\t";
            text += "}";
            text += "\n";
            text += "\t\t\t";
            text += "}";
            text += "\n";
            text += "\t\t";
            text += "}";
            text += "\n";
            text += "}";

            //private PracticeAdmins practiceAdmins;
            //public PracticeAdmins PracticeAdmins
            //{
            //    get
            //    {
            //        if (default(PracticeAdmins) == practiceAdmins)
            //            practiceAdmins = new PracticeAdmins(this, DataContext);
            //        return practiceAdmins;
            //    }
            //}


            File.WriteAllText(contextFilePath, text);
        }
        private TResult WriteFileFromTemplate <TResult>(string templateFilePath, string outputFilePath,
                                                        IDictionary <string, string> substitutions, ResourceInfo resourceInfo,
                                                        Func <TResult> onSuccess,
                                                        Func <TResult> onError)
        {
            try
            {
                MsgBox("WriteFileFromTemplate", $"templateFilePath: {templateFilePath}     outputFilePath: {outputFilePath}");
                var subInfo = "SubstitutionInfo---    ";
                foreach (var substitution in substitutions)
                {
                    subInfo += $"{substitution.Key} : {substitution.Value}";
                }
                MsgBox("WriteFileFromTemplate", subInfo);

                using (TextReader reader = File.OpenText(templateFilePath))
                {
                    string templateText = reader.ReadToEnd();
                    foreach (var substitution in substitutions)
                    {
                        templateText = templateText.Replace(substitution.Key, substitution.Value);
                    }

                    Directory.CreateDirectory(Path.GetDirectoryName(outputFilePath));
                    using (var writer = new StreamWriter(outputFilePath))
                    {
                        writer.Write(templateText);
                    }
                }
                return(onSuccess());
            }
            catch (Exception ex)
            {
                MsgBox("WriteFileFromTemplate", ex.Message);
                return(onError());
            }
        }