#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# This file is part of the python-chess library.
# Copyright (C) 2012-2014 Niklas Fiekas <niklas.fiekas@tu-clausthal.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import argparse
import chess
import collections
import json
import sys

def read_eco(source):
    result = { }

    tokens = collections.deque()

    eco = None
    name = None
    position = chess.Bitboard()
    state = 0

    for lineno, unstripped_line in enumerate(source):
        # Skip emtpy lines and comments.
        line = unstripped_line.strip()
        if not line or line.startswith("#"):
            continue

        # Split line into tokens.
        tokens.extend(line.split())

        # Consume tokens on the fly.
        while tokens:
            try:
                token = tokens.popleft()

                if state == 0:
                    # State 0: Expecting ECO code.
                    eco = token
                    if eco in result:
                        state = 4
                    else:
                        state = 1
                elif state == 1:
                    # State 1: Expecting variation name.
                    if not token.startswith("\""):
                        name = token
                        state = 3
                    elif not token.endswith("\""):
                        name = token[1:]
                        state = 2
                    else:
                        name = token[1:-1]
                        state = 3
                elif state == 2:
                    # State 2: Expecting rest of a quoted name.
                    if not token.endswith("\""):
                        name += " " + token
                    else:
                        name += " " + token[:-1]
                        state = 3
                elif state == 3:
                    # State 3: Expecting moves.
                    if token == "*":
                        result[eco] = {
                            "eco": eco,
                            "fen": position.fen(),
                            "hash": position.__hash__(),
                            "name": name,
                        }
                        state = 0
                        eco = None
                        name = None
                        position = chess.Bitboard()
                    else:
                        san = token.split(".")[-1]
                        if san in ["0-0", "o-o"]:
                            san = "O-O"
                        elif san in ["0-0-0", "o-o-o"]:
                            san = "O-O-O"
                        position.push_san(san)
                elif state == 4:
                    # State 4: Waiting for end of record.
                    if token == "*":
                        state = 0
            except:
                # Dump last line and token.
                sys.stderr.write("Line %d:\n" % (lineno + 1, ))
                sys.stderr.write("  ")
                sys.stderr.write(unstripped_line)
                sys.stderr.write("  ")
                sys.stderr.write(" " * unstripped_line.index(token))
                sys.stderr.write("^" * len(token))
                sys.stderr.write("\n")

                # Dump current variables.
                sys.stderr.write("State: %d\n" % state)
                sys.stderr.write("ECO: %s\n" % eco)
                sys.stderr.write("FEN: %s\n" % position.fen())
                sys.stderr.write("Name: %s\n" % name)
                sys.stderr.flush()
                raise


    return result


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Compiles ECO files to JSON for faster lookups.")

    parser.add_argument("source",
        type=argparse.FileType("r"),
        nargs="?",
        default=sys.stdin,
        help="The input ECO file.")

    args = parser.parse_args()

    json.dump(read_eco(args.source), sys.stdout,
        ensure_ascii=False,
        indent=4,
        separators=(",", ": "),
        sort_keys=True)
