#!/usr/bin/env python3

import os
import subprocess
import sys
import tempfile

cc = os.getenv("CC", "cc")
pkg_config = os.getenv("PKG_CONFIG", "pkg-config")

version = subprocess.check_output([pkg_config, "libdrm", "--modversion"]).decode().strip()
cflags = subprocess.check_output([pkg_config, "libdrm", "--cflags-only-I"]).decode().strip().split()
if not cflags[0].startswith("-I"):
	raise Exception("Expected one include dir for libdrm")
libdrm_include = cflags[0][2:]
fourcc_include = libdrm_include + "/drm_fourcc.h"

ident_list = []
with open(fourcc_include) as input_file:
	for l in input_file.readlines():
		parts = l.split()
		if len(parts) < 3 or parts[0] != "#define":
			continue
		ident = parts[1]
		if not ident.startswith("DRM_FORMAT_") and not ident.startswith("I915_FORMAT_"):
			continue
		if "(" in ident:
			# Some complicated formats use a macro with parameters
			continue
		ident_list.append(ident)

idents = {}
with tempfile.TemporaryDirectory() as work_dir:
	c_file_name = work_dir + "/main.c"
	exe_file_name = work_dir + "/main"

	with open(c_file_name, "w+") as c_file:
		c_file.write('#include <inttypes.h>\n')
		c_file.write('#include <stdint.h>\n')
		c_file.write('#include <stdio.h>\n')
		c_file.write('#include <drm_fourcc.h>\n')
		c_file.write('\n')
		c_file.write('int main(void) {\n')
		for ident in ident_list:
			c_file.write('printf("0x%" PRIX64 "\\n", (uint64_t)' + ident + ');\n')
		c_file.write('}\n')


	subprocess.check_call([cc, "-Wall", "-Wextra", "-o", exe_file_name, c_file_name] + cflags)
	output = subprocess.check_output([exe_file_name]).decode().strip()
	for (i, l) in enumerate(output.splitlines()):
		idents[ident_list[i]] = l

types = ["Format", "ModifierVendor", "Modifier"]
words = ["none", "invalid", "linear"]
initialisms = ["AMD", "NVIDIA", "ARM"]

def to_camel_case(s):
	parts = s.split("_")
	for (i, part) in enumerate(parts):
		if not part in initialisms:
			parts[i] = part.lower().capitalize()
	return "".join(parts)

consts = []
for (ident, val) in idents.items():
	if "_MOD_" in ident:
		t = "Modifier"
		if ident.startswith("DRM_FORMAT_MOD_"):
			ident = ident[len("DRM_FORMAT_MOD_"):]
			if ident.startswith("VENDOR_"):
				t = "ModifierVendor"
				ident = ident[len("VENDOR_"):]
		else:
			parts = ident.split("_FORMAT_MOD_")
			assert(len(parts) == 2)
			ident = parts[0] + "_" + parts[1]
		if ident in ["NONE"]:
			continue
	elif ident.startswith("DRM_FORMAT_"):
		t = "Format"
		ident = ident[len("DRM_FORMAT_"):]
		if ident in ["BIG_ENDIAN", "RESERVED"]:
			continue
	else:
		assert(False)

	name = ident
	if ident.lower() in words:
		name = ident.lower()
	elif t == "ModifierVendor":
		name = to_camel_case(ident)

	if t == "ModifierVendor" or ident.lower() in words:
		ident = to_camel_case(ident)

	consts.append({"name": name, "go_ident": t + ident, "value": val, "type": t})

with open("fourcc_generated.go", "w+") as go_file:
	go_file.write('// Code generated by fourcc.py - DO NOT EDIT\n')
	go_file.write('// libdrm ' + version + '\n')
	go_file.write('\n')
	go_file.write('package drm\n')
	for t in types:
		go_file.write('\n')
		go_file.write('const (\n')
		for cst in consts:
			if cst["type"] != t:
				continue
			go_file.write('\t' + cst["go_ident"] + ' ' + cst["type"] + ' = ' + cst["value"] + '\n')
		go_file.write(')\n')
		go_file.write('\n')
		go_file.write('func (v ' + t + ') String() string {\n')
		go_file.write('\tswitch v {\n')
		for cst in consts:
			if cst["type"] != t:
				continue
			go_file.write('\tcase ' + cst["go_ident"] + ':\n')
			go_file.write('\t\treturn "' + cst["name"] + '"\n')
		go_file.write('\tdefault:\n')
		go_file.write('\t\treturn "unknown"\n')
		go_file.write('\t}\n')
		go_file.write('}\n')
