/// <summary> It expands the morpheme chart to deal with the phoneme change phenomenon.</summary>
        /// <param name="from">- the index of the start segment position
        /// </param>
        /// <param name="front">- the front part of the string
        /// </param>
        /// <param name="back">- the next part of the string
        /// </param>
        /// <param name="ftag">- the morpheme tag of the front part
        /// </param>
        /// <param name="btag">- the morpheme tag of the next part
        /// </param>
        /// <param name="phoneme">- phoneme
        /// </param>
        public virtual void  phonemeChange(int from, System.String front, System.String back, int ftag, int btag, int phoneme)
        {
            TNODE node = null;
            int   size = 0;
            bool  x, y;
            int   next;
            int   nc_idx;

            // searches the system dictionary for the front part
            node = systemDic.fetch(front.ToCharArray());
            if (node != null && node.info_list != null)
            {
                size = node.info_list.Count;
            }

            Position pos = sp.getPosition(from);

            for (int i = 0; i < size; i++)
            {
                INFO info = node.info_list.Get_Renamed(i);

                // comparison of the morpheme tag of the front part
                x = tagSet.checkTagType(ftag, info.tag);

                // comparison of the phoneme of the front part
                y = tagSet.checkPhonemeType(phoneme, info.phoneme);

                if (x && y)
                {
                    next = altSegment(back);

                    if (checkChart(pos.morpheme, pos.morphCount, info.tag, info.phoneme, next, btag, front) == false)
                    {
                        nc_idx            = addMorpheme(info.tag, info.phoneme, next, btag);
                        chart[nc_idx].str = front;
                        pos.morpheme[pos.morphCount++] = nc_idx;
                    }
                    else
                    {
                        System.Console.Error.WriteLine("phonemeChange: exit");
                        System.Environment.Exit(0);
                    }
                }
            }
        }
        /// <summary> It performs morphological anlysis on the morpheme chart from the specified index in the chart.</summary>
        /// <param name="chartIndex">- the index of the chart to analyze
        /// </param>
        /// <param name="tagType">- the type of next morpheme
        /// </param>
        /// <returns> the number of analysis results
        /// </returns>
        private int analyze(int chartIndex, int tagType)
        {
            int               from, to;
            int               i, j, x, y;
            int               mp;
            char              c;
            int               nc_idx;
            TNODE             node;
            LinkedList <INFO> infoList = null;
            INFO              info     = null;

            int      sidx    = 1;
            int      uidx    = 1;
            int      nidx    = 1;
            Position fromPos = null;
            Position toPos   = null;
            Morpheme morph   = chart[chartIndex];

            from    = morph.nextPosition;
            fromPos = sp.getPosition(from);

            switch (sp.getPosition(from).state)
            {
            default:
                return(0);

            /* dictionary search */


            case SegmentPosition.SP_STATE_N:
                i         = 0;
                bufString = "";

                // searches all combinations of words segmented through the dictionaries
                for (to = from; to != SegmentPosition.POSITION_START_KEY; to = sp.nextPosition(to))
                {
                    toPos = sp.getPosition(to);
                    c     = toPos.key;

                    if (sidx != 0)
                    {
                        sidx = systemDic.node_look(c, sidx);
                    }
                    if (uidx != 0)
                    {
                        uidx = userDic.node_look(c, uidx);
                    }
                    if (nidx != 0)
                    {
                        nidx = numDic.node_look(c, nidx);
                    }

                    toPos.sIndex = sidx;
                    toPos.uIndex = uidx;
                    toPos.nIndex = nidx;

                    bufString       += c;
                    segmentPath[i++] = to;
                }

                nidx = 0;

                for (; i > 0; i--)
                {
                    to    = segmentPath[i - 1];
                    toPos = sp.getPosition(to);

                    // system dictionary
                    if (toPos.sIndex != 0)
                    {
                        node = systemDic.get_node(toPos.sIndex);
                        if ((infoList = node.info_list) != null)
                        {
                            for (j = 0; j < infoList.Count; j++)
                            {
                                info = infoList.Get_Renamed(j);

                                nc_idx            = addMorpheme(info.tag, info.phoneme, sp.nextPosition(to), 0);
                                chart[nc_idx].str = bufString.Substring(0, (i) - (0));
                                fromPos.morpheme[fromPos.morphCount++] = nc_idx;
                            }
                        }
                    }

                    // user dictionary
                    if (toPos.uIndex != 0)
                    {
                        node = userDic.get_node(toPos.uIndex);
                        if ((infoList = node.info_list) != null)
                        {
                            for (j = 0; j < infoList.Count; j++)
                            {
                                info              = infoList.Get_Renamed(j);
                                nc_idx            = addMorpheme(info.tag, info.phoneme, sp.nextPosition(to), 0);
                                chart[nc_idx].str = bufString.Substring(0, (i) - (0));
                                fromPos.morpheme[fromPos.morphCount++] = nc_idx;
                            }
                        }
                    }

                    // number dictionary
                    if (nidx == 0 && toPos.nIndex != 0)
                    {
                        if (numDic.isNum(toPos.nIndex))
                        {
                            nc_idx            = addMorpheme(tagSet.numTag, TagSet.PHONEME_TYPE_ALL, sp.nextPosition(to), 0);
                            chart[nc_idx].str = bufString.Substring(0, (i) - (0));
                            fromPos.morpheme[fromPos.morphCount++] = nc_idx;
                            nidx = toPos.nIndex;
                        }
                        else
                        {
                            nidx = 0;
                        }
                    }
                }

                fromPos.state = SegmentPosition.SP_STATE_D;

                /* chart expansion regarding various rules */
                goto case SegmentPosition.SP_STATE_D;

            case SegmentPosition.SP_STATE_D:
                exp.prule(from, morph.str, bufString, sp);
                sp.getPosition(from).state = SegmentPosition.SP_STATE_R;

                /* recursive processing */
                goto case SegmentPosition.SP_STATE_R;

            case SegmentPosition.SP_STATE_R:
                x = 0;
                for (i = 0; i < fromPos.morphCount; i++)
                {
                    mp = fromPos.morpheme[i];

                    // It prevents a recursive call for '습니다', which needs to be improved.
                    if (tagSet.checkTagType(tagType, chart[mp].tag) == false)
                    {
                        continue;
                    }

                    // It prevents some redundant processing
                    if (chart[mp].state == MORPHEME_STATE_INCOMPLETE)
                    {
                        y  = analyze(mp, chart[mp].nextTagType);
                        x += y;

                        if (y != 0)
                        {
                            chart[mp].state = MORPHEME_STATE_SUCCESS;
                        }
                        else
                        {
                            chart[mp].state = MORPHEME_STATE_FAIL;
                        }
                    }
                    else
                    {
                        x += chart[mp].connectionCount;
                    }
                }

                if (x == 0)
                {
                    if (tagType == TagSet.TAG_TYPE_ALL)
                    {
                        fromPos.state = SegmentPosition.SP_STATE_F;
                    }
                    return(0);
                }

                if (tagType == TagSet.TAG_TYPE_ALL)
                {
                    fromPos.state = SegmentPosition.SP_STATE_M;
                }

                /* connecton rule */
                goto case SegmentPosition.SP_STATE_M;

            case SegmentPosition.SP_STATE_M:
                for (i = 0; i < fromPos.morphCount; i++)
                {
                    mp = fromPos.morpheme[i];

                    if (chart[mp].state == MORPHEME_STATE_SUCCESS && connection.checkConnection(tagSet, morph.tag, chart[mp].tag, morph.str.Length, chart[mp].str.Length, morph.nextTagType))
                    {
                        morph.connection[morph.connectionCount++] = mp;
                    }
                }
                break;
            }
            return(morph.connectionCount);
        }