import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk

from pychess import Variants
from pychess.Utils.const import (
    NORMALCHESS,
    ATOMICCHESS,
    BUGHOUSECHESS,
    CRAZYHOUSECHESS,
    LOSERSCHESS,
    SUICIDECHESS,
    FISCHERRANDOMCHESS,
    WILDCASTLESHUFFLECHESS,
    SHUFFLECHESS,
    RANDOMCHESS,
    ASYMMETRICRANDOMCHESS,
    WILDCASTLECHESS,
    UPSIDEDOWNCHESS,
    PAWNSPUSHEDCHESS,
    PAWNSPASSEDCHESS,
    GIVEAWAYCHESS,
    THREECHECKCHESS,
)

IC_CONNECTED, IC_DISCONNECTED = range(2)

# Fixed values of my relation to this game
# http://www.freechess.org/Help/HelpFiles/style12.html
(
    IC_POS_INITIAL,
    IC_POS_ISOLATED,
    IC_POS_OBSERVING_EXAMINATION,
    IC_POS_OP_TO_MOVE,
    IC_POS_OBSERVING,
    IC_POS_ME_TO_MOVE,
    IC_POS_EXAMINATING,
) = range(-4, 3)

# RatingType
(
    TYPE_BLITZ,
    TYPE_STANDARD,
    TYPE_LIGHTNING,
    TYPE_WILD,
    TYPE_BUGHOUSE,
    TYPE_CRAZYHOUSE,
    TYPE_SUICIDE,
    TYPE_LOSERS,
    TYPE_ATOMIC,
    TYPE_BULLET,
    TYPE_ONE_MINUTE,
    TYPE_THREE_MINUTE,
    TYPE_FIVE_MINUTE,
    TYPE_FIFTEEN_MINUTE,
    TYPE_FORTYFIVE_MINUTE,
    TYPE_CHESS960,
    TYPE_UNTIMED,
    TYPE_EXAMINED,
    TYPE_OTHER,
) = range(19)

RATING_TYPES = (
    TYPE_BLITZ,
    TYPE_STANDARD,
    TYPE_LIGHTNING,
    TYPE_BULLET,
    TYPE_ONE_MINUTE,
    TYPE_THREE_MINUTE,
    TYPE_FIVE_MINUTE,
    TYPE_FIFTEEN_MINUTE,
    TYPE_FORTYFIVE_MINUTE,
    TYPE_ATOMIC,
    TYPE_BUGHOUSE,
    TYPE_CRAZYHOUSE,
    TYPE_LOSERS,
    TYPE_SUICIDE,
    TYPE_WILD,
    TYPE_CHESS960,
    TYPE_UNTIMED,
)

# Rating deviations
DEVIATION_NONE, DEVIATION_ESTIMATED, DEVIATION_PROVISIONAL = range(3)

(
    IC_STATUS_PLAYING,
    IC_STATUS_ACTIVE,
    IC_STATUS_BUSY,
    IC_STATUS_OFFLINE,
    IC_STATUS_AVAILABLE,
    IC_STATUS_NOT_AVAILABLE,
    IC_STATUS_EXAMINING,
    IC_STATUS_IDLE,
    IC_STATUS_IN_TOURNAMENT,
    IC_STATUS_RUNNING_SIMUL_MATCH,
    IC_STATUS_UNKNOWN,
) = range(11)

TITLES_RE = r"(?:\([A-Z*]+\))*"
NAMES_RE = "[A-Za-z]+"

DEVIATION = {
    "E": DEVIATION_ESTIMATED,
    "P": DEVIATION_PROVISIONAL,
    " ": DEVIATION_NONE,
    "": DEVIATION_NONE,
}

STATUS = {
    "^": IC_STATUS_PLAYING,
    " ": IC_STATUS_AVAILABLE,
    ".": IC_STATUS_IDLE,
    "#": IC_STATUS_EXAMINING,
    ":": IC_STATUS_NOT_AVAILABLE,
    "~": IC_STATUS_RUNNING_SIMUL_MATCH,
    "&": IC_STATUS_IN_TOURNAMENT,
}


class GameType:
    def __init__(
        self,
        fics_name,
        short_fics_name,
        rating_type,
        display_text=None,
        variant_type=NORMALCHESS,
    ):
        self.fics_name = fics_name
        self.short_fics_name = short_fics_name
        self.rating_type = rating_type
        if display_text:
            self.display_text = display_text
        self.variant_type = variant_type

    @property
    def variant(self):
        return Variants.variants[self.variant_type]

    def __repr__(self):
        s = "<GameType "
        s += "fics_name='%s', " % self.fics_name
        s += "display_text='%s'>" % self.display_text
        return s


