/// <summary>
        /// Processes the template using passed Template Inputs and the handlebars template name.  These inputs can be from a variety of sources including direct schema (useful for caching scenarios), filename and connection strings.
        /// </summary>
        /// <returns><c>true</c>, if template was processed, <c>false</c> otherwise.</returns>
        /// <param name="TemplateFileNameOrPath">The file name of a handlebars template or a path that contains handlebars templates. If no path is specified,  the app will prepend the assembly path in front of the text and search there</param>
        /// <param name="originalTemplateInputSource">The template input class,  could be an object of type IDatabase or if type schema</param>
        /// <param name="compareToTemplateInputSource">The template input class to compare to,  will only change the difference</param>
        /// <param name="OutputPath">The output path.  If there is no &lt;FILE&gt;FILENAMEHERE&lt;/FILE&gt; specifier, then this should be a file name,
        /// if there is a file specifier,  then it will write to the file resolved between the FILE tags.  Note that you can specify and OUTPUT_PATH xml tag
        /// in order to specify and output target (which will override the the path passed through this paramter)</param>
        /// <returns>A return code </returns>
        public ReturnCodes ProcessTemplate(string TemplateFileNameOrPath, ITemplateInput originalTemplateInputSource, ITemplateInput compareToTemplateInputSource, string outputPath)
        {
            if (!(
                    (File.Exists(TemplateFileNameOrPath)) ||
                    (Directory.Exists(TemplateFileNameOrPath)
                    )))
            {
                TemplateFileNameOrPath = ("{ASSEMBLY_PATH}" + TemplateFileNameOrPath).ResolvePathVars();
            }
            if (!((File.Exists(TemplateFileNameOrPath)) || (Directory.Exists(TemplateFileNameOrPath))))
            {
                throw new Exception(string.Format("Template not found in path {0}", TemplateFileNameOrPath));
            }

            // get the file attributes for file or directory
            FileAttributes attr = File.GetAttributes(TemplateFileNameOrPath);

            if (attr.HasFlag(FileAttributes.Directory))
            {
                return(ProcessTemplate((DirectoryName)TemplateFileNameOrPath, originalTemplateInputSource, compareToTemplateInputSource, outputPath));
            }
            else
            {
                return(ProcessTemplate((FileName)TemplateFileNameOrPath, originalTemplateInputSource, compareToTemplateInputSource, outputPath));
            }
        }
 private static void HandlePath(string Path, TemplatePathOption option, ITemplateInput originalTemplateInputSource, ITemplateInput compareToTemplateInputSource)
 {
     try
     {
     }
     catch (Exception)
     {
         throw;
     }
 }
 /// <summary>
 /// Processes the template using passed Template Inputs and the handlebars template name.  These inputs can be from a variety of sources including direct schema (useful for caching scenarios), filename and connection strings.
 /// </summary>
 /// <param name="TemplateFileNameOrPath">The file name of a handlebars template or a path that contains handlebars templates. If no path is specified,  the app will prepend the assembly path in front of the text and search there</param>
 /// <param name="templateInput">The template input class,  could be an object of type IDatabase or if type schema</param>
 /// <param name="OutputPath">The output path.  If there is no &lt;FILE&gt;FILENAMEHERE&lt;/FILE&gt; specifier, then this should be a file name,
 /// if there is a file specifier,  then it will write to the file resolved between the FILE tags.  Note that you can specify and OUTPUT_PATH xml tag
 /// in order to specify and output target (which will override the the path passed through this paramter)</param>
 /// <returns>A return code </returns>
 /// <exception cref="Exception"></exception>
 public ReturnCodes ProcessTemplate(string TemplateFileNameOrPath, ITemplateInput templateInput, string outputPath)
 {
     try
     {
         return(ProcessTemplate(TemplateFileNameOrPath, templateInput, null, outputPath));
     }
     catch (Exception ex)
     {
         throw new Exception(string.Format("Failed on ProcessTemplate. {0}", ex.Message), ex);
     }
 }
        protected ReturnCodes ProcessTemplate(DirectoryName pathName, ITemplateInput originalTemplateInputSource, ITemplateInput compareToTemplateInputSource, string outputPath)
        {
            var filesEndingInHbs = Directory.EnumerateFiles(pathName).Where(f => f.EndsWith("hbs", StringComparison.InvariantCulture)).ToList();
            var returnCodeList   = new ReturnCodes();

            foreach (var _templateFullFileName in filesEndingInHbs)
            {
                string templateFullFileName = (FileName)_templateFullFileName;
                if ((this.TemplateFileNameFilter.Length > 0) && (Path.GetFileNameWithoutExtension(templateFullFileName).IsIn(this.TemplateFileNameFilter)))
                {
                    CurrentTask = string.Format("Template {0} will be ignored because it matches a pattern in TemplateFileNameFilter", Path.GetFileNameWithoutExtension(templateFullFileName));
                }
                else
                {
                    returnCodeList.Merge(ProcessTemplate((FileName)_templateFullFileName, originalTemplateInputSource, compareToTemplateInputSource, outputPath));
                }
            }
            return(returnCodeList);
        }
        /// <summary>
        /// Processes the template using passed Template Inputs and the handlebars template name.  These inputs can be from a variety of sources including direct schema (useful for caching scenarios), filename and connection strings.
        /// </summary>
        /// <returns><c>true</c>, if template was processed, <c>false</c> otherwise.</returns>
        /// <param name="templateFileName">File name of an existing handlebars template file name</param>
        /// <param name="originalTemplateInputSource">Original template input source.  Pass the input to here if you want to generate using only 1 schema</param>
        /// <param name="compareToTemplateInputSource">Optional - Compare to template input source.  This will process only the differences. </param>
        /// <param name="outputPath">The output path.  If there is no &lt;FILE&gt;FILENAMEHERE&lt;/FILE&gt; specifier, then this should be a file name,  if there is a file specifier,  then it will write to the file resolved between the FILE tags</param>
        protected ReturnCodes ProcessTemplate(FileName _templateFileName, ITemplateInput originalTemplateInputSource, ITemplateInput compareToTemplateInputSource, string outputPath)
        {
            FileActions.Clear();
            Configuration EzDbConfig = null;

            this.OutputPath = outputPath;
            string templateFileName = _templateFileName;

            _currentTemplateName = Path.GetFileNameWithoutExtension(templateFileName);

            if (!File.Exists(templateFileName))
            {
                templateFileName = ("{ASSEMBLY_PATH}" + templateFileName).ResolvePathVars();
            }
            CurrentTask = "Entering ProcessTemplate";
            var returnCode = ReturnCode.OkNoAddDels;

            try
            {
                CurrentTask = string.Format("Trying to find Config file at {0}", ConfigurationFileName);
                if (File.Exists(ConfigurationFileName))
                {
                    CurrentTask = string.Format("Config file found! lets read it");
                    EzDbConfig  = Configuration.FromFile(ConfigurationFileName);
                    foreach (var item in EzDbConfig.PluralizerCrossReference)
                    {
                        Pluralizer.Instance.AddWord(item.SingleWord, item.PluralWord);
                    }
                    if (!string.IsNullOrEmpty(EzDbConfig.Database.SchemaName))
                    {
                        CurrentTask     = string.Format("Schema name has been changed from {0} to {1} by configuration file.", this.SchemaName, EzDbConfig.Database.SchemaName);
                        this.SchemaName = EzDbConfig.Database.SchemaName;
                    }
                }
                else
                {
                    ErrorMessage(string.Format("WARNING!  Configuration file was not found at {0}", ConfigurationFileName));
                }

                CurrentTask = "Performing Validations";
                if (originalTemplateInputSource == null)
                {
                    throw new Exception(@"There must be an Template Source passed through originalTemplateInputSource!");
                }
                CurrentTask = "Loading Source Schema";
                IDatabase schema = originalTemplateInputSource.LoadSchema(EzDbConfig);
                schema.Name = this.SchemaName;

                if (schema == null)
                {
                    throw new Exception(@"originalTemplateInputSource is not a valid template");
                }

                CurrentTask = "Template path is " + templateFileName;

                string result = "";
                try
                {
                    CurrentTask = string.Format("Reading Template from '{0}'", templateFileName);
                    var templateAsString             = File.ReadAllText(templateFileName);
                    var forceDeleteReloadOfDirectory = false;
                    //Does template have a project path override? If so, extract it and stash it
                    if (templateAsString.Contains(CodeGenBase.OP_PROJECT_PATH))
                    {
                        this.ProjectPath = templateAsString.Pluck(CodeGenBase.OP_PROJECT_PATH, CodeGenBase.OP_PROJECT_PATH_END, out templateAsString).Trim();
                        if (this.ProjectPath.StartsWith("@"))  //An @ at the beginning forces the app to treat this as a path and delete and attempt to recreate it
                        {
                            this.ProjectPath = this.ProjectPath.Substring(1);
                            CurrentTask      = string.Format("'@' was found at the beginning of ProjectPath but doesn't do anything here and will be ignored");
                        }
                        if (this.ProjectPath.Contains(CodeGenBase.VAR_THIS_PATH))
                        {
                            this.ProjectPath = Path.GetFullPath(this.ProjectPath.Replace(CodeGenBase.VAR_THIS_PATH, Path.GetDirectoryName(templateFileName).PathEnds()));
                        }
                        if (this.ProjectPath.Contains(CodeGenBase.VAR_TEMP_PATH))
                        {
                            this.ProjectPath = Path.GetFullPath(this.ProjectPath.Replace(CodeGenBase.VAR_TEMP_PATH, Path.GetDirectoryName(templateFileName).PathEnds()));
                        }
                        CurrentTask      = string.Format("Project Path modifier found in template, resolved to: {0}", this.ProjectPath);
                        templateAsString = templateAsString.Replace(CodeGenBase.OP_PROJECT_PATH, "").Replace(CodeGenBase.OP_PROJECT_PATH_END, "").Trim();
                    }

                    //Does template have and Output path override? if so, override the local outputDirectory and strip it
                    if (templateAsString.Contains(CodeGenBase.OP_OUTPUT_PATH))
                    {
                        this.OutputPath = templateAsString.Pluck(CodeGenBase.OP_OUTPUT_PATH, CodeGenBase.OP_OUTPUT_PATH_END, out templateAsString).Trim();

                        if (this.OutputPath.StartsWith("@"))  //An @ at the beginning forces the app to treat this as a path and delete and attempt to recreate it
                        {
                            this.OutputPath = this.OutputPath.Substring(1);
                            CurrentTask     = string.Format("'@' was found at the beginning... Will forcefully delete: {0}", this.OutputPath);
                            forceDeleteReloadOfDirectory = true;
                        }
                        if (this.OutputPath.Contains(CodeGenBase.VAR_THIS_PATH))
                        {
                            this.OutputPath = Path.GetFullPath(this.OutputPath.Replace(CodeGenBase.VAR_THIS_PATH, Path.GetDirectoryName(templateFileName).PathEnds()));
                        }
                        if (this.OutputPath.Contains(CodeGenBase.VAR_TEMP_PATH))
                        {
                            this.OutputPath = Path.GetFullPath(this.OutputPath.Replace(CodeGenBase.VAR_TEMP_PATH, Path.GetDirectoryName(templateFileName).PathEnds()));
                        }
                        CurrentTask = string.Format("Output Path modifier found in template, resolved to: {0}", this.OutputPath);

                        //If we asked for a force of a reload and if we don't contain a file operator, then the output path must be a single file result.
                        //  Forcing this to be created will prevent us from writing this file out, so we will ignore that force directory operator in this case
                        if (forceDeleteReloadOfDirectory)
                        {
                            if (templateAsString.Contains(CodeGenBase.OP_FILE))
                            {
                                if (Directory.Exists(this.OutputPath))
                                {
                                    Directory.Delete(this.OutputPath, true);
                                }
                                if (!Directory.Exists(this.OutputPath))
                                {
                                    Directory.CreateDirectory(this.OutputPath);
                                }
                            }
                            else
                            {
                                var OutputDirectoryContainer = Path.GetDirectoryName(this.OutputPath).PathEnds();
                                if (File.Exists(this.OutputPath))
                                {
                                    File.Delete(this.OutputPath);
                                }
                                if (!Directory.Exists(OutputDirectoryContainer))
                                {
                                    Directory.CreateDirectory(OutputDirectoryContainer);
                                }
                            }
                        }
                        templateAsString = templateAsString.Replace(CodeGenBase.OP_OUTPUT_PATH, "").Replace(CodeGenBase.OP_OUTPUT_PATH_END, "").Trim();
                    }

                    if (!File.Exists(templateFileName))
                    {
                        throw new FileNotFoundException("Template File " + templateFileName + " is not found");
                    }
                    CurrentTask = string.Format("Checking to see if outpath of {0} exists?", this.OutputPath);
                    if (string.IsNullOrEmpty(this.OutputPath))
                    {
                        throw new Exception(string.Format("Output Path was not passed through ProcessTemplate nor did <OUTPUT_PATH /> exist in the hbs template {1}.  It must exist in one or the other.", this.OutputPath, templateFileName));
                    }
                    CurrentTask = string.Format("Registering Handlbar helpers");
                    HandlebarsUtility.RegisterHelpers();
                    HandlebarsCsUtility.RegisterHelpers();
                    HandlebarsCsV0Utility.RegisterHelpers();
                    HandlebarsTsUtility.RegisterHelpers();
                    CurrentTask = string.Format("Compiling Handlbar Template");
                    var template = Handlebars.Compile(templateAsString);
                    CurrentTask = string.Format("Rendering Handlbar Template");
                    result      = template(schema);
                }
                catch (Exception exTemplateError)
                {
                    returnCode = ReturnCode.Error;
                    ErrorMessage(string.Format("{0}: Error while {1}. {2}", Path.GetFileNameWithoutExtension(templateFileName), CurrentTask, exTemplateError.Message));
                    throw;
                    //throw exRazerEngine;
                }
                finally
                {
                }

                result = result.Replace("<t>", "")
                         .Replace("<t/>", "")
                         .Replace("<t />", "")
                         .Replace("</t>", "")
                         .Replace("$OUTPUT_PATH$", this.OutputPath).TrimStart();

                CurrentTask = string.Format("Template Rendering Completed.. handling output now");
                /* If the entity key specifier doesn't exist */
                var hasEntityKeySpecifier = result.Contains(CodeGenBase.OP_ENTITY_KEY);
                CurrentTask = string.Format("Does the file contain FILE operator?");
                if (result.Contains(CodeGenBase.OP_FILE))    /* File seperation specifier - this will split by the files specified by  */
                {
                    if (!Directory.Exists(this.OutputPath))  //This does contain a FILE specifier,  so we need to make this a directoy and try to create it if it doesn't exist
                    {
                        this.OutputPath = Path.GetDirectoryName(this.OutputPath).PathEnds();
                        CurrentTask     = string.Format("It doesn't... so lets try to create it");
                        Directory.CreateDirectory(this.OutputPath);
                    }


                    CurrentTask = string.Format("Parsing files");
                    /* First, lets get all the files currently in the path */
                    FileActions.Clear();
                    string[] FilesinOutputDirectory = Directory.GetFiles(this.OutputPath);
                    foreach (var fileName in FilesinOutputDirectory)
                    {
                        FileActions.Add(fileName, TemplateFileAction.Unknown);
                    }

                    var      FileListAndContents = new EntityFileDictionary();
                    string[] parseFiles          = result.Split(new[] { CodeGenBase.OP_FILE }, StringSplitOptions.RemoveEmptyEntries);

                    var EntityKey = "";
                    foreach (string fileText in parseFiles)
                    {
                        var    filePart          = CodeGenBase.OP_FILE + fileText;              //need to add the delimiter to make pluck work as expected
                        string newOutputFileName = filePart.Pluck(CodeGenBase.OP_FILE, CodeGenBase.OP_FILE_END, out string FileContents);
                        FileContents = FileContents.Replace(CodeGenBase.OP_FILE, "").Replace(CodeGenBase.OP_FILE_END, "").Trim();
                        if ((newOutputFileName.Length > 0) && (newOutputFileName.StartsWith(this.OutputPath, StringComparison.Ordinal)))
                        {
                            EntityKey = "XXX" + Guid.NewGuid().ToString();                              /* guaruntee this to be unique */
                            //var FileContents = filePart.Substring(CodeGenBase.OP_FILE_END.Length + 1);
                            if (FileContents.Contains(CodeGenBase.OP_ENTITY_KEY))
                            {
                                EntityKey    = FileContents.Pluck(CodeGenBase.OP_ENTITY_KEY, CodeGenBase.OP_ENTITY_KEY_END, out FileContents);
                                FileContents = FileContents.Replace(CodeGenBase.OP_ENTITY_KEY, "").Replace(CodeGenBase.OP_ENTITY_KEY_END, "").Trim();
                            }
                            FileListAndContents.Add(newOutputFileName, EntityKey, FileContents);
                        }
                    }

                    CurrentTask = string.Format("Handling the output file");
                    var       EffectivePathOption = this.TemplatePathOption;
                    IDatabase schemaToCompareTo   = null;
                    if (EffectivePathOption == TemplatePathOption.Auto)
                    {
                        EffectivePathOption = TemplatePathOption.Clear;
                        if ((compareToTemplateInputSource != null) && (hasEntityKeySpecifier))
                        {
                            schemaToCompareTo = compareToTemplateInputSource.LoadSchema(EzDbConfig);
                            if (schemaToCompareTo == null)
                            {
                                throw new Exception(@"schemaToCompareTo is not a valid template");
                            }
                            EffectivePathOption = TemplatePathOption.SyncDiff;
                        }
                    }
                    if (EffectivePathOption.Equals(TemplatePathOption.Clear))
                    {
                        StatusMessage("Path Option is set to 'Clear'");
                        foreach (var fileName in FileActions.Keys.ToList())
                        {
                            FileActions[fileName] = TemplateFileAction.Delete;
                        }
                    }
                    else if (EffectivePathOption.Equals(TemplatePathOption.SyncDiff))
                    {
                        StatusMessage("Path Option is set to 'SyncDiff'");
                        var SchemaDiffs = schema.CompareTo(schemaToCompareTo);
                        StatusMessage(string.Format("There where {0} differences between the schemas", SchemaDiffs.Count));
                        if (SchemaDiffs.Count > 0)
                        {
                            foreach (var schemaDiff in SchemaDiffs)
                            {
                                var      entityName = schemaDiff.EntityName;
                                FileName fileName   = "";
                                if (schemaDiff.FileAction == TemplateFileAction.Add)
                                {
                                    if (FileActions.ContainsKey(fileName))
                                    {
                                        /* this should not happen;  but if it does */
                                        FileActions[fileName] = TemplateFileAction.Update;
                                    }
                                    else
                                    {
                                        FileActions.Add(fileName, TemplateFileAction.Add);
                                    }
                                }
                                else if (schemaDiff.FileAction == TemplateFileAction.Update)
                                {
                                    if (FileActions.ContainsKey(fileName))
                                    {
                                        FileActions[fileName] = TemplateFileAction.Update;
                                    }
                                    else
                                    {
                                        FileActions.Add(fileName, TemplateFileAction.Add);
                                    }
                                }
                                else if (schemaDiff.FileAction == TemplateFileAction.Delete)
                                {
                                    if (FileActions.ContainsKey(fileName))
                                    {
                                        FileActions[fileName] = TemplateFileAction.Delete;
                                    }
                                    else
                                    {
                                        FileActions.Add(fileName, TemplateFileAction.Delete);
                                    }
                                }
                            }
                        }
                    }
                    else if (EffectivePathOption.Equals(TemplatePathOption.Update))
                    {
                        StatusMessage("Path Option is set to 'Update'");
                    }

                    CurrentTask = string.Format("Queueing file actions");
                    //Lets now make sure all of those files that should be rendered are there
                    foreach (string fileName in FileListAndContents.ClonePrimaryKeys())
                    {
                        if ((FileActions.ContainsKey(fileName)))
                        {
                            //if the file exists and it is slated to be deleted and if it was going to be a generated,  then mark it as an update
                            if (FileActions[fileName] == TemplateFileAction.Delete)
                            {
                                FileActions[fileName] = TemplateFileAction.Update;
                            }
                            else
                            {
                                FileActions[fileName] = TemplateFileAction.None;
                            }
                        }
                        else
                        {
                            FileActions.Add(fileName, TemplateFileAction.Add);
                        }
                    }

                    CurrentTask = string.Format("Performing file actions");
                    var Deletes = 0; var Updates = 0; var Adds = 0;
                    /* Process File Actions based on which Template File action*/
                    foreach (string fileName in FileActions.Keys.ToList())
                    {
                        CurrentTask = string.Format("Performing file actions on {0} (Action={1})", fileName, FileActions[fileName]);
                        if ((FileActions[fileName] == TemplateFileAction.Delete) ||
                            (FileActions[fileName] == TemplateFileAction.Unknown))
                        {
                            if (File.Exists(fileName))
                            {
                                File.Delete(fileName);
                                Deletes++;
                            }
                        }
                        else if (FileActions[fileName] == TemplateFileAction.Update)
                        {
                            //We do not need to update if the file contents are the same
                            if (!FileListAndContents[(FileName)fileName].IsEqualToFileContents(fileName))
                            {
                                Updates++;
                                //if (File.Exists(fileName)) File.Delete(fileName);
                                File.WriteAllText(fileName, FileListAndContents[(FileName)fileName]);
                            }
                        }
                        else if (FileActions[fileName] == TemplateFileAction.Add)
                        {
                            Adds++;
                            File.WriteAllText(fileName, FileListAndContents[(FileName)fileName]);
                        }
                    }
                    StatusMessage(string.Format("File Action Counts: Adds={0}, Updates={1}, Deletes={2}", Adds, Updates, Deletes), true);
                    if ((Adds > 0) || (Deletes > 0))
                    {
                        returnCode = ReturnCode.OkAddDels;
                    }
                }
                else if (!string.IsNullOrEmpty(result))
                {
                    if (File.Exists(OutputPath))
                    {
                        File.Delete(OutputPath);
                    }
                    File.WriteAllText(OutputPath, result);
                }
                else
                {
                    throw new ApplicationException("The Template Engine Produced No results for path [" + templateFileName + "]");
                }
                StatusMessage(string.Format("Template was rendered to path {0}", this.OutputPath));

                CurrentTask = string.Format("Checking Project File Modification Option: {0}", (this.ProjectPath.Length > 0));

                if (this.ProjectPath.Length > 0)
                {
                    CurrentTask = string.Format("Looks like Project Mod was set to true, Does path exist? ");
                    if (!File.Exists(this.ProjectPath))
                    {
                        StatusMessage(string.Format("ProjectPath was set to {0} but this file doesn't exist,  I will ignore ProjectPath option", this.ProjectPath));
                    }
                    else
                    {
                        StatusMessage(string.Format("ProjectPath was set to {0},  so we will alter this project with the files affected if necessary", this.ProjectPath));
                        var FileActionsOffset = new Dictionary <string, TemplateFileAction>();
                        CurrentTask = string.Format("Figuring out offset of files added compared to Project location");
                        foreach (var fileWithFileAction in FileActions)
                        {
                            var fileOffset = (new Uri(this.ProjectPath))
                                             .MakeRelativeUri(new Uri(fileWithFileAction.Key))
                                             .ToString()
                                             .Replace('/', Path.DirectorySeparatorChar);
                            CurrentTask = string.Format("Project File Check: {0}", fileOffset);
                            FileActionsOffset.Add(fileOffset, fileWithFileAction.Value);
                        }

                        CurrentTask = string.Format("Now we modify the project file {0}", this.ProjectPath);
                        var ret = (new ProjectHelpers()).ModifyClassPath(this.ProjectPath, FileActionsOffset);
                        if (ret)
                        {
                            StatusMessage(string.Format("There were changes to {0},  project will probably have to be reloaded", this.ProjectPath));
                        }
                        else
                        {
                            StatusMessage(string.Format("There were no changes to {0}", this.ProjectPath));
                        }
                    }
                }
                CurrentTask = string.Format("All done!");
                return(new ReturnCodes(templateFileName, returnCode));
            }
            catch (Exception ex)
            {
                returnCode = ReturnCode.Error;
                ErrorMessage(string.Format("{0}: Error while {1}. {2}", Path.GetFileNameWithoutExtension(templateFileName), CurrentTask, ex.Message));
                throw;
            }
        }
 /// <summary>
 /// Processes the template using passed Template Inputs and the handlebars template name.  These inputs can be from a variety of sources including direct schema (useful for caching scenarios), filename and connection strings. There needs to be a  &lt;FILE&gt;FILENAMEHERE&lt;/FILE&gt; specifier, then this should be a file name,
 /// </summary>
 /// <returns><c>true</c>, if template was processed, <c>false</c> otherwise.</returns>
 /// <param name="TemplateFileNameOrPath">The file name of a handlebars template or a path that contains handlebars templates. If no path is specified,  the app will prepend the assembly path in front of the text and search there</param>
 /// <param name="originalTemplateInputSource">The template input class,  could be an object of type IDatabase or if type schema</param>
 /// <param name="compareToTemplateInputSource">The template input class to compare to,  will only change the difference</param>
 /// <returns>A return code </returns>
 public ReturnCodes ProcessTemplate(string TemplateFileNameOrPath, ITemplateInput originalTemplateInputSource)
 {
     return(ProcessTemplate(TemplateFileNameOrPath, originalTemplateInputSource, null, ""));
 }
        public static void Enable(CommandLineApplication app)
        {
            app.Name             = "ezdb.codegen.cli";
            app.Description      = "EzDbCodeGen - Code Generation Utility";
            app.ExtendedHelpText = "This application will allow you to trigger code generation based on a template file or a list of template files."
                                   + Environment.NewLine + "";

            app.HelpOption("-?|-h|--help");

            var sampleFilesOption = app.Option("-i|--init-files <path>",
                                               "This option will download the template files and required powerscript to the [path] directory, renaming assets using the value sent through -a/--app-name ",
                                               CommandOptionType.SingleValue);

            var appNameOption = app.Option("-a|--app-name <appame>",
                                           "This option will be used to customize the name and files on --init-files,  this default value will be MyApp",
                                           CommandOptionType.SingleValue);

            var verboseOption = app.Option("-v|--verbose",
                                           "Will output more detailed message about what is happening during application processing.  This parm is optional and will override the value in appsettings.json.   ",
                                           CommandOptionType.NoValue);

            var versionOption = app.Option("-ver|--version",
                                           "Will output the current version of the utility.",
                                           CommandOptionType.NoValue);

            var templateFileNameOrDirectoryOption = app.Option("-t|--template <value>",
                                                               "The template file name or path that you wish to render.  If you choose aa path,  ",
                                                               CommandOptionType.SingleValue);

            var pathNameOption = app.Option("-p|--outpath <value>",
                                            "The template that you wish to render.  This is required uniless you use the <OUTPUT_PATH> specifier in the template file.",
                                            CommandOptionType.SingleValue);

            var sourceConnectionStringOption = app.Option("-sc|--connection-string <optionvalue>",
                                                          "Connection String pass via the appline.  This parm is optional and this value will override the value in appsettings.json. ",
                                                          CommandOptionType.SingleValue);

            var sourceSchemaFileNameOption = app.Option("-sf|--schema-file <optionvalue>",
                                                        "Specify a schema json dump to perform the code generation (as opposed to a connection string).  This parm is optional and parm is present, it will override the appsettings and the -sc app line parm",
                                                        CommandOptionType.SingleValue);

            var configFileOption = app.Option("-cf|--configfile",
                                              "The configuration file this template render will use.  This is optional, the default search path will be in the same path as this assembly of this applicaiton. ",
                                              CommandOptionType.SingleValue);

            var compareToConnectionStringOption = app.Option("-tc|--compare-connection-string <optionvalue>",
                                                             "Connection String to compare to.  This parm is optional.  If it is present,  This schema will be compared to either the -sc or -sf and the only the changes will be updated.",
                                                             CommandOptionType.SingleValue);

            var compareToSchemaFileNameOption = app.Option("-tf|--compare-schema-file <optionvalue>",
                                                           "OPTIONAL: Specify a compare schema json dump to perform the (as opposed to a compare connection string).  This parm is optional and parm is present, it will override the -ts command line parameter and will be used to compare,  affecting only those entities that have changed.",
                                                           CommandOptionType.SingleValue);

            var schemaNameOption = app.Option("-sn|--schemaName",
                                              "the Name of the schema,  a decent standard could be <DatabaseName>Entites.",
                                              CommandOptionType.SingleValue);

            var projectFileToModifyOption = app.Option("-pf|--project-file <optionvalue>",
                                                       "Option to pass a project file that will be altered with the ouputpath that the template files will be written to.  This only pertains to older version of a visual studio project file.",
                                                       CommandOptionType.SingleValue);

            var templateFilterFileMasks = app.Option("-f|--filter <optionvalue>",
                                                     "Option to ignore template file names (seperated by comma, wildcards are acceptable) for those runs where a path is sent through parm -t (or --template).",
                                                     CommandOptionType.SingleValue);

            app.OnExecute(() =>
            {
                var pfx = "EzDbCodeGen: ";
                if (versionOption.HasValue())
                {
                    var version_ = Assembly.GetAssembly(typeof(CodeGenerator)).GetName().Version;
                    Console.WriteLine(version_);
                    Environment.ExitCode = 0;
                    Environment.Exit(Environment.ExitCode);
                    return(Environment.ExitCode);
                }

                if (verboseOption.HasValue())
                {
                    AppSettings.Instance.VerboseMessages = verboseOption.HasValue();
                }
                try
                {
                    var sampleFilesPath = (sampleFilesOption.HasValue() ? sampleFilesOption.Value().ResolvePathVars() : "%THIS%".ResolvePathVars());
                    if (!sampleFilesPath.EndsWith(Path.DirectorySeparatorChar))
                    {
                        sampleFilesPath += Path.DirectorySeparatorChar;
                    }
                    if (sampleFilesOption.HasValue())
                    {
                        var workPath = Path.GetTempPath() + @"EzDbCodeGen\";
                        var appName  = (appNameOption.HasValue() ? appNameOption.Value() : "MyApp");
                        Directory.Delete(workPath, true);
                        Console.WriteLine(pfx + "Sample Files to be downloaded from https://github.com/rvegajr/ez-db-codegen-core to " + workPath);
                        WebFileHelper.CurlGitRepoZip(workPath);
                        if (Directory.Exists(workPath))
                        {
                            var rootPath = workPath + @"ez-db-codegen-core-master\Src\EzDbCodeGen.Cli\";
                            WebFileHelper.CopyTo(@"Templates\SchemaRender.hbs", rootPath, sampleFilesPath);
                            WebFileHelper.CopyTo(@"Templates\SchemaRenderAsFiles.hbs", rootPath, sampleFilesPath);
                            WebFileHelper.CopyTo(@"Templates\SchemaRenderAsFilesNoOutput.hbs", rootPath, sampleFilesPath);
                            WebFileHelper.CopyTo(@"ezdbcodegen.config.json", rootPath, sampleFilesPath);
                            WebFileHelper.CopyTo(@"ezdbcodegen.ps1", rootPath, sampleFilesPath);

                            WebFileHelper.CopyTo(@"ezdbcodegen.config.json", rootPath, sampleFilesPath, appName + ".config.json")
                            .ReplaceAll("MyEntities", appName + "Entities");
                            WebFileHelper.CopyTo(@"ezdbcodegen.ps1", rootPath, sampleFilesPath, appName + ".codegen.ps1")
                            .ReplaceAll("ezdbcodegen", appName);;
                            WebFileHelper.CopyTo(@"readme.txt", rootPath, sampleFilesPath)
                            .ReplaceAll("SuperApp", appName)
                            .ReplaceAll("%PSPATH%", sampleFilesPath)
                            ;
                        }
                    }

                    var schemaName = "MySchema";

                    if (schemaNameOption.HasValue())
                    {
                        schemaName = schemaNameOption.Value();
                    }
                    if (sourceConnectionStringOption.HasValue())
                    {
                        AppSettings.Instance.ConnectionString = sourceConnectionStringOption.Value().SettingResolution();
                    }

                    if (configFileOption.HasValue())
                    {
                        AppSettings.Instance.ConfigurationFileName = configFileOption.Value();
                    }

                    var Errors     = new StringBuilder();
                    var OutputPath = string.Empty;
                    if ((!templateFileNameOrDirectoryOption.HasValue()) || (templateFileNameOrDirectoryOption.Value().Length == 0))
                    {
                        Errors.AppendLine("TemplateName is missing or empty. ");
                    }
                    if ((pathNameOption.HasValue()) && (pathNameOption.Value().Length > 0))
                    {
                        OutputPath = pathNameOption.Value();
                    }
                    if ((!sourceSchemaFileNameOption.HasValue()) && (AppSettings.Instance.ConnectionString.Length == 0))
                    {
                        Errors.AppendLine("ConnectionString and schemaFileName are both missing or empty. ");
                    }
                    if ((sourceSchemaFileNameOption.HasValue()) && (!File.Exists(sourceSchemaFileNameOption.Value())))
                    {
                        Errors.AppendLine(string.Format("Schema file '{0}' was does not exists! ", sourceSchemaFileNameOption.Value()));
                    }
                    if (Errors.Length > 0)
                    {
                        if (sampleFilesOption.HasValue())
                        {
                            Console.WriteLine("Sample files where generated... exiting");
                            Environment.ExitCode = 0;
                            Environment.Exit(Environment.ExitCode);
                            return(Environment.ExitCode);
                        }
                        throw new Exception(Errors.ToString());
                    }

                    var TemplateFileNameOrPath = templateFileNameOrDirectoryOption.Value();
                    if (Path.GetPathRoot(TemplateFileNameOrPath).Length == 0)
                    {
                        TemplateFileNameOrPath = ("{ASSEMBLY_PATH}" + TemplateFileNameOrPath).ResolvePathVars();
                    }
                    if (!(
                            (File.Exists(TemplateFileNameOrPath)) ||
                            (Directory.Exists(TemplateFileNameOrPath)
                            )))
                    {
                        TemplateFileNameOrPath = ("{ASSEMBLY_PATH}" + TemplateFileNameOrPath).ResolvePathVars();
                    }
                    if (!((File.Exists(TemplateFileNameOrPath)) || (Directory.Exists(TemplateFileNameOrPath))))
                    {
                        throw new Exception(string.Format("Template not found in path {0}", TemplateFileNameOrPath));
                    }

                    // get the file attributes for file or directory
                    FileAttributes attr = File.GetAttributes(TemplateFileNameOrPath);

                    if (attr.HasFlag(FileAttributes.Directory))
                    {
                        pfx = "<List of templates>: ";
                        //Since we know this is a directory,  force it to end with a system path seperator
                        TemplateFileNameOrPath = TemplateFileNameOrPath.PathEnds();
                    }
                    else
                    {
                        pfx = Path.GetFileNameWithoutExtension(TemplateFileNameOrPath) + ": ";
                    }

                    Console.WriteLine("Performing Rendering of template " + pfx + "....");
                    if (AppSettings.Instance.VerboseMessages)
                    {
                        Console.WriteLine(pfx + "Template Path: " + TemplateFileNameOrPath);
                        Console.WriteLine(pfx + "Path Name: " + pathNameOption.Value());
                        Console.WriteLine(pfx + "Config File Name: " + AppSettings.Instance.ConfigurationFileName);
                        if (!sourceSchemaFileNameOption.HasValue())
                        {
                            Console.WriteLine(pfx + "Source Connection String: " + AppSettings.Instance.ConnectionString);
                        }
                        if (sourceSchemaFileNameOption.HasValue())
                        {
                            Console.WriteLine(pfx + "Source Schema File Name: " + sourceSchemaFileNameOption.Value());
                        }

                        if (compareToSchemaFileNameOption.HasValue())
                        {
                            Console.WriteLine(pfx + "Compare To Schema File Name: " + compareToSchemaFileNameOption.Value());
                        }
                        if ((!compareToSchemaFileNameOption.HasValue()) && (compareToConnectionStringOption.HasValue()))
                        {
                            Console.WriteLine(pfx + "Compare To Connection String: " + compareToConnectionStringOption.Value());
                        }
                    }
                    var CodeGen = new CodeGenerator
                    {
                        SchemaName             = schemaName,
                        VerboseMessages        = AppSettings.Instance.VerboseMessages,
                        ConfigurationFileName  = AppSettings.Instance.ConfigurationFileName,
                        ProjectPath            = ((projectFileToModifyOption.HasValue()) ? projectFileToModifyOption.Value() : ""),
                        TemplateFileNameFilter = ((templateFilterFileMasks.HasValue()) ? templateFilterFileMasks.Value() : "")
                    };

                    var version = Assembly.GetAssembly(typeof(CodeGenerator)).GetName().Version;
                    Console.WriteLine(pfx + "Using CodeGenerator Version " + version);

                    CodeGen.OnStatusChangeEventArgs += StatusChangeEventHandler;

                    var returnCode        = new ReturnCodes();
                    ITemplateInput Source = null;
                    if (sourceSchemaFileNameOption.HasValue())
                    {
                        Source = new TemplateInputFileSource(sourceSchemaFileNameOption.Value());
                    }
                    else
                    {
                        Source = new TemplateInputDatabaseConnecton(AppSettings.Instance.ConnectionString);
                    }

                    ITemplateInput CompareTo = null;
                    if (compareToSchemaFileNameOption.HasValue())
                    {
                        CompareTo = new TemplateInputFileSource(compareToSchemaFileNameOption.Value());
                    }
                    else if (compareToConnectionStringOption.HasValue())
                    {
                        CompareTo = new TemplateInputDatabaseConnecton(compareToConnectionStringOption.Value());
                    }

                    if (CompareTo == null)
                    {
                        Source.VerboseMessages = AppSettings.Instance.VerboseMessages;
                        returnCode             = CodeGen.ProcessTemplate(TemplateFileNameOrPath, Source, OutputPath);
                    }
                    else
                    {
                        Source.VerboseMessages    = AppSettings.Instance.VerboseMessages;
                        CompareTo.VerboseMessages = AppSettings.Instance.VerboseMessages;
                        returnCode = CodeGen.ProcessTemplate(TemplateFileNameOrPath, Source, CompareTo, OutputPath);
                    }

                    Console.WriteLine("Render of template " + templateFileNameOrDirectoryOption.Value() + " Completed!");
                    Environment.ExitCode = (int)returnCode.Result;
                    Environment.Exit(Environment.ExitCode);
                    return(Environment.ExitCode);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Could not render template. " + ex.Message);
                    Console.WriteLine("Stack Trace:");
                    Console.WriteLine(ex.StackTrace);
                    Environment.ExitCode = (int)ReturnCode.Error;
                    Environment.Exit(Environment.ExitCode);
                    return(Environment.ExitCode);
                }
            });
        }