public PgnData()
 {
     coRegex       = new Regex("^\\[([A-Za-z]*) \"(.*)\"", RegexOptions.Compiled);
     coValue       = new System.Text.StringBuilder();
     coState       = GameParserState.State.HEADER;
     coPeriodCount = 0;
 }
        /// <summary>
        /// Calls the correct event based on the parsers state.
        /// </summary>
        /// <param name="state"></param>
        void callEvent(GameParserState.State state)
        {
            if (coValue.Length > 0)
            {
                switch (state)
                {
                case GameParserState.State.COMMENT:
                    if (EventCommentParsed != null)
                    {
                        EventCommentParsed(this);
                    }
                    break;

                case GameParserState.State.NAGS:
                    if (EventNagParsed != null)
                    {
                        EventNagParsed(this);
                    }
                    break;

                case GameParserState.State.NUMBER:
                    if (EventMoveParsed != null)
                    {
                        EventMoveParsed(this);
                    }
                    coState = GameParserState.State.COLOR;
                    break;

                case GameParserState.State.WHITE:
                    if (EventMoveParsed != null)
                    {
                        EventMoveParsed(this);
                    }
                    coState = GameParserState.State.BLACK;
                    break;

                case GameParserState.State.BLACK:
                    if (EventMoveParsed != null)
                    {
                        EventMoveParsed(this);
                    }
                    coState = GameParserState.State.NUMBER;
                    break;
                }
            }

            // Always clear out our data as the handler should have used this value during the event.
            coValue.Length = 0;
        }
        void handleChar(char aChar)
        {
            switch (aChar)
            {
            case '{':
                callEvent(coState);
                coPrevState = coState;
                coState     = GameParserState.State.COMMENT;
                break;

            case '(':
                if (EventEnterVariation != null)
                {
                    EventEnterVariation(this);
                }
                break;

            case ')':
                if (EventExitVariation != null)
                {
                    EventExitVariation(this);
                }
                break;

            case ' ':
                // Only if we have some data do we want to fire an event.
                callEvent(coState);
                break;

            case '.':
                // We may have come across 6. e4 6... d5 as in our example data.
                coState = GameParserState.State.NUMBER;
                callEvent(coState);
                coPeriodCount = 1;
                break;

            case '$':
                callEvent(coState);
                coPrevState = coState;
                coState     = GameParserState.State.NAGS;
                break;

            default:
                coValue.Append(aChar);
                break;
            }
        }
        public void parse()
        {
            System.IO.StreamReader reader = new System.IO.StreamReader(coFilename);

            long position = 0;

            for (coData = reader.ReadLine();
                 coData != null;
                 coData = reader.ReadLine())
            {
                if (coData.Length > 0)
                {
                    if (Regex.IsMatch(coData, "^\\["))
                    {
                        if (coNextGame == false)
                        {
                            callEvent(coState);

                            coNextGame = true;
                            if (EventNewGame != null)
                            {
                                EventNewGame(this);
                            }
                        }
                        coState = GameParserState.State.HEADER;
                        parseTag(coData);
                        coValue.Length = 0;
                    }
                    else
                    {
                        if (coNextGame)
                        {
                            coNextGame = false;
                        }
                        parseDetail(coData);
                    }
                    position += coData.Length + 2;
                }
            }
            callEvent(coState);
            reader.Close();
            if (EventFinished != null)
            {
                EventFinished(this);
            }
        }
        public void parseDetail(string line)
        {
            foreach (char aChar in line)
            {
                // Handle any special processing of our text.
                switch (coState)
                {
                case GameParserState.State.COMMENT:
                    if (aChar == '}')
                    {
                        callEvent(coState);
                        coState = coPrevState;
                    }
                    else
                    {
                        coValue.Append(aChar);
                    }
                    break;

                case GameParserState.State.NAGS:
                    if (aChar >= '0' && aChar <= '9')
                    {
                        coValue.Append(aChar);
                    }
                    else
                    {
                        callEvent(coState);
                        coState = coPrevState;
                        handleChar(aChar);
                    }
                    break;

                case GameParserState.State.COLOR:
                    if (aChar == '.')
                    {
                        coPeriodCount++;
                    }
                    else
                    {
                        coValue.Length = 0;
                        if (coPeriodCount == 1)
                        {
                            coState = GameParserState.State.WHITE;
                        }
                        else if (coPeriodCount > 1)
                        {
                            coState = GameParserState.State.BLACK;
                        }
                        handleChar(aChar);
                        coPeriodCount = 0;
                    }
                    break;

                default:
                    handleChar(aChar);
                    break;
                }
            }
            // Ensure we add a space between comment lines that are broken appart.
            if (coState == GameParserState.State.COMMENT)
            {
                coValue.Append(' ');
            }
            else
            {
                callEvent(coState);
            }
        }