import json


def configure(conf):
    pass


def build(bld):
    in_node = bld.path.find_node('protocol_endpoints_table.json')
    out_node = bld.path.get_bld().make_node('protocol_endpoints_table.auto.h')

    def generate_endpoints_table(task):
        in_node = task.inputs[0]
        out_node = task.outputs[0]
        endpoints = []
        definition = {}
        with open(in_node.abspath(), 'r') as f_in:
            definition.update(json.load(f_in))

        endpoints.extend(definition['prf_and_normal_fw'])
        if bld.variant != 'prf':
            endpoints.extend(definition['normal_fw_only'])
        endpoints.sort()

        def get_access_enum(access_str):
            if access_str == "private":
                return "PebbleProtocolAccessPrivate"
            elif access_str == "any":
                return "PebbleProtocolAccessAny"
            elif access_str == "any":
                return "PebbleProtocolAccessPublic"
            else:
                raise ValueError("Unknown value: %s" % access_str)

        with open(out_node.abspath(), 'w') as f_out:
            f_out.write("// GENERATED -- DO NOT EDIT\n\n")
            f_out.write("#include \"kernel/pebble_tasks.h\"\n\n")

            DEFAULT_SYSTEM_RECV_IMPL = \
                "g_default_kernel_receiver_implementation"
            recv_imp_set = set([DEFAULT_SYSTEM_RECV_IMPL])

            DEFAULT_SYSTEM_RECV_OPT = \
                "g_default_kernel_receiver_opt_bg"
            recv_opt_set = set([DEFAULT_SYSTEM_RECV_OPT])

            for (eid, eid_str, access_str, cb_str,
                 recv_imp, recv_opt) in endpoints:
                if recv_imp:
                    recv_imp_set.add(recv_imp)
                if recv_opt:
                    recv_opt_set.add(recv_opt)
                if cb_str:
                    f_out.write("extern void {cb_str}(CommSession *session, "
                                "const uint8_t* data, "
                                "size_t length);\n".format(cb_str=cb_str))

            f_out.write("\n\n")
            for recv_imp in recv_imp_set:
                fmt = "extern ReceiverImplementation {recv_imp};\n"
                f_out.write(fmt.format(recv_imp=recv_imp))

            f_out.write("\n\n")
            for recv_opt in recv_opt_set:
                fmt = "extern const PebbleTask {recv_opt};\n"
                f_out.write(fmt.format(recv_opt=recv_opt))

            f_out.write("\n\nstatic const PebbleProtocolEndpoint "
                        "s_protocol_endpoints[] = {\n")
            for (eid, eid_str, access_str, cb_str,
                 recv_imp, recv_opt) in endpoints:
                if int(eid_str, base=16) != eid:
                    raise ValueError("Endpoint IDs need to match: %i vs %s" %
                                     (eid, eid_str))
                if not cb_str:
                    cb_str = "NULL"
                if not recv_imp:
                    recv_imp = DEFAULT_SYSTEM_RECV_IMPL
                    if not recv_opt:
                        recv_opt = DEFAULT_SYSTEM_RECV_OPT
                if not recv_opt:
                    recv_opt = "NULL"
                else:
                    recv_opt = "&" + recv_opt
                fmt = ("  {{ {eid}, {cb_str}, {access_enum}, &{recv_imp},"
                       " {recv_opt} }},\n")
                f_out.write(fmt.format(eid=eid,
                                       cb_str=cb_str,
                                       access_enum=get_access_enum(access_str),
                                       recv_imp=recv_imp,
                                       recv_opt=recv_opt,
                                       ))
            f_out.write("};\n\n")

    bld(rule=generate_endpoints_table,
        source=[in_node],
        target=out_node)