class NormalGameType(GameType):
    def __init__(self, fics_name, short_fics_name, rating_type, display_text):
        GameType.__init__(
            self, fics_name, short_fics_name, rating_type, display_text=display_text
        )


class VariantGameType(GameType):
    def __init__(self, fics_name, short_fics_name, rating_type, variant_type):
        GameType.__init__(
            self, fics_name, short_fics_name, rating_type, variant_type=variant_type
        )

    @property
    def display_text(self):
        assert self.variant_type is not None
        return Variants.variants[self.variant_type].name

    @property
    def seek_text(self):
        if "/" in self.fics_name:
            return self.fics_name.replace("/", " ")
        else:
            return self.fics_name


class WildGameType(VariantGameType):
    _instances = []

    def __init__(self, fics_name, variant_type):
        VariantGameType.__init__(
            self, fics_name, "w", TYPE_WILD, variant_type=variant_type
        )
        WildGameType._instances.append(self)

    @classmethod
    def instances(cls):
        return cls._instances


# FICS game types
GAME_TYPES = {
    "blitz": NormalGameType("blitz", "b", TYPE_BLITZ, _("Blitz")),
    "standard": NormalGameType("standard", "s", TYPE_STANDARD, _("Standard")),
    "lightning": NormalGameType("lightning", "l", TYPE_LIGHTNING, _("Lightning")),
    "1-minute": NormalGameType("1-minute", "o", TYPE_ONE_MINUTE, _("1-minute")),
    "3-minute": NormalGameType("3-minute", "M", TYPE_THREE_MINUTE, _("3-minute")),
    "5-minute": NormalGameType("5-minute", "f", TYPE_FIVE_MINUTE, _("5-minute")),
    "15-minute": NormalGameType("15-minute", "F", TYPE_FIFTEEN_MINUTE, _("15-minute")),
    "45-minute": NormalGameType(
        "45-minute", "J", TYPE_FORTYFIVE_MINUTE, _("45-minute")
    ),
    "chess960": NormalGameType("chess960", "K", TYPE_CHESS960, _("Chess960")),
    "untimed": NormalGameType("untimed", "u", TYPE_UNTIMED, _("Untimed")),
    "examined": NormalGameType("examined", "e", TYPE_EXAMINED, _("Examined")),
    "nonstandard": NormalGameType("nonstandard", "n", TYPE_OTHER, _("Other")),
    "w20": NormalGameType("loaded", "w20", TYPE_OTHER, _("Other")),  # loadfen/loadgame
    "w21": NormalGameType(
        "loaded", "w21", TYPE_OTHER, _("Other")
    ),  # thematic tournaments
    "atomic": VariantGameType("atomic", "x", TYPE_ATOMIC, ATOMICCHESS),
    "bughouse": VariantGameType("bughouse", "B", TYPE_BUGHOUSE, BUGHOUSECHESS),
    "crazyhouse": VariantGameType("crazyhouse", "z", TYPE_CRAZYHOUSE, CRAZYHOUSECHESS),
    "losers": VariantGameType("losers", "L", TYPE_LOSERS, LOSERSCHESS),
    "suicide": VariantGameType("suicide", "S", TYPE_SUICIDE, SUICIDECHESS),
    # FICS http://www.freechess.org/Help/HelpFiles/wild.html
    "wild/fr": WildGameType("wild/fr", FISCHERRANDOMCHESS),
    "wild/0": WildGameType("wild/0", WILDCASTLECHESS),
    "wild/1": WildGameType("wild/1", WILDCASTLESHUFFLECHESS),
    "wild/2": WildGameType("wild/2", SHUFFLECHESS),
    "wild/3": WildGameType("wild/3", RANDOMCHESS),
    "wild/4": WildGameType("wild/4", ASYMMETRICRANDOMCHESS),
    "wild/5": WildGameType("wild/5", UPSIDEDOWNCHESS),
    "wild/8": WildGameType("wild/8", PAWNSPUSHEDCHESS),
    "wild/8a": WildGameType("wild/8a", PAWNSPASSEDCHESS),
    # ICC https://www.chessclub.com/user/helpcenter/tips/wild.html
    "w17": WildGameType("w17", LOSERSCHESS),
    "w26": WildGameType("w26", GIVEAWAYCHESS),
    "w24": WildGameType("w24", BUGHOUSECHESS),
    "w23": WildGameType("w23", CRAZYHOUSECHESS),
    # "w16": WildGameType("w16", KRIEGSPIELCHESS),
    "w27": WildGameType("w27", ATOMICCHESS),
    # "w28": WildGameType("w28", SHATRANJCHESS),
    "w25": WildGameType("w25", THREECHECKCHESS),
    "w1": WildGameType("w1", WILDCASTLESHUFFLECHESS),
    "w2": WildGameType("w2", SHUFFLECHESS),
    "w3": WildGameType("w3", RANDOMCHESS),
    "w4": WildGameType("w4", ASYMMETRICRANDOMCHESS),
    "w22": WildGameType("w22", FISCHERRANDOMCHESS),
    "w5": WildGameType("w5", UPSIDEDOWNCHESS),
    # "w7": WildGameType("w7", THREEPAWNSCHESS),
    "w8": WildGameType("w8", PAWNSPUSHEDCHESS),
    # "w9": WildGameType("w9", TWOKINGSCHESS),
    # "w18": WildGameType("w18", EIGHTQUEENSCHESS),
    # "w19": WildGameType("w19", KNNKPCHESS),
}

