/// <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;
            }
        }