internal TranslationUnit GetTranslationUnit(UIDataString key)
        {
            switch (key.Type)
            {
            case LocalizableStringType.Category:
                return(Localizations.Categories.TranslationUnits.FirstOrDefault(tu => tu.English == key.SourceUIString));

            case LocalizableStringType.SectionHeading:
                return(Localizations.Groups.FirstOrDefault(g => g.Id == FileBody.GetSectionId(key))?.TranslationUnits.Single());

            case LocalizableStringType.Question:
                return(Localizations.FindQuestionGroup(key)?.TranslationUnits.Single());

            case LocalizableStringType.Alternate:
            case LocalizableStringType.Answer:
            case LocalizableStringType.Note:
                return(Localizations.FindQuestionGroup(key)?.GetQuestionSubGroup(key.Type)?.TranslationUnits.SingleOrDefault(tu => tu.English == key.SourceUIString));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
        internal TranslationUnit GetLocalizableStringInfo(UIDataString key)
        {
            if (String.IsNullOrWhiteSpace(key?.SourceUIString))
            {
                return(null);
            }

            if (key.Type == LocalizableStringType.Category)
            {
                return(Localizations.Categories.TranslationUnits.SingleOrDefault(tu => tu.English == key.SourceUIString));
            }
            if (key.Type == LocalizableStringType.SectionHeading)
            {
                return(Localizations.Groups.SingleOrDefault(g => g.Id == FileBody.GetSectionId(key))?.TranslationUnits?.Single());
            }

            var question = Localizations.FindQuestionGroup(key);

            if (question == null)
            {
                return(null);
            }
            switch (key.Type)
            {
            case LocalizableStringType.Question:
                return(question.TranslationUnits?.SingleOrDefault());

            case LocalizableStringType.Answer:
            case LocalizableStringType.Note:
            case LocalizableStringType.Alternate:
                return(question.GetQuestionSubGroup(key.Type)?.
                       TranslationUnits.SingleOrDefault(tu => tu.English == key.SourceUIString));

            default:
                throw new Exception("Unhandled type!");
            }
        }
        public TranslationUnit AddLocalizationEntry(UIDataString data, string localizedString = null, bool isLocalized = true, int specificSection = 0)
        {
            if (String.IsNullOrWhiteSpace(data?.SourceUIString))
            {
                throw new ArgumentException("Invalid key!", nameof(data));
            }

            InitializeLookupTable();

            TranslationUnit existing;
            Group           group = null;
            var             type  = data.Type;

            if (type == LocalizableStringType.Category)
            {
                existing = Localizations.Categories.TranslationUnits.SingleOrDefault(c => c.Id == data.SourceUIString);
                if (existing == null)
                {
                    return(Localizations.Categories.AddTranslationUnit(data, localizedString, isLocalized));
                }
            }
            else if (type == LocalizableStringType.SectionHeading)
            {
                var id = FileBody.GetSectionId(data);
                existing = Localizations.Groups.FirstOrDefault(g => g.Id == id)?.TranslationUnits.Single();
                if (existing == null)
                {
                    var sectionGroup = new Group {
                        Id = id
                    };
                    Localizations.Groups.Add(sectionGroup);
                    sectionGroup.SubGroups = new List <Group>();
                    return(sectionGroup.AddTranslationUnit(data, localizedString, isLocalized));
                }
            }
            else
            {
                var sectionGroup = Localizations.FindSectionsForQuestion(data).Skip(specificSection).FirstOrDefault();
                Debug.Assert(sectionGroup != null);
                group = sectionGroup.FindQuestionGroup(data.Question) ?? AddQuestionGroup(sectionGroup, data);
                switch (type)
                {
                case LocalizableStringType.Question:
                    existing = group.TranslationUnits?.FirstOrDefault();
                    break;

                case LocalizableStringType.Alternate:
                    group    = group.SubGroups?.SingleOrDefault(g => g.Id == FileBody.kAlternatesGroupId) ?? group.AddSubGroup(FileBody.kAlternatesGroupId);
                    existing = group.TranslationUnits?.FirstOrDefault(a => a.English == data.SourceUIString);
                    break;

                case LocalizableStringType.Answer:
                    group    = group.SubGroups?.SingleOrDefault(g => g.Id == FileBody.kAnswersGroupId) ?? group.AddSubGroup(FileBody.kAnswersGroupId);
                    existing = group.TranslationUnits?.FirstOrDefault(a => a.English == data.SourceUIString);
                    break;

                case LocalizableStringType.Note:
                    group    = group.SubGroups?.SingleOrDefault(g => g.Id == FileBody.kNotesGroupId) ?? group.AddSubGroup(FileBody.kNotesGroupId);
                    existing = group.TranslationUnits?.FirstOrDefault(a => a.English == data.SourceUIString);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            if (existing == null)
            {
                Debug.Assert(group != null);
                return(group.AddTranslationUnit(data, localizedString, isLocalized));
            }
            existing.Target.Text        = localizedString;
            existing.Target.IsLocalized = isLocalized;
            return(existing);
        }
        internal void GenerateOrUpdateFromMasterQuestions(QuestionSections questions, List <XmlTranslation> existingTxlTranslations = null, bool retainOnlyTranslatedStrings = false)
        {
            InitializeLookupTable();

            // Note: there are two possible sources for existing localized translations of strings: either a Transcelerator project
            // (the list passed into this method), or the content read from a previous version of the file represented by this accessor.
            var existingLocalizations = XliffRoot.File.Body;

            existingLocalizations.DeleteGroupsWithoutLocalizations();
            if (existingLocalizations.Groups == null)
            {
                existingLocalizations = null;
            }

            if (existingTxlTranslations == null && retainOnlyTranslatedStrings)
            {
                return;
            }

            InitializeLocalizations();

            if (existingTxlTranslations == null)
            {
                if (existingLocalizations == null)
                {
                    AddTranslationUnit = (group, data) => group.AddTranslationUnit(data);
                }
                else
                {
                    AddTranslationUnit = (group, data) =>
                    {
                        var tu = existingLocalizations.GetStringLocalization(data);
                        if (tu == null)
                        {
                            group.AddTranslationUnit(data);
                        }
                        else
                        {
                            group.AddTranslationUnit(tu);
                        }
                    };
                }
            }
            else
            {
                if (existingLocalizations == null)
                {
                    AddTranslationUnit = (group, data) =>
                    {
                        group.AddTranslationUnit(data, LookupTranslation(existingTxlTranslations, data));
                    };
                }
                else
                {
                    AddTranslationUnit = (group, data) =>
                    {
                        var tu = existingLocalizations.GetStringLocalization(data);
                        if (tu == null)
                        {
                            group.AddTranslationUnit(data, LookupTranslation(existingTxlTranslations, data));
                        }
                        else
                        {
                            group.AddTranslationUnit(tu);
                        }
                    };
                }
            }

            UIDataString key;

            foreach (var section in questions.Items)
            {
                var sectionGroup = new Group {
                    Id = FileBody.GetSectionId(section)
                };
                Localizations.Groups.Add(sectionGroup);
                key = new UISectionHeadDataString(new SectionInfo(section));
                AddTranslationUnit(sectionGroup, key);

                foreach (Category category in section.Categories)
                {
                    var categoryGroup = sectionGroup.AddSubGroup(category.Type);
                    if (category.Type != null)
                    {
                        if (!Localizations.Categories.TranslationUnits.Any(tu => tu.English == category.Type))
                        {
                            key = new UISimpleDataString(category.Type, LocalizableStringType.Category);
                            AddTranslationUnit(Localizations.Categories, key);
                        }
                    }

                    foreach (Question q in category.Questions.Where(q => !String.IsNullOrWhiteSpace(q.Text)))
                    {
                        if (q.ScriptureReference == null)
                        {
                            q.ScriptureReference = section.ScriptureReference;
                            q.StartRef           = section.StartRef;
                            q.EndRef             = section.EndRef;
                        }
                        // The following line handles the unusual case of the same question twice in the same verse.
                        var questionGroup = categoryGroup.SubGroups?.SingleOrDefault(qg => qg.Id == $"{FileBody.kQuestionIdPrefix}{q.ScriptureReference}+{q.PhraseInUse}");
                        if (questionGroup == null)
                        {
                            questionGroup = categoryGroup.AddSubGroup($"{FileBody.kQuestionIdPrefix}{q.ScriptureReference}+{q.PhraseInUse}");
                            key           = new UIQuestionDataString(q, true, false);
                            AddTranslationUnit(questionGroup, key);
                        }

                        AddAlternatesSubgroupAndLocalizableStringsIfNeeded(q, questionGroup);
                        AddAnswerOrNoteSubgroupAndLocalizableStringsIfNeeded(q, questionGroup, LocalizableStringType.Answer, qu => qu.Answers);
                        AddAnswerOrNoteSubgroupAndLocalizableStringsIfNeeded(q, questionGroup, LocalizableStringType.Note, qu => qu.Notes);
                    }
                }
            }

            if (retainOnlyTranslatedStrings)
            {
                Localizations.DeleteGroupsWithoutLocalizations();
            }

            AddTranslationUnit = null;
        }