# Parses all the data files into one database file.
# COpyright (C) 2026-09-18 Linsinite

# creates the file database.json in the format of: (acient; this is not how it works anymore lol)
"""
{
	...
	"氵": [7, "水"],
	...
	"海": ["hǎi", "sea, ocean; maritime", ["氵", "每"]],
	...
}
"""

import re, math, json

def makeCharacterListTape():
	charfile = open("ChartofStandardFormsofCommonNationalCharacters.txt")
	characters = charfile.read().split("\n")

	minchar = int(1e+100)
	maxchar = 0
	for chardef in characters: # prepares unicode range
		# print("Preparing Unicode range... ({:.0f}%)\033[K\r".format(math.floor(100 * (i + 1) / len(characters))), end="")
		if len(chardef) != 0:
			chardefsplit = chardef.split(" ")
			unicode = int(chardefsplit[2], 16)
			if unicode < minchar:
				minchar = unicode
			if unicode > maxchar:
				maxchar = unicode

	charactertape = [0] * (maxchar - minchar + 1)
	characterlist = []
	for i, chardef in enumerate(characters):
		# print("Making character list and tape... ({:.0f}%)\033[K\r".format(math.floor(100 * (i + 1) / len(characters))), end="")
		chardefsplit = chardef.split(" ")
		unicode = int(chardefsplit[2], 16)
		characterlist.append(unicode)
		charactertape[unicode - minchar] = 1

	charfile.close()
	return {
		"list": characterlist,
		"tape": charactertape,
		"range": [minchar, maxchar]
	}

def makePhoneticsDefinitionsList(deccharacterrange):
	urfile = open("Unihan_Readings.txt")
	unihanreadings = urfile.read().split("\n")

	readingslist = [""] * (deccharacterrange[1] - deccharacterrange[0] + 1)
	definitionslist = [""] * (deccharacterrange[1] - deccharacterrange[0] + 1)

	for i, reading in enumerate(unihanreadings): # could somewhat easily be optimized further but meh
		print("Constructing phonetics and definitions... ({:.0f}%)\033[K\r".format(math.floor(100 * (i + 1) / len(unihanreadings))), end="")
		if len(reading) != 0 and reading[0] != "#":
			readingsplit = reading.split("\t")
			unicodesub = int(readingsplit[0][2:], 16) - deccharacterrange[0]
			if unicodesub >= 0 and unicodesub < len(readingslist):
				if len(readingsplit) == 3:
					if readingsplit[1] == "kHanyuPinlu":
						readingslist[unicodesub] = re.sub(r"\([0-9]+\)", "", readingsplit[2]).replace(" ", ", ")
					if readingsplit[1] == "kHanyuPinyin":
						readingslist[unicodesub] = readingsplit[2].split(" ")[0].split(":")[1].replace(",", ", ")
					if readingsplit[1] == "kMandarin" and readingslist[unicodesub] == "":
						readingslist[unicodesub] = readingsplit[2]
					if readingsplit[1] == "kDefinition":
						definitionslist[unicodesub] = readingsplit[2]
	print()

	urfile.close()
	return [readingslist, definitionslist]

