private static ExecuteStatus ProcessFile(InputDataEx poInput, string psSourceFileName)
    {
        bool          lbHasError = false;
        ExecuteStatus ES         = new ExecuteStatus();

        string lsEntityNameSpace = null;
        string lsEntityClassName = null;
        string lsEntityBody      = null;

        string lsAllLines = string.Empty;
        string lsText;
        int    lsIndex = 0, lsLinesDone = 0;

        string[]      lasTokens;
        char[]        lacSplits = { ' ' };
        StringBuilder lsbProps  = new StringBuilder();

        log.Info(KEYS.FILE_NAME_LOG, psSourceFileName, poInput.SourceRootFolder);

        // Check if file exists, we dont want to overwrite customized code
        if (File.Exists(Path.Combine(poInput.DestinationFolder, psSourceFileName)))
        {
            log.Debug("\tFile Exist in destination, Not processing.");
            ES.ExitStatus = ReturnStatus.FILE_EXISTS;
            ES.Message    = psSourceFileName;
            ES.Messages.AppendLine("File Exists, skipping. " + psSourceFileName);
            return(ES);
        }

        try
        {
            foreach (string lsLine in File.ReadAllLines(Path.Combine(poInput.SourceRootFolder, psSourceFileName)))
            {
                lbHasError = false;                         // reset for each loop, we dont want carry-overs
                lsLinesDone++;

                if (lsLine.StartsWith(MC_KEY_NSPACE))
                {
                    lsText     = lsLine.Split(' ')[1] ?? string.Empty;                           // drop any comments after namespace
                    lbHasError = string.IsNullOrWhiteSpace(lsText);
                    if (lbHasError)
                    {
                        // create error note and exit
                    }
                    else
                    {
                        lsEntityNameSpace = lsText.Trim();
                        log.Debug("lsEntityNameSpace = {0}", lsEntityNameSpace);
                    }
                }
                else if (lsLine.StartsWith(MC_KEY_CLASS))
                {
                    lsIndex    = 0;
                    lsText     = lsLine.Remove(0, MC_KEY_CLASS.Length);
                    lbHasError = string.IsNullOrWhiteSpace(lsText);
                    if (lbHasError)
                    {
                        // create error note and exit
                    }
                    else
                    {
                        lsIndex = lsText.IndexOf(" ");
                        if (lsIndex > 0)
                        {
                            lsText = lsText.Substring(0, lsIndex);
                        }
                        lsEntityClassName = lsText.Trim();
                        log.Debug("lsEntityClassName = {0}", lsEntityClassName);
                    }
                }
                else if (lsLine.StartsWith(MC_KEY_PROP) && lsLine.Contains("{"))                                // Quick fix, identify constructor properly
                {
                    if (lsLine.StartsWith(MC_KEY_PROP_SKIP))
                    {
                        continue;                                       // Ignore reference keys
                    }
                    lsbProps.AppendLine();                              // need an blank line above to add annotations

                    // Also add default attribute to all properties, using property name
                    lasTokens = lsLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    lsbProps.AppendFormat(MC_DEF_ATTR_DISP, lasTokens[2], "\t\t\t");
                    lsbProps.AppendLine();
                    lsbProps.AppendLine(poInput.PropertyPadLeft + lsLine.Replace("    ", "\t"));
                    log.Debug("lsLine (Property) = {0}", lsLine);
                }

                if (lbHasError)
                {
                    // process errors for caller to get
                    log.Error(lsLine);
                    ES.Messages.AppendLine("Error Processing line");
                    ES.Messages.AppendLine(lsLine);
                    ES.Messages.AppendLine("of File > " + psSourceFileName);
                    //break;	// analyze errors to see if any code fix needed
                    continue;
                }
            }                       // foreach (string lsLine in

            log.Info("Lines Processed = {0}", lsLinesDone);
            lsEntityBody = lsbProps.ToString();
        }
        catch (Exception Ex)
        {
            log.Error(Ex, psSourceFileName);
            ES.ExitStatus = ReturnStatus.SRC_FILE_PROCESS_ERR;
            ES.Message    = psSourceFileName;
        }

        // Verify all tags have data

        if (
            string.IsNullOrWhiteSpace(lsEntityNameSpace) ||
            string.IsNullOrWhiteSpace(lsEntityClassName) ||
            string.IsNullOrWhiteSpace(lsEntityBody)
            )
        {
            log.Error(KEYS.DATA_MISSING);
            log.Error("lsEntityNameSpace = {0}", lsEntityNameSpace);
            log.Error("lsEntityClassName = {0}", lsEntityClassName);
            log.Error("lsEntityBody      = \n{0}", lsEntityBody);
            ES.ExitStatus = ReturnStatus.SOURCE_DATA_ERR;
            ES.Message    = psSourceFileName;
            return(ES);
        }

        //log.Debug("Replacing placeholders in template");
        //log.Debug("{0} -> {1}", poInput.NameSpaceTag, lsEntityNameSpace);
        //log.Debug("{0} -> {1}", poInput.NameSpaceAnnnoteTag, poInput.AnnotationNameSpaceSegment);
        //log.Debug("{0} -> {1}", poInput.ClassNameTag, lsEntityClassName);
        //log.Debug("{0} -> {1}", poInput.MetaClassSfxTag, poInput.MetaDataClassSuffix);
        //// log.Debug("{0} -> {1}", poInput.BodyTag, lsEntityBody);
        // log.Debug("INSPECT OUTPUT FOR CORRECTNESS");

        // Process the template
        lsEntityBody = poInput.MetaDataFileTemplate
                       .Replace(poInput.NameSpaceTag, lsEntityNameSpace)
                       .Replace(poInput.NameSpaceAnnnoteTag, poInput.AnnotationNameSpaceSegment)
                       .Replace(poInput.ClassNameTag, lsEntityClassName)
                       .Replace(poInput.MetaClassSfxTag, poInput.MetaDataClassSuffix)
                       .Replace(poInput.BodyTag, lsEntityBody)
        ;

        // Does destination exist? Create if needed,
        // do check just before write to avoid creating empty folders
        if (!Directory.Exists(poInput.DestinationFolder))
        {
            DirectoryInfo vNewDir = null;
            try
            {
                vNewDir = Directory.CreateDirectory(poInput.DestinationFolder);
            }
            catch (Exception eX)
            {
                // log the error
            }
            // Check Again, to see if it is created
            if (!Directory.Exists(poInput.DestinationFolder))
            {
                log.Error(KEYS.DEST_FOLDER_NOACCESS, poInput.DestinationFolder);
                ES.ExitStatus = ReturnStatus.DEST_DIR_NO_ACCESS;
                ES.Message    = poInput.DestinationFolder;
                return(ES);
            }
        }                   // if (!Directory.Exists(poInput.DestinationFolder))

        try
        {
            File.WriteAllText(Path.Combine(poInput.DestinationFolder, psSourceFileName), lsEntityBody);
            ES.FilesGenerated++;
            ES.ExitStatus = ReturnStatus.OK;
        }
        catch (Exception Ex)
        {
            log.Error(Ex, psSourceFileName);
            ES.ExitStatus = ReturnStatus.DEST_FILE_WRITE_ERR;
            ES.Message    = psSourceFileName;
        }

        return(ES);
    }
    public static int?Generate(InputData poInput)
    {
        // Validation
        // input readable
        // output writable

        // log.Debug("START public static int? Generate(InputData poInput)");

        int         liRetVal       = -1;
        string      lsTemplateFile = string.Empty;
        string      lsText         = string.Empty;
        InputDataEx loInput        = new InputDataEx(poInput);

        // Write out output recieved
        log.Info("Using INPUT DATA: _________  ");
        log.Info("          SourceRootFolder = '" + loInput.SourceRootFolder + "'");
        log.Info("         DestinationFolder = '" + loInput.DestinationFolder + "'");
        log.Info("       MetaDataClassSuffix = '" + loInput.MetaDataClassSuffix + "'");
        log.Info("AnnotationNameSpaceSegment = '" + loInput.AnnotationNameSpaceSegment + "'");
        log.Info("      MetaDataFileTemplate = '" + loInput.MetaDataFileTemplate + "'");
        log.Info("           PropertyPadLeft = '" + loInput.PropertyPadLeft + "'");

        log.Info("           DestinationRoot = '" + loInput.DestinationRoot + "'");
        log.Info("              NameSpaceTag = '" + loInput.NameSpaceTag + "'");
        log.Info("       NameSpaceAnnnoteTag = '" + loInput.NameSpaceAnnnoteTag + "'");
        log.Info("              ClassNameTag = '" + loInput.ClassNameTag + "'");
        log.Info("           MetaClassSfxTag = '" + loInput.MetaClassSfxTag + "'");
        log.Info("                   BodyTag = '" + loInput.BodyTag + "'");
        log.Info("");

        if (string.IsNullOrWhiteSpace(loInput.MetaDataFileTemplate))
        {
            lsTemplateFile = MC_DEF_TEMPLATE;
        }
        else if (File.Exists(loInput.MetaDataFileTemplate))
        {
            lsTemplateFile = loInput.MetaDataFileTemplate;
        }

        // If it is filename, get the contents
        if (!string.IsNullOrWhiteSpace(lsTemplateFile))
        {
            try
            {
                lsText = File.ReadAllText(lsTemplateFile);
                if (!string.IsNullOrWhiteSpace(lsText))
                {
                    loInput.MetaDataFileTemplate = lsText;
                }
                else
                {
                    liRetVal = (int)ReturnStatus.TEMPLATE_MISSING;
                }
            }
            catch (Exception Ex)
            {
                log.Error("Unable to get Template");
                liRetVal = (int)ReturnStatus.TEMPLATE_MISSING;
            }
        }

        // Check if all tags exist in the template
        lsText = loInput.MetaDataFileTemplate;
        if (
            (liRetVal <= 0) &&
            (lsText.Contains(loInput.NameSpaceTag)) &&
            (lsText.Contains(loInput.NameSpaceAnnnoteTag)) &&
            (lsText.Contains(loInput.ClassNameTag)) &&
            (lsText.Contains(loInput.MetaClassSfxTag)) &&
            (lsText.Contains(loInput.BodyTag))
            )
        {
            // TAGS ARE GOOD
        }
        else
        {
            log.Error("TEMPLATE DATA IS UNUSABLE");
            liRetVal = (int)ReturnStatus.TEMPLATE_FORMAT_BAD;
        }


        if (liRetVal > 0)
        {
            return(liRetVal);
        }


        // All GOOD, process now
        DateTime      ldtStart = DateTime.Now, ldtFinish;               // Report processing time
        ExecuteStatus ES = ProcessFolder(loInput);

        ldtFinish = DateTime.Now;
        liRetVal  = (int)ES.ExitStatus;

        // Write out summary
        log.Info("Processing Summary:");
        log.Info("Files Total : " + ES.FilesTotal);
        log.Info("in Folders  : " + ES.FoldersTotal);
        log.Info("Processed   : " + ES.FilesGenerated);
        log.Info("Started at  : " + ldtStart.ToString("HH:mm:ss.ffff"));
        log.Info("Finished at : " + ldtFinish.ToString("HH:mm:ss.ffff"));
        log.Info("Took (mS)   : " + ldtFinish.Subtract(ldtStart).TotalMilliseconds);


        return(liRetVal);
    }
    private static ExecuteStatus ProcessFolder(InputDataEx poInput)
    {
        ExecuteStatus voES, loES = new ExecuteStatus()
        {
            FoldersTotal = 1
        };

        log.Info(KEYS.FOLDER_NAME_LOG, poInput.SourceRootFolder);

        // Process all CS files
        foreach (string vsFilePath in Directory.EnumerateFiles(poInput.SourceRootFolder, "*.cs"))
        {
            voES = ProcessFile(poInput, Path.GetFileName(vsFilePath));                          // Pass only file name, need to getit again later
            loES.FilesTotal++;
            if (voES.ExitStatus == ReturnStatus.OK)
            {
                loES.FilesGenerated += voES.FilesGenerated;
            }
            else
            {
                // add message to list
                loES.Messages.AppendLine(voES.Message);
                loES.Messages.AppendLine(voES.Messages.ToString());
            }
        }                   // foreach (string vsFilePath in Dir

        // Process all Subfolders
        string lsDestFolder = poInput.DestinationFolder;                        // Remember stsrting folder, to POP

        foreach (string vSubDir in Directory.EnumerateDirectories(poInput.SourceRootFolder))
        {
            // if same as target dir, skip
            if (vSubDir == poInput.DestinationRoot)
            {
                log.Info(KEYS.SKIP_DESTINATION, vSubDir);
                loES.Messages.AppendFormat(KEYS.SKIP_DESTINATION, vSubDir);
                loES.Messages.AppendLine();
                continue;
            }

            // PUSH the subfolder
            poInput.SourceRootFolder  = vSubDir;
            poInput.DestinationFolder = Path.Combine(lsDestFolder, Path.GetFileName(vSubDir));

            // Call ourself, treating this as root
            voES = ProcessFolder(poInput);
            if (voES.ExitStatus == ReturnStatus.OK)
            {
                // Update counts for the report
                loES.FilesTotal     += voES.FilesTotal;
                loES.FoldersTotal   += voES.FoldersTotal;
                loES.FilesGenerated += voES.FilesGenerated;
            }
            else
            {
                // add messages to list. See if Enumeration is needed
                loES.Messages.AppendLine(voES.Messages.ToString());
            }
        }                   // foreach (string vSubDir in Dir

        loES.ExitStatus = ReturnStatus.OK;
        return(loES);
    }