VARIANT_GAME_TYPES = {}
for key in GAME_TYPES:
    if isinstance(GAME_TYPES[key], VariantGameType):
        VARIANT_GAME_TYPES[GAME_TYPES[key].variant_type] = GAME_TYPES[key]

# The following 3 GAME_TYPES_* data structures don't have any real entries
# for the WildGameType's in GAME_TYPES above, and instead use
# a dummy type for the all-encompassing "Wild" FICS rating for wild/* games
GAME_TYPES_BY_SHORT_FICS_NAME = {
    "w": GameType("wild", "w", TYPE_WILD, display_text=_("Wild"))
}
for key in GAME_TYPES:
    if not isinstance(GAME_TYPES[key], WildGameType):
        GAME_TYPES_BY_SHORT_FICS_NAME[GAME_TYPES[key].short_fics_name] = GAME_TYPES[key]

GAME_TYPES_BY_RATING_TYPE = {}
for key in GAME_TYPES_BY_SHORT_FICS_NAME:
    GAME_TYPES_BY_RATING_TYPE[GAME_TYPES_BY_SHORT_FICS_NAME[key].rating_type] = (
        GAME_TYPES_BY_SHORT_FICS_NAME[key]
    )

GAME_TYPES_BY_FICS_NAME = {}
for key in GAME_TYPES_BY_SHORT_FICS_NAME:
    GAME_TYPES_BY_FICS_NAME[GAME_TYPES_BY_SHORT_FICS_NAME[key].fics_name] = (
        GAME_TYPES_BY_SHORT_FICS_NAME[key]
    )


# Finally add conflicting ICC game type
GAME_TYPES["bullet"] = NormalGameType("bullet", "B", TYPE_BULLET, _("Bullet"))
GAME_TYPES_BY_FICS_NAME["bullet"] = GAME_TYPES["bullet"]
GAME_TYPES_BY_RATING_TYPE[TYPE_BULLET] = GAME_TYPES["bullet"]
# GAME_TYPES_BY_SHORT_FICS_NAME["B"] will be fixed in FICSConnections.py
# and VARIANT_GAME_TYPES[FISCHERRANDOMCHESS] also


def type_to_display_text(typename):
    if "loaded from" in typename.lower():
        typename = typename.split()[-1]
    if typename in GAME_TYPES:
        return GAME_TYPES[typename].display_text
    # Default solution for eco/A00 and a few others
    elif "/" in typename:
        a, b = typename.split("/")
        a = a[0].upper() + a[1:]
        b = b[0].upper() + b[1:]
        return a + " " + b
    else:
        # Otherwise forget about it
        return typename[0].upper() + typename[1:]


def time_control_to_gametype(minutes, gain):
    assert isinstance(minutes, int) and isinstance(gain, int)
    assert minutes >= 0 and gain >= 0
    gainminutes = gain > 0 and (gain * 60) - 1 or 0
    if minutes == 0 and gain == 0:
        return GAME_TYPES["untimed"]
    elif (minutes * 60) + gainminutes >= (15 * 60):
        return GAME_TYPES["standard"]
    elif (minutes * 60) + gainminutes >= (3 * 60):
        return GAME_TYPES["blitz"]
    else:
        return GAME_TYPES["lightning"]


(
    TYPE_ADMINISTRATOR,
    TYPE_BLINDFOLD,
    TYPE_COMPUTER,
    TYPE_TEAM,
    TYPE_UNREGISTERED,
    TYPE_CHESS_ADVISOR,
    TYPE_SERVICE_REPRESENTATIVE,
    TYPE_TOURNAMENT_DIRECTOR,
    TYPE_MAMER_MANAGER,
    TYPE_GRAND_MASTER,
    TYPE_INTERNATIONAL_MASTER,
    TYPE_FIDE_MASTER,
    TYPE_WOMAN_GRAND_MASTER,
    TYPE_WOMAN_INTERNATIONAL_MASTER,
    TYPE_WOMAN_FIDE_MASTER,
    TYPE_DUMMY_ACCOUNT,
    TYPE_CANDIDATE_MASTER,
    TYPE_FIDE_ARBEITER,
    TYPE_NATIONAL_MASTER,
    TYPE_DISPLAY_MASTER,
) = range(20)

