/*
 * Copyright (C) Bernhard Seybold. All rights reserved.
 *
 * This software is published under the terms of the LGPL Software License,
 * a copy of which has been included with this distribution in the LICENSE.txt
 * file.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *
 * $Id: PGNWriter.java,v 1.2 2003/01/04 16:15:02 BerniMan Exp $
 */

package chesspresso.pgn;


import java.io.PrintWriter;
import java.io.Writer;

import chesspresso.Chess;
import chesspresso.game.Game;
import chesspresso.game.GameListener;
import chesspresso.game.GameModel;
import chesspresso.game.GameModelIterator;
import chesspresso.move.Move;
import chesspresso.position.FEN;


/**
 * A PGN writer is able to write a game (collection) in PGN syntax.
 *
 * @author  Bernhard Seybold
 * @version $Revision: 1.2 $
 */
public class PGNWriter extends PGN
{

    private PrintWriter m_out;
    private int m_charactersPerLine;
    private int m_curCol;

    /*================================================================================*/

    public PGNWriter(Writer out)
    {
        this(new PrintWriter(out));
    }

    public PGNWriter(PrintWriter out)
    {
        m_out = out;
        setCharactersPerLine(80);
    }

    /*================================================================================*/

    public void setCharactersPerLine(int chars) {m_charactersPerLine = chars;}

    public void write(GameModelIterator iterator)
    {
        while (iterator.hasNext()) {
            write(iterator.nextGameModel());
            m_out.println();
        }
    }

    public void write(GameModel gameModel)
    {
        Game game = new Game(gameModel);
        writeHeader(game);
        m_out.println();
        m_curCol = 0;
        writeMoves(game);
        if (m_curCol > 0) m_out.println();
    }

    /*================================================================================*/

    private void writeHeader(Game game)
    {
        m_out.println(TOK_TAG_BEGIN + TAG_EVENT  + " " + TOK_QUOTE + game.getEvent()     + TOK_QUOTE + TOK_TAG_END);
        m_out.println(TOK_TAG_BEGIN + TAG_SITE   + " " + TOK_QUOTE + game.getSite()      + TOK_QUOTE + TOK_TAG_END);
        m_out.println(TOK_TAG_BEGIN + TAG_DATE   + " " + TOK_QUOTE + game.getDate()      + TOK_QUOTE + TOK_TAG_END);
        m_out.println(TOK_TAG_BEGIN + TAG_ROUND  + " " + TOK_QUOTE + game.getRound()     + TOK_QUOTE + TOK_TAG_END);
        m_out.println(TOK_TAG_BEGIN + TAG_WHITE  + " " + TOK_QUOTE + game.getWhite()     + TOK_QUOTE + TOK_TAG_END);
        m_out.println(TOK_TAG_BEGIN + TAG_BLACK  + " " + TOK_QUOTE + game.getBlack()     + TOK_QUOTE + TOK_TAG_END);
        m_out.println(TOK_TAG_BEGIN + TAG_RESULT + " " + TOK_QUOTE + game.getResultStr() + TOK_QUOTE + TOK_TAG_END);

        if (game.getWhiteEloStr() != null)
            m_out.println(TOK_TAG_BEGIN + TAG_WHITE_ELO  + " " + TOK_QUOTE + game.getWhiteElo()  + TOK_QUOTE + TOK_TAG_END);
        if (game.getBlackEloStr() != null)
            m_out.println(TOK_TAG_BEGIN + TAG_BLACK_ELO  + " " + TOK_QUOTE + game.getBlackElo()  + TOK_QUOTE + TOK_TAG_END);
        if (game.getEventDate() != null)
            m_out.println(TOK_TAG_BEGIN + TAG_EVENT_DATE + " " + TOK_QUOTE + game.getEventDate() + TOK_QUOTE + TOK_TAG_END);
        if (game.getECO() != null)
            m_out.println(TOK_TAG_BEGIN + TAG_ECO        + " " + TOK_QUOTE + game.getECO()       + TOK_QUOTE + TOK_TAG_END);

        if (!game.getPosition().isStartPosition())
            m_out.println(TOK_TAG_BEGIN + TAG_FEN        + " " + TOK_QUOTE + FEN.getFEN(game.getPosition()) + TOK_QUOTE + TOK_TAG_END);
    }

    public void writeMoves(Game game)
    {
        game.gotoStart();
        // print leading comments before move 1
        String comment = game.getComment();
        if (comment != null) {
            print(TOK_COMMENT_BEGIN + comment + TOK_COMMENT_END, true);
        }

        game.traverse(new GameListener() {
            private boolean needsMoveNumber = true;

            @Override
			public void notifyMove(Move move, char[] nags, String preMoveComment, String postMoveComment,
            		int plyNumber, int level)
            {
				if (preMoveComment != null) {
					print(TOK_COMMENT_BEGIN + preMoveComment + TOK_COMMENT_END, true);
				}

				if (needsMoveNumber) {
                    if (move.isWhiteMove()) {
                        print(Chess.plyToMoveNumber(plyNumber) + ".", true);
                    } else {
                        print(Chess.plyToMoveNumber(plyNumber) + "...", true);
                    }
                }
                print(move.toString(), true);

                if (nags != null) {
                    for (int i=0; i < nags.length; i++) {
                        print(String.valueOf(TOK_NAG_BEGIN) + String.valueOf(nags[i]), true);
                    }
                }
                if (postMoveComment != null) print(TOK_COMMENT_BEGIN + postMoveComment + TOK_COMMENT_END, true);
                needsMoveNumber = !move.isWhiteMove() || (postMoveComment != null);
            }

            @Override
			public void notifyLineStart(int level)
            {
                print(String.valueOf(TOK_LINE_BEGIN), false);
                needsMoveNumber = true;
            }

            @Override
			public void notifyLineEnd(int level)
            {
                print(String.valueOf(TOK_LINE_END), true);
                needsMoveNumber = true;
            }
        }, true);

        print(game.getResultStr(), false);
    }

    private void print(String s, boolean addSpace)
    {
        if (m_curCol + s.length() > m_charactersPerLine) {
            m_out.println();
            m_curCol = 0;
        }
        m_out.print(s);
        m_curCol += s.length();
        if (m_curCol > 0 && addSpace) {
            m_out.print(" ");
            m_curCol += 1;
        }
    }
}
@@ -5084,16 +5084,21 @@
 valueOf(
+(int)
 nags%5Bi%5D)

fix invalid NAG writing