def makeDecompositionsList(unicoderange, characterlist):
	decfile = open("cjk-decomp.txt")
	decompositions = decfile.read().split("\n")
	if len(decompositions[-1]) == 0:
		decompositions.pop()

	unencdecomps = [[]] * 89999
	
	# adding unencoded characters
	minunidecom = int(1e+100)
	maxunidecom = 0
	unidecstart = 0
	for i, dec in enumerate(decompositions):
		print("Adding unencoded characters... ({:.0f}%)\033[K\r".format(math.floor(100 * (i + 1) / len(decompositions))), end="")
		decsplit = dec.split(":")
		if ord(decsplit[0][0]) < 0x3A:
			unencdecomps[int(decsplit[0]) - 10001] = re.sub(r"^.+\(|\)", "", decsplit[1]).split(",")
			encodstart = i + 1
		else:
			if ord(decsplit[0]) < minunidecom:
				minunidecom = ord(decsplit[0])
			if ord(decsplit[0]) > maxunidecom:
				maxunidecom = ord(decsplit[0])
	print()
	
	# adding encoded characters
	encodeddecomps = [[]] * (maxunidecom - minunidecom + 1)
	encdecompsstart = decompositions[encodstart:]
	for i, dec in enumerate(encdecompsstart):
		print("Adding encoded characters... ({:.0f}%)\033[K\r".format(math.floor(100 * (i + 1) / len(encdecompsstart))), end="")
		decsplit = dec.split(":")
		encodeddecomps[ord(decsplit[0]) - minunidecom] = re.sub(r"^.+\(|\)", "", decsplit[1]).split(",")
	print()
	
	# fully decomposes encoded characters
	def decomposeFully(character):
		if ord(character[0]) < 0x3A: # number, always decompose
			return [""] + [decomposeFully(c) for c in unencdecomps[int(character) - 10001]]
		elif character not in "一㇐㇑㇔㇓㇠㇚二亠人儿入八冂冖冫几凵刀力勹匕匚匸十卜卩厂厶又口囗土士夂夊夕大女子宀寸小尢尸屮山巛工己巾干幺广廴廾弋弓彐彡彳心戈戶手支攴文斗斤方无日曰月木欠止歹殳毋母比毛氏气水火爪父爻爿片牙牛犬玄玉瓜瓦甘生用田疋疒癶白皮皿目矛矢石示禸禾穴立竹米糸缶网羊羽老而耒耳聿肉臣自至臼舌舛舟艮色艸虍虫血行衣襾西見角言谷豆豕豸貝赤走足身車辛辰辵邑酉釆里金長門阜隶隹雨靑青非面革韋韭音頁風飛食首香馬骨高髟鬥鬯鬲鬼魚鳥鹵鹿麥麻黃黍黑黹黽鼎鼓鼠鼻齊齒龍龜龠":
			# not a Kangxi radical, always decompose
			if any([(i in "㇀㇁㇂㇃㇄㇅㇆㇇㇈㇉㇊㇋㇌㇍㇎㇏㇐㇑㇒㇓㇔㇕㇖㇗㇙㇚㇛㇜㇝㇞㇟㇠㇡㇢㇣") for i in encodeddecomps[ord(character) - minunidecom]]):
				# do not decompose if it has single stroke components
				return character
			else: # decompose otherwise
				return [character] + [decomposeFully(c) for c in encodeddecomps[ord(character) - minunidecom]]
		else: # do not decompose if it is a Kangxi radical
			return character

	#dhdfjh = "⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳"
	#print("".join([(encodeddecomps[ord(c) - minunidecom][0] if len(encodeddecomps[ord(c) - minunidecom]) == 1 else c) for c in dhdfjh]))
	
	fulldecomps = [[]] * len(characterlist)
	for i, c in enumerate(characterlist):
		print("Constructing full decompositions... ({:.0f}%)\033[K\r".format(math.floor(100 * (i + 1) / len(characterlist))), end="")
		fulldecomps[i] = decomposeFully(chr(c))
	print()
	
	decfile.close()
	return [fulldecomps, [minunidecom, maxunidecom]]

if __name__ == "__main__":
	charactertapelist = makeCharacterListTape()
	unicoderange = charactertapelist["range"]

	decompositionsnrange = makeDecompositionsList(unicoderange, charactertapelist["list"])
	phoneticsdefinitions = makePhoneticsDefinitionsList(decompositionsnrange[1])
	final = {
		"phonetics":           phoneticsdefinitions[0],
		"definitions":         phoneticsdefinitions[1],
		"decompositionsrange": decompositionsnrange[1],
		"decompositions":      decompositionsnrange[0]
	}

	database = open("hanzidatabase.json", "w")
	database.write(json.dumps(final, ensure_ascii=False))
	database.close()

"""
⺁→厂
⺆→冂
⺊→V
⺌→V
⺍→V
⺕→Ｖ
⺗→Ｖ
⺘→V
⺙→V
⺛→V
⺢→V
⺦→V
⺪→V
⺭→V
⺯→V
⺰→V
⺳→V
⺴→V
⺺→V
⺻→V
⺼→V
艹→艸
⺿:me(⺾)
[:d(卄,*)]→艹
⻊→V
⻌:me(辶)
⻍→V
⻎→V
⻐→V
[a:(*,⻖)]->⻏
⻏→邑
⻖R→阜
⻚→V
⻛→Ｖ
⻜→V
⻠→V
⻡→V
⻥→V
⻩→V
⻭→V
⻁→V
⻇→V
尢→V
水
灬
𠂉
扌
犭
亻
刂
a(金
礻
衤
罒
忄
⺹
辶
爿
开
弁
异
弃
弄
弈
弊
:a(月
"""