TITLE_TYPE_DISPLAY_TEXTS = (
    _("Administrator"),
    _("Blindfold Account"),
    _("Computer"),
    _("Team Account"),
    _("Unregistered"),
    _("Chess Advisor"),
    _("Service Representative"),
    _("Tournament Director"),
    _("Mamer Manager"),
    _("Grand Master"),
    _("International Master"),
    _("FIDE Master"),
    _("Woman Grand Master"),
    _("Woman International Master"),
    _("Woman FIDE Master"),
    _("Dummy Account"),
    _("Candidate Master"),
    _("FIDE Arbeiter"),
    _("National Master"),
    _("Display Master"),
)

TITLE_TYPE_DISPLAY_TEXTS_SHORT = (
    _("*"),
    _("B"),
    _("C"),
    _("T"),
    _("U"),
    _("CA"),
    _("SR"),
    _("TD"),
    _("TM"),
    _("GM"),
    _("IM"),
    _("FM"),
    _("WGM"),
    _("WIM"),
    _("WFM"),
    _("D"),
    _("H"),
    _("CM"),
    _("FA"),
    _("NM"),
    _("DM"),
)

TITLES = {  # From FICS 'help who'
    "*": TYPE_ADMINISTRATOR,
    "B": TYPE_BLINDFOLD,
    "C": TYPE_COMPUTER,
    "T": TYPE_TEAM,
    "U": TYPE_UNREGISTERED,
    "CA": TYPE_CHESS_ADVISOR,
    "SR": TYPE_SERVICE_REPRESENTATIVE,
    "TD": TYPE_TOURNAMENT_DIRECTOR,
    "TM": TYPE_MAMER_MANAGER,
    "GM": TYPE_GRAND_MASTER,
    "IM": TYPE_INTERNATIONAL_MASTER,
    "FM": TYPE_FIDE_MASTER,
    "WFM": TYPE_WOMAN_FIDE_MASTER,
    "WIM": TYPE_WOMAN_INTERNATIONAL_MASTER,
    "WGM": TYPE_WOMAN_GRAND_MASTER,
    "D": TYPE_DUMMY_ACCOUNT,
    "H": TYPE_SERVICE_REPRESENTATIVE,
    "CM": TYPE_CANDIDATE_MASTER,
    "FA": TYPE_FIDE_ARBEITER,
    "NM": TYPE_NATIONAL_MASTER,
    "DM": TYPE_DISPLAY_MASTER,
}

HEX_TO_TITLE = {
    0x1: TYPE_UNREGISTERED,
    0x2: TYPE_COMPUTER,
    0x4: TYPE_GRAND_MASTER,
    0x8: TYPE_INTERNATIONAL_MASTER,
    0x10: TYPE_FIDE_MASTER,
    0x20: TYPE_WOMAN_GRAND_MASTER,
    0x40: TYPE_WOMAN_INTERNATIONAL_MASTER,
    0x80: TYPE_WOMAN_FIDE_MASTER,
}


def parse_title_hex(titlehex):
    titles = set()
    for key in HEX_TO_TITLE:
        if int(titlehex, 16) & key:
            titles.add(HEX_TO_TITLE[key])
    return titles


def parseRating(rating):
    if rating[0] == " ":
        rating = rating[1:]
    if rating[-1].isalpha():
        rating = rating[:-1]
    return int(rating) if rating.isdigit() else 0


def get_infobarmessage_content(player, text, gametype=None):
    content = Gtk.HBox()
    icon = Gtk.Image()
    icon.set_from_pixbuf(player.getIcon(size=32, gametype=gametype))
    content.pack_start(icon, False, False, 4)
    label = Gtk.Label()
    label.set_markup(player.getMarkup(gametype=gametype))
    content.pack_start(label, False, False, 0)
    label = Gtk.Label()
    label.set_markup(text)
    content.pack_start(label, False, False, 0)
    return content


def get_infobarmessage_content2(player, heading_text, message_text, gametype=None):
    hbox = Gtk.HBox()
    image = Gtk.Image()
    image.set_from_pixbuf(player.getIcon(size=24, gametype=gametype))
    hbox.pack_start(image, False, False, 0)
    label = Gtk.Label()
    markup = player.getMarkup(gametype=gametype, long_titles=False)
    label.set_markup(markup + heading_text)
    hbox.pack_start(label, False, False, 0)
    vbox = Gtk.VBox()
    vbox.pack_start(hbox, False, False, 0)
    label = Gtk.Label()
    label.props.xalign = 0
    label.props.xpad = 4
    label.props.justify = Gtk.Justification.LEFT
    label.props.wrap = True
    label.set_width_chars(70)
    label.set_text(message_text)
    vbox.pack_start(label, False, False, 5)
    return vbox


"""
Internal command codes used in FICS block mode
(see "help block_codes" and "help iv_block").
Used mostly by internal library functions.

BLOCK_ variables are message boundary markers.

BLKCMD_ variables are command codes.
"""

BLOCK_START = chr(21)  # \U
BLOCK_SEPARATOR = chr(22)  # \V
BLOCK_END = chr(23)  # \W
BLOCK_POSE_START = chr(24)  # \X
BLOCK_POSE_END = chr(25)  # \Y

