private async Task <bool> StreamAndSaveObservation(ContentURI docToCalcURI,
                                                           IDictionary <string, string> fileOrFolderPaths, bool hasInitialColumnDictionary)
        {
            bool   bHasObservation = false;
            string sId             = string.Empty;
            string sFileToAnalyze  = string.Empty;
            int    i = 0;

            WriteColumnNameRow();
            foreach (KeyValuePair <string, string> kvp in fileOrFolderPaths)
            {
                sId            = kvp.Key;
                sFileToAnalyze = kvp.Value;
                if (await Helpers.FileStorageIO.URIAbsoluteExists(
                        docToCalcURI, sFileToAnalyze))
                {
                    FileToAnalyzeReader
                        = await Helpers.FileStorageIO.GetXmlReaderAsync(docToCalcURI, sFileToAnalyze);

                    if (FileToAnalyzeReader != null)
                    {
                        using (FileToAnalyzeReader)
                        {
                            FileToAnalyzeReader.MoveToContent();
                            Ancestors.Clear();
                            AddObservations(docToCalcURI,
                                            hasInitialColumnDictionary);
                        }
                    }
                    if (docToCalcURI.ErrorMessage != string.Empty)
                    {
                        //fix all errors before running an analysis
                        break;
                    }
                    i++;
                }
            }
            if (docToCalcURI.ErrorMessage == string.Empty)
            {
                if (hasInitialColumnDictionary)
                {
                    //save the observations file
                    TextFile.Flush();
                    bHasObservation = true;
                }
            }
            return(bHasObservation);
        }
        //allows derived classes to override the default streaming
        //and save method
        public async Task <bool> StreamAndSaveObservation(ContentURI docToCalcURI,
                                                          IDictionary <string, string> fileOrFolderPaths)
        {
            HasGoodObservationFile = false;
            if (fileOrFolderPaths == null)
            {
                docToCalcURI.ErrorMessage
                    = DevTreks.Exceptions.DevTreksErrors.GetMessage("OBSERVATIONS_NOFILES_SAVETEXT");
                return(false);
            }
            else
            {
                if (fileOrFolderPaths.Count <= 0)
                {
                    docToCalcURI.ErrorMessage
                        = DevTreks.Exceptions.DevTreksErrors.GetMessage("OBSERVATIONS_NOFILES_SAVETEXT");
                    return(false);
                }
            }
            bool   bHasInitialColumnDictionary = InitColumnDictionary();
            string sObservationsPath
                = GetObservationFilePath(docToCalcURI.URIDataManager.TempDocPath);

            if (!string.IsNullOrEmpty(sObservationsPath))
            {
                try
                {
                    using (TextFile =
                               new StreamWriter(sObservationsPath))
                    {
                        string sId            = string.Empty;
                        string sFileToAnalyze = string.Empty;
                        int    i = 0;
                        //file order is not relevant in this addin,
                        //but parallel won't work (yet) because of the way
                        //the observationRoot gets built
                        foreach (KeyValuePair <string, string> kvp
                                 in fileOrFolderPaths)
                        {
                            sId            = kvp.Key;
                            sFileToAnalyze = kvp.Value;
                            if (await Helpers.FileStorageIO.URIAbsoluteExists(
                                    docToCalcURI, sFileToAnalyze))
                            {
                                //stream and add the calculation (observation)
                                //to the observationsRoot
                                if (!await Helpers.FileStorageIO.URIAbsoluteExists(
                                        docToCalcURI, sFileToAnalyze))
                                {
                                    return(HasGoodObservationFile);
                                }
                                FileToAnalyzeReader = await Helpers.FileStorageIO.GetXmlReaderAsync(docToCalcURI, sFileToAnalyze);

                                if (FileToAnalyzeReader != null)
                                {
                                    using (FileToAnalyzeReader)
                                    {
                                        FileToAnalyzeReader.MoveToContent();
                                        Ancestors.Clear();
                                        CurrentNodeName
                                            = string.Empty;
                                        ParentNodeName
                                                        = string.Empty;
                                        LinkedViewCount = 0;
                                        AddObservations(docToCalcURI, bHasInitialColumnDictionary);
                                    }
                                }
                                if (docToCalcURI.ErrorMessage != string.Empty)
                                {
                                    //fix all errors before running an analysis
                                    docToCalcURI.ErrorMessage
                                        = docToCalcURI.ErrorMessage;
                                    break;
                                }
                                i++;
                            }
                        }
                        if (docToCalcURI.ErrorMessage == string.Empty)
                        {
                            //subroutine builds the observations
                            bHasInitialColumnDictionary = true;
                            HasGoodObservationFile      = await StreamAndSaveObservation(docToCalcURI, fileOrFolderPaths,
                                                                                         bHasInitialColumnDictionary);
                        }
                    }
                }
                catch (Exception x)
                {
                    docToCalcURI.ErrorMessage = x.ToString();
                    TextFile.Dispose();
                }
            }
            return(HasGoodObservationFile);
        }