#!/usr/bin/env python3

"""
Updates the capability definitions at irc/caps/defs.go

To add a capability, add it to the CAPDEFS list below,
then run `make capdefs` from the project root.
"""

import io
import subprocess
import sys
from collections import namedtuple

CapDef = namedtuple("CapDef", ['identifier', 'name', 'url', 'standard'])

CAPDEFS = [
    CapDef(
        identifier="AccountNotify",
        name="account-notify",
        url="https://ircv3.net/specs/extensions/account-notify-3.1.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="AccountTag",
        name="account-tag",
        url="https://ircv3.net/specs/extensions/account-tag-3.2.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="AwayNotify",
        name="away-notify",
        url="https://ircv3.net/specs/extensions/away-notify-3.1.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="Batch",
        name="batch",
        url="https://ircv3.net/specs/extensions/batch-3.2.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="CapNotify",
        name="cap-notify",
        url="https://ircv3.net/specs/extensions/cap-notify-3.2.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="ChgHost",
        name="chghost",
        url="https://ircv3.net/specs/extensions/chghost-3.2.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="EchoMessage",
        name="echo-message",
        url="https://ircv3.net/specs/extensions/echo-message-3.2.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="ExtendedJoin",
        name="extended-join",
        url="https://ircv3.net/specs/extensions/extended-join-3.1.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="InviteNotify",
        name="invite-notify",
        url="https://ircv3.net/specs/extensions/invite-notify-3.2.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="LabeledResponse",
        name="labeled-response",
        url="https://ircv3.net/specs/extensions/labeled-response.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="Languages",
        name="draft/languages",
        url="https://gist.github.com/DanielOaks/8126122f74b26012a3de37db80e4e0c6",
        standard="proposed IRCv3",
    ),
    CapDef(
        identifier="MessageTags",
        name="message-tags",
        url="https://ircv3.net/specs/extensions/message-tags.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="MultiPrefix",
        name="multi-prefix",
        url="https://ircv3.net/specs/extensions/multi-prefix-3.1.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="Relaymsg",
        name="draft/relaymsg",
        url="https://github.com/ircv3/ircv3-specifications/pull/417",
        standard="proposed IRCv3",
    ),
    CapDef(
        identifier="ChannelRename",
        name="draft/channel-rename",
        url="https://ircv3.net/specs/extensions/channel-rename",
        standard="draft IRCv3",
    ),
    CapDef(
        identifier="SASL",
        name="sasl",
        url="https://ircv3.net/specs/extensions/sasl-3.2.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="ServerTime",
        name="server-time",
        url="https://ircv3.net/specs/extensions/server-time-3.2.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="SetName",
        name="setname",
        url="https://ircv3.net/specs/extensions/setname.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="STS",
        name="sts",
        url="https://ircv3.net/specs/extensions/sts.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="UserhostInNames",
        name="userhost-in-names",
        url="https://ircv3.net/specs/extensions/userhost-in-names-3.2.html",
        standard="IRCv3",
    ),
    CapDef(
        identifier="ZNCSelfMessage",
        name="znc.in/self-message",
        url="https://wiki.znc.in/Query_buffers",
        standard="ZNC vendor",
    ),
    CapDef(
        identifier="EventPlayback",
        name="draft/event-playback",
        url="https://github.com/ircv3/ircv3-specifications/pull/362",
        standard="proposed IRCv3",
    ),
    CapDef(
        identifier="ZNCPlayback",
        name="znc.in/playback",
        url="https://wiki.znc.in/Playback",
        standard="ZNC vendor",
    ),
    CapDef(
        identifier="Nope",
        name="oragono.io/nope",
        url="https://oragono.io/nope",
        standard="Oragono vendor",
    ),
    CapDef(
        identifier="Multiline",
        name="draft/multiline",
        url="https://github.com/ircv3/ircv3-specifications/pull/398",
        standard="proposed IRCv3",
    ),
    CapDef(
        identifier="Chathistory",
        name="draft/chathistory",
        url="https://github.com/ircv3/ircv3-specifications/pull/393",
        standard="proposed IRCv3",
    ),
    CapDef(
        identifier="AccountRegistration",
        name="draft/account-registration",
        url="https://github.com/ircv3/ircv3-specifications/pull/435",
        standard="draft IRCv3",
    ),
]

def validate_defs():
    CAPDEFS.sort(key=lambda d: d.name)
    numCaps = len(CAPDEFS)
    numNames = len(set(capdef.name for capdef in CAPDEFS))
    if numCaps != numNames:
        raise Exception("defs must have unique names, but found duplicates")
    numIdentifiers = len(set(capdef.identifier for capdef in CAPDEFS))
    if numCaps != numIdentifiers:
        raise Exception("defs must have unique identifiers, but found duplicates")

def main():
    validate_defs()
    output = io.StringIO()
    print("""
package caps

/*
	WARNING: this file is autogenerated by `make capdefs`
	DO NOT EDIT MANUALLY.
*/


    """, file=output)


    numCapabs = len(CAPDEFS)
    bitsetLen = numCapabs // 32
    if numCapabs % 32 > 0:
        bitsetLen += 1
    print ("""
const (
	// number of recognized capabilities:
	numCapabs = %d
	// length of the uint64 array that represents the bitset:
	bitsetLen = %d
)
    """ % (numCapabs, bitsetLen), file=output)

    print("const (", file=output)
    for capdef in CAPDEFS:
        print("// %s is the %s capability named \"%s\":" % (capdef.identifier, capdef.standard, capdef.name), file=output)
        print("// %s" % (capdef.url,), file=output)
        print("%s Capability = iota" % (capdef.identifier,), file=output)
        print(file=output)
    print(")", file=output)

    print("// `capabilityNames[capab]` is the string name of the capability `capab`", file=output)
    print("""var ( capabilityNames = [numCapabs]string{""", file=output)
    for capdef in CAPDEFS:
        print("\"%s\"," % (capdef.name,), file=output)
    print("})", file=output)

    # run the generated code through `gofmt -s`, which will print it to stdout
    gofmt = subprocess.Popen(['gofmt', '-s'], stdin=subprocess.PIPE)
    gofmt.communicate(input=output.getvalue().encode('utf-8'))
    if gofmt.poll() != 0:
        print(output.getvalue())
        raise Exception("gofmt failed")
    return 0

if __name__ == '__main__':
    sys.exit(main())