BLKCMD_NULL = 0
BLKCMD_GAME_MOVE = 1
BLKCMD_ABORT = 10
BLKCMD_ACCEPT = 11
BLKCMD_ADDLIST = 12
BLKCMD_ADJOURN = 13
BLKCMD_ALLOBSERVERS = 14
BLKCMD_ASSESS = 15
BLKCMD_BACKWARD = 16
BLKCMD_BELL = 17
BLKCMD_BEST = 18
BLKCMD_BNAME = 19
BLKCMD_BOARDS = 20
BLKCMD_BSETUP = 21
BLKCMD_BUGWHO = 22
BLKCMD_CBEST = 23
BLKCMD_CLEARMESSAGES = 24
BLKCMD_CLRSQUARE = 25
BLKCMD_CONVERT_BCF = 26
BLKCMD_CONVERT_ELO = 27
BLKCMD_CONVERT_USCF = 28
BLKCMD_COPYGAME = 29
BLKCMD_CRANK = 30
BLKCMD_CSHOUT = 31
BLKCMD_DATE = 32
BLKCMD_DECLINE = 33
BLKCMD_DRAW = 34
BLKCMD_ECO = 35
BLKCMD_EXAMINE = 36
BLKCMD_FINGER = 37
BLKCMD_FLAG = 38
BLKCMD_FLIP = 39
BLKCMD_FMESSAGE = 40
BLKCMD_FOLLOW = 41
BLKCMD_FORWARD = 42
BLKCMD_GAMES = 43
BLKCMD_GETGI = 44
BLKCMD_GETPI = 45
BLKCMD_GINFO = 46
BLKCMD_GOBOARD = 47
BLKCMD_HANDLES = 48
BLKCMD_HBEST = 49
BLKCMD_HELP = 50
BLKCMD_HISTORY = 51
BLKCMD_HRANK = 52
BLKCMD_INCHANNEL = 53
BLKCMD_INDEX = 54
BLKCMD_INFO = 55
BLKCMD_ISET = 56
BLKCMD_IT = 57
BLKCMD_IVARIABLES = 58
BLKCMD_JKILL = 59
BLKCMD_JOURNAL = 60
BLKCMD_JSAVE = 61
BLKCMD_KIBITZ = 62
BLKCMD_LIMITS = 63
BLKCMD_LINE = 64  # Not on FICS
BLKCMD_LLOGONS = 65
BLKCMD_LOGONS = 66
BLKCMD_MAILHELP = 67
BLKCMD_MAILMESS = 68
BLKCMD_MAILMOVES = 69
BLKCMD_MAILOLDMOVES = 70
BLKCMD_MAILSOURCE = 71
BLKCMD_MAILSTORED = 72
BLKCMD_MATCH = 73
BLKCMD_MESSAGES = 74
BLKCMD_MEXAMINE = 75
BLKCMD_MORETIME = 76
BLKCMD_MOVES = 77
BLKCMD_NEWS = 78
BLKCMD_NEXT = 79
BLKCMD_OBSERVE = 80
BLKCMD_OLDMOVES = 81
BLKCMD_OLDSTORED = 82
BLKCMD_OPEN = 83
BLKCMD_PARTNER = 84
BLKCMD_PASSWORD = 85
BLKCMD_PAUSE = 86
BLKCMD_PENDING = 87
BLKCMD_PFOLLOW = 88
BLKCMD_POBSERVE = 89
BLKCMD_PREFRESH = 90
BLKCMD_PRIMARY = 91
BLKCMD_PROMOTE = 92
BLKCMD_PSTAT = 93
BLKCMD_PTELL = 94
BLKCMD_PTIME = 95
BLKCMD_QTELL = 96
BLKCMD_QUIT = 97
BLKCMD_RANK = 98
BLKCMD_RCOPYGAME = 99
BLKCMD_RFOLLOW = 100
BLKCMD_REFRESH = 101
BLKCMD_REMATCH = 102
BLKCMD_RESIGN = 103
BLKCMD_RESUME = 104
BLKCMD_REVERT = 105
BLKCMD_ROBSERVE = 106
BLKCMD_SAY = 107
BLKCMD_SERVERS = 108
BLKCMD_SET = 109
BLKCMD_SHOUT = 110
BLKCMD_SHOWLIST = 111
BLKCMD_SIMABORT = 112
BLKCMD_SIMALLABORT = 113
BLKCMD_SIMADJOURN = 114
BLKCMD_SIMALLADJOURN = 115
BLKCMD_SIMGAMES = 116
BLKCMD_SIMMATCH = 117
BLKCMD_SIMNEXT = 118
BLKCMD_SIMOBSERVE = 119
BLKCMD_SIMOPEN = 120
BLKCMD_SIMPASS = 121
BLKCMD_SIMPREV = 122
BLKCMD_SMOVES = 123
BLKCMD_SMPOSITION = 124
BLKCMD_SPOSITION = 125
BLKCMD_STATISTICS = 126
BLKCMD_STORED = 127
BLKCMD_STYLE = 128
BLKCMD_SWITCH = 130
BLKCMD_TAKEBACK = 131
BLKCMD_TELL = 132
BLKCMD_TIME = 133
BLKCMD_TOMOVE = 134
BLKCMD_TOURNSET = 135
BLKCMD_UNALIAS = 136
BLKCMD_UNEXAMINE = 137
BLKCMD_UNOBSERVE = 138
BLKCMD_UNPAUSE = 139
BLKCMD_UPTIME = 140
BLKCMD_USCF = 141
BLKCMD_USTAT = 142
BLKCMD_VARIABLES = 143
BLKCMD_WHENSHUT = 144
BLKCMD_WHISPER = 145
BLKCMD_WHO = 146
BLKCMD_WITHDRAW = 147
BLKCMD_WNAME = 148
BLKCMD_XKIBITZ = 149
BLKCMD_XTELL = 150
BLKCMD_XWHISPER = 151
BLKCMD_ZNOTIFY = 152
BLKCMD_REPLY = 153  # Not on FICS
BLKCMD_SUMMON = 154
BLKCMD_SEEK = 155
BLKCMD_UNSEEK = 156
BLKCMD_SOUGHT = 157
BLKCMD_PLAY = 158
BLKCMD_ALIAS = 159
BLKCMD_NEWBIES = 160
BLKCMD_SR = 161
BLKCMD_CA = 162
BLKCMD_TM = 163
BLKCMD_GETGAME = 164
BLKCMD_CCNEWSE = 165
BLKCMD_CCNEWSF = 166
BLKCMD_CCNEWSI = 167
BLKCMD_CCNEWSP = 168
BLKCMD_CCNEWST = 169
BLKCMD_CSNEWSE = 170
BLKCMD_CSNEWSF = 171
BLKCMD_CSNEWSI = 172
BLKCMD_CSNEWSP = 173
BLKCMD_CSNEWST = 174
BLKCMD_CTNEWSE = 175
BLKCMD_CTNEWSF = 176
BLKCMD_CTNEWSI = 177
BLKCMD_CTNEWSP = 178
BLKCMD_CTNEWST = 179
BLKCMD_CNEWS = 180
BLKCMD_SNEWS = 181
BLKCMD_TNEWS = 182
BLKCMD_RMATCH = 183
BLKCMD_RSTAT = 184
BLKCMD_CRSTAT = 185
BLKCMD_HRSTAT = 186
BLKCMD_GSTAT = 187

# Note admin codes start from 300.

BLKCMD_ERROR_BADCOMMAND = 512
BLKCMD_ERROR_BADPARAMS = 513
BLKCMD_ERROR_AMBIGUOUS = 514
BLKCMD_ERROR_RIGHTS = 515
BLKCMD_ERROR_OBSOLETE = 516
BLKCMD_ERROR_REMOVED = 517
BLKCMD_ERROR_NOTPLAYING = 518
BLKCMD_ERROR_NOSEQUENCE = 519
BLKCMD_ERROR_LENGTH = 520

LIMIT_BLKCMD_ERRORS = 500

