/// <summary>
        /// Sets the number of occurrences of a context.
        /// </summary>
        /// <param name="min">The min.</param>
        /// <param name="max">The max.</param>
        public void SetContextOccurrence(int min, int max)
        {
            CheckDisposed();
            SelectionHelper sel    = SelectionHelper.Create(m_view);
            int             cellId = GetCell(sel);
            int             hvo    = GetItemHvo(sel, SelectionHelper.SelLimitType.Anchor);
            IPhPhonContext  ctxt   = PhPhonContext.CreateFromDBObject(m_cache, hvo);
            int             index  = -1;

            using (new UndoRedoTaskHelper(m_cache, MEStrings.ksRegRuleUndoSetOccurrence, MEStrings.ksRegRuleRedoSetOccurrence))
            {
                if (ctxt.ClassID == PhIterationContext.kclsidPhIterationContext)
                {
                    // if there is an existing iteration context, just update it or remove it if it can occur only once
                    IPhIterationContext iterCtxt = ctxt as IPhIterationContext;
                    if (min == 1 && max == 1)
                    {
                        index = OverwriteContext(iterCtxt.MemberRA, iterCtxt, cellId == (int)PhSegRuleRHS.PhSegRuleRHSTags.kflidLeftContext, false);
                    }
                    else
                    {
                        iterCtxt.Minimum = min;
                        iterCtxt.Maximum = max;
                    }
                }
                else if (min != 1 || max != 1)
                {
                    // create a new iteration context
                    IPhIterationContext iterCtxt = new PhIterationContext();
                    index = OverwriteContext(iterCtxt, ctxt, cellId == (int)PhSegRuleRHS.PhSegRuleRHSTags.kflidLeftContext, true);
                    iterCtxt.MemberRAHvo = ctxt.Hvo;
                    iterCtxt.Minimum     = min;
                    iterCtxt.Maximum     = max;
                    iterCtxt.NotifyNew();
                }
            }

            if (index == -1)
            {
                IPhPhonContext     envCtxt = cellId == (int)PhSegRuleRHS.PhSegRuleRHSTags.kflidLeftContext ? RHS.LeftContextOA : RHS.RightContextOA;
                IPhSequenceContext seqCtxt;
                index = GetIndex(ctxt, envCtxt, out seqCtxt);
            }

            ReconstructView(cellId, index, true);
        }
        /// <summary>
        /// Parses the string representation of the specified environment and creates contexts
        /// based off of the environment. This is called recursively.
        /// </summary>
        /// <param name="envStr">The environment string.</param>
        /// <param name="leftEnv">if <c>true</c> insert in the left context, otherwise the right context.</param>
        /// <param name="iterCtxt">The iteration context to insert into.</param>
        void InsertContextsFromEnv(string envStr, int flid, IPhIterationContext iterCtxt)
        {
            int i = 0;

            while (i < envStr.Length)
            {
                switch (envStr[i])
                {
                case '#':
                    IPhSimpleContextBdry bdryCtxt = new PhSimpleContextBdry();
                    AppendToEnv(bdryCtxt, flid);
                    bdryCtxt.FeatureStructureRAHvo = m_cache.GetIdFromGuid(LangProject.kguidPhRuleWordBdry);
                    bdryCtxt.NotifyNew();
                    i++;
                    break;

                case '[':
                    int    closeBracket = envStr.IndexOf(']', i + 1);
                    string ncAbbr       = envStr.Substring(i + 1, closeBracket - (i + 1));
                    int    redupIndex   = ncAbbr.IndexOf('^');
                    if (redupIndex != -1)
                    {
                        ncAbbr = ncAbbr.Substring(0, redupIndex);
                    }
                    foreach (IPhNaturalClass nc in m_cache.LangProject.PhonologicalDataOA.NaturalClassesOS)
                    {
                        if (nc.Abbreviation.BestAnalysisAlternative.Text == ncAbbr)
                        {
                            IPhSimpleContextNC ncCtxt = new PhSimpleContextNC();
                            if (iterCtxt != null)
                            {
                                m_cache.LangProject.PhonologicalDataOA.ContextsOS.Append(ncCtxt);
                                iterCtxt.MemberRAHvo = ncCtxt.Hvo;
                            }
                            else
                            {
                                AppendToEnv(ncCtxt, flid);
                            }
                            ncCtxt.FeatureStructureRAHvo = nc.Hvo;
                            ncCtxt.NotifyNew();
                            break;
                        }
                    }
                    i = closeBracket + 1;
                    break;

                case '(':
                    int    closeParen = envStr.IndexOf(')', i + 1);
                    string str        = envStr.Substring(i + 1, closeParen - (i + 1));
                    IPhIterationContext newIterCtxt = new PhIterationContext();
                    AppendToEnv(newIterCtxt, flid);
                    newIterCtxt.Minimum = 0;
                    newIterCtxt.Maximum = 1;
                    InsertContextsFromEnv(str, flid, newIterCtxt);
                    newIterCtxt.NotifyNew();
                    i = closeParen + 1;
                    break;

                case ' ':
                    i++;
                    break;

                default:
                    int nextIndex = envStr.IndexOfAny(new char[] { '[', ' ', '#', '(' }, i + 1);
                    if (nextIndex == -1)
                    {
                        nextIndex = envStr.Length;
                    }
                    int len = nextIndex - i;
                    while (len > 0)
                    {
                        string phonemeStr = envStr.Substring(i, len);
                        foreach (IPhPhoneme phoneme in m_cache.LangProject.PhonologicalDataOA.PhonemeSetsOS[0].PhonemesOC)
                        {
                            foreach (IPhCode code in phoneme.CodesOS)
                            {
                                if (code.Representation.BestVernacularAlternative.Text == phonemeStr)
                                {
                                    IPhSimpleContextSeg segCtxt = new PhSimpleContextSeg();
                                    if (iterCtxt != null)
                                    {
                                        m_cache.LangProject.PhonologicalDataOA.ContextsOS.Append(segCtxt);
                                        iterCtxt.MemberRAHvo = segCtxt.Hvo;
                                    }
                                    else
                                    {
                                        AppendToEnv(segCtxt, flid);
                                    }
                                    segCtxt.FeatureStructureRAHvo = phoneme.Hvo;
                                    segCtxt.NotifyNew();
                                    goto Found;
                                }
                            }
                        }
                        len--;
                    }
Found:

                    if (len == 0)
                    {
                        i++;
                    }
                    else
                    {
                        i += len;
                    }
                    break;
                }
            }
        }