FICS_COMMANDS = [
    "abort",
    "accept",
    "addlist",
    "adjourn",
    "alias",
    "allobservers",
    "assess",
    "backward",
    "bell",
    "best",
    "boards",
    "bsetup",
    "bugwho",
    "cbest",
    "clearmessages",
    "convert_bcf",
    "convert_elo",
    "convert_uscf",
    "copygame",
    "crank",
    "cshout",
    "date",
    "decline",
    "draw",
    "examine",
    "finger",
    "flag",
    "flip",
    "fmessage",
    "follow",
    "forward",
    "games",
    "gnotify",
    "goboard",
    "handles",
    "hbest",
    "help",
    "history",
    "hrank",
    "inchannel",
    "index",
    "info",
    "it",
    "jkill",
    "jsave",
    "kibitz",
    "limits",
    "llogons",
    "logons",
    "mailhelp",
    "mailmess",
    "mailmoves",
    "mailoldmoves",
    "mailsource",
    "mailstored",
    "match",
    "messages",
    "mexamine",
    "moretime",
    "moves",
    "news",
    "next",
    "observe",
    "oldmoves",
    "open",
    "password",
    "pause",
    "pending",
    "pfollow",
    "play",
    "pobserve",
    "promote",
    "pstat",
    "qtell",
    "quit",
    "rank",
    "refresh",
    "resign",
    "resume",
    "revert",
    "say",
    "seek",
    "servers",
    "set",
    "shout",
    "showlist",
    "simabort",
    "simallabort",
    "simadjourn",
    "simalladjourn",
    "simgames",
    "simmatch",
    "simnext",
    "simobserve",
    "simopen",
    "simpass",
    "simprev",
    "smoves",
    "smposition",
    "sought",
    "sposition",
    "statistics",
    "stored",
    "style",
    "sublist",
    "switch",
    "takeback",
    "tell",
    "time",
    "unalias",
    "unexamine",
    "unobserve",
    "unpause",
    "unseek",
    "uptime",
    "ustat",
    "variables",
    "whisper",
    "who",
    "withdraw",
    "xkibitz",
    "xtell",
    "xwhisper",
    "znotify",
]

FICS_HELP = [
    "_index",
    "abort",
    "abuse",
    "academy",
    "accept",
    "addlist",
    "addresses",
    "adjourn",
    "adjournments",
    "adjudicate",
    "adjudication",
    "adm_app",
    "adm_info",
    "adm_new",
    "admins",
    "alias",
    "allobservers",
    "assess",
    "atomic",
    "audiochat",
    "avail_vars",
    "backward",
    "bclock",
    "bell",
    "best",
    "blind",
    "blindfold",
    "blindh",
    "blitz",
    "block_codes",
    "bname",
    "boards",
    "brating",
    "bsetup",
    "bughouse",
    "bughouse_strat",
    "bugreport",
    "bugwho",
    "busy",
    "ca",
    "category",
    "cbest",
    "censor",
    "chan_1",
    "chan_4",
    "channel",
    "channel_list",
    "channels",
    "chess_adviser",
    "chess_advisor",
    "clearmessage",
    "clearmessages",
    "clock",
    "clocks",
    "clrsquare",
    "cls",
    "cls_info",
    "command",
    "commands",
    "commit",
    "computer_app",
    "computer_list",
    "computers",
    "confidentiality",
    "convert_bcf",
    "convert_elo",
    "convert_uscf",
    "copygame",
    "crank",
    "crazyhouse",
    "crazyhouse_strat",
    "credit",
    "crstat",
    "cshout",
    "csnewse",
    "csnewsf",
    "csnewsi",
    "csnewsp",
    "csnewst",
    "date",
    "decline",
    "disclaimer",
    "disconnection",
    "draw",
    "eco",
    "eggo",
    "email",
    "etime",
    "examine",
    "exl",
    "fen",
    "fics_faq",
    "fics_lingo",
    "finger",
    "flag",
    "flip",
    "fmessage",
    "follow",
    "formula",
    "forward",
    "fr",
    "fr_rules",
    "ftp_hints",
    "games",
    "games",
    "getgame",
    "getgi",
    "getpi",
    "ginfo",
    "glicko",
    "gnotify",
    "goboard",
    "handle",
    "handles",
    "hbest",
    "help",
    "highlight",
    "history",
    "hrank",
    "hrstat",
    "hstat",
    "icsdrone",
    "idlenotify",
    "inchannel",
    "index",
    "indexfile",
    "inetchesslib",
    "info",
    "intellegence",
    "interfaces",
    "intro_analysis",
    "intro_basics",
    "intro_general",
    "intro_information",
    "intro_moving",
    "intro_playing",
    "intro_settings",
    "intro_talking",
    "intro_welcome",
    "irc_help",
    "iset",
    "it",
    "iv_allresults",
    "iv_atomic",
    "iv_audiochat",
    "iv_block",
    "iv_boardinfo",
    "iv_compressmove",
    "iv_crazyhouse",
    "iv_defprompt",
    "iv_extascii",
    "iv_extuserinfo",
    "iv_fr",
    "iv_gameinfo",
    "iv_graph",
    "iv_list",
    "iv_lock",
    "iv_pendinfo",
    "iv_seekinfo",
    "iv_seekremove",
    "iv_startpos",
    "ivariables",
    "jkill",
    "journal",
    "jsave",
    "kibitz",
    "kiblevel",
    "lag",
    "lecture1",
    "lessons",
    "lightning",
    "limits",
    "links",
    "lists",
    "llogons",
    "logons",
    "losers",
    "losers_chess",
    "mailhelp",
    "mailmess",
    "mailmoves",
    "mailoldmoves",
    "mailstored",
    "mamer",
    "manual_usage",
    "manual_vars",
    "match",
    "meeting_1_followup",
    "meeting_1_long",
    "meeting_1_short",
    "meetings_index",
    "messages",
    "mexamine",
    "moretime",
    "motd",
    "motd_fri",
    "motd_help",
    "motd_mon",
    "motd_sat",
    "motd_sun",
    "motd_thu",
    "motd_tue",
    "motd_wed",
    "moves",
    "mule",
    "new_features",
    "newbie",
    "news",
    "next",
    "noescape",
    "noplay",
    "notes",
    "notify",
    "observe",
    "odds",
    "oldmoves",
    "oldpstat",
    "open",
    "partner",
    "password",
    "pause",
    "pending",
    "pfollow",
    "pgn",
    "ping",
    "play",
    "pobserve",
    "powericsfaq",
    "prefresh",
    "primary",
    "private",
    "promote",
    "pstat",
    "ptell",
    "ptime",
    "qtell",
    "quit",
    "rank",
    "rating_changes",
    "ratings",
    "rcopygame",
    "rd",
    "refresh",
    "register",
    "relay",
    "relay_operator",
    "rematch",
    "replay",
    "resign",
    "result",
    "resume",
    "revert",
    "rfollow",
    "rmatch",
    "robofics",
    "robserve",
    "rstat",
    "sabort",
    "say",
    "sdraw",
    "seek",
    "servers",
    "set",
    "setup",
    "shout",
    "shout_quota",
    "showadmins",
    "showlist",
    "showsrs",
    "simabort",
    "simadjourn",
    "simallabort",
    "simalladjourn",
    "simgames",
    "simmatch",
    "simnext",
    "simobserve",
    "simopen",
    "simpass",
    "simprev",
    "simuls",
    "skype",
    "smoves",
    "smposition",
    "sought",
    "spending",
    "sposition",
    "sr",
    "sr_info",
    "standard",
    "statistics",
    "stats",
    "stc",
    "stored",
    "style",
    "style12",
    "sublist",
    "suicide_chess",
    "summon",
    "switch",
    "system_alias",
    "takeback",
    "team",
    "teamgames",
    "tell",
    "time",
    "timeseal",
    "timeseal_mac",
    "timeseal_os2",
    "timeseal_unix",
    "timeseal_windows",
    "timezones",
    "tm",
    "tomove",
    "totals",
    "totals_info",
    "tournset",
    "town_meetings",
    "townmtg1",
    "unalias",
    "unexamine",
    "unobserve",
    "unpause",
    "unseek",
    "untimed",
    "uptime",
    "uscf",
    "uscf_faq",
    "ustat",
    "v_autoflag",
    "v_automail",
    "v_availinfo",
    "v_availmax",
    "v_availmin",
    "v_bell",
    "v_bugopen",
    "v_chanoff",
    "v_cshout",
    "v_ctell",
    "v_echo",
    "v_flip",
    "v_formula",
    "v_gin",
    "v_height",
    "v_highlight",
    "v_inc",
    "v_interface",
    "v_jprivate",
    "v_kibitz",
    "v_kiblevel",
    "v_language",
    "v_mailmess",
    "v_messreply",
    "v_notakeback",
    "v_notifiedby",
    "v_open",
    "v_pgn",
    "v_pin",
    "v_private",
    "v_prompt",
    "v_provshow",
    "v_ptime",
    "v_rated",
    "v_ropen",
    "v_seek",
    "v_shout",
    "v_silence",
    "v_simopen",
    "v_style",
    "v_tell",
    "v_time",
    "v_tolerance",
    "v_tourney",
    "v_tzone",
    "v_unobserve",
    "v_width",
    "variables",
    "wclock",
    "webpage",
    "whenshut",
    "whisper",
    "who",
    "wild",
    "withdraw",
    "wname",
    "wrating",
    "xkibitz",
    "xtell",
    "xwhisper",
    "zhouse",
    "znotify",
]
