from .parser import parseFiles


def toConsole(sourceFiles, definedNames=[]):
	data = parseFiles(sourceFiles, definedNames)

	if data.gasp is not None:
		print("---- gasp ----")
		for size, doGridfit, doGray, symSmoothing, symGridfit in data.gasp:
			line = "{:5d}".format(size)
			if doGridfit    : line += " doGridfit"
			if doGray       : line += " doGray"
			if symSmoothing : line += " symSmoothing"
			if symGridfit   : line += " symGridfit"
			print(line)
		print()

	if data.head is not None:
		print("---- head ----")
		for name, value in data.head.items():
			if name == "flags":
				for bitIndex, bitValue in value:
					print("{:2d} flags Bit {}".format(bitValue, bitIndex))
			else:
				print("{:2d} {}".format(value, name))
		print()

	if data.maxp is not None:
		print("---- maxp ----")
		for name, value in data.maxp.items():
			print("{:5d} {}".format(value, name))
		print()

	if data.cvt is not None:
		print("---- cvt ----")
		for value in data.cvt:
			print(value)
		print()

	if data.fpgm is not None:
		print("---- fpgm ----")
		print(str(data.fpgm))

	if data.prep is not None:
		print("---- prep ----")
		print(str(data.prep))

	for name, program in data.glyphs.items():
		print("----", name, "----")
		print(str(program))


def toFontforge(sourceFiles, font, definedNames=[]):
	data = parseFiles(sourceFiles, definedNames)

	if data.gasp is not None:
		gasp = []
		for size, doGridfit, doGray, symSmoothing, symGridfit in data.gasp:
			flags = []
			if doGridfit    : flags.append("gridfit")
			if doGray       : flags.append("antialias")
			if symSmoothing : flags.append("symmetric-smoothing")
			if symGridfit   : flags.append("gridfit+smoothing")
			gasp.append((size, tuple(flags)))
		font.gasp_version = 1
		font.gasp = tuple(gasp)

	if data.head is not None:
		for name, value in data.head.items():
			if name == "flags":
				for bitIndex, bitValue in value:
					if bitIndex == 13:
						font.head_optimized_for_cleartype = bitValue
					else:
						print("FontForge cannot set head flags bit: {}".format(bitIndex))
			else:
				print("FontForge cannot set head record: {}".format(name))

	if data.maxp is not None:
		for name, value in data.maxp.items():
			if name == "maxStackElements" : font.maxp_maxStackDepth = value
			if name == "maxFunctionDefs"  : font.maxp_FDEFs = value
			if name == "maxStorage"       : font.maxp_storageCnt = value
			if name == "maxZones"         : font.maxp_zones = value
			if name == "maxTwilightPoints": font.maxp_twilightPtCnt = value

	if data.cvt is not None:
		font.cvt = data.cvt

	if data.fpgm is not None:
		font.setTableData("fpgm", bytes(data.fpgm))

	if data.prep is not None:
		font.setTableData("prep", bytes(data.prep))

	for name, program in data.glyphs.items():
		try:
			font[name].ttinstrs = bytes(program)
		except Exception:
			print("Error with glyph: " + name)
			raise


def toFontTools(sourceFiles, font, definedNames=[]):
	import array
	from fontTools import ttLib
	from fontTools.ttLib.tables._g_a_s_p import GASP_SYMMETRIC_GRIDFIT, GASP_SYMMETRIC_SMOOTHING, GASP_DOGRAY, GASP_GRIDFIT
	from fontTools.ttLib.tables._g_l_y_f import ROUND_XY_TO_GRID, USE_MY_METRICS
	data = parseFiles(sourceFiles, definedNames)

	if data.gasp is not None:
		gasp = ttLib.newTable("gasp")
		gasp.gaspRange = {}
		for size, doGridfit, doGray, symSmoothing, symGridfit in data.gasp:
			flags = 0
			if doGridfit    : flags |= GASP_GRIDFIT
			if doGray       : flags |= GASP_DOGRAY
			if symSmoothing : flags |= GASP_SYMMETRIC_SMOOTHING
			if symGridfit   : flags |= GASP_SYMMETRIC_GRIDFIT
			gasp.gaspRange[size] = flags
		gasp.version = 1
		font["gasp"] = gasp

	if data.maxp is not None:
		for name, value in data.maxp.items():
			if name == "maxStackElements" : font["maxp"].maxStackElements = value
			if name == "maxFunctionDefs"  : font["maxp"].maxFunctionDefs = value
			if name == "maxStorage"       : font["maxp"].maxStorage = value
			if name == "maxZones"         : font["maxp"].maxZones = value
			if name == "maxTwilightPoints": font["maxp"].maxTwilightPoints = value

	if data.cvt is not None:
		font["cvt "] = cvt = ttLib.newTable("cvt ")
		cvt.values = array.array("h", data.cvt)

	if data.fpgm is not None:
		font["fpgm"] = fpgm = ttLib.newTable("fpgm")
		fpgm.program = ttLib.tables.ttProgram.Program()
		fpgm.program.fromBytecode(bytes(data.fpgm))

	if data.head is not None:
		for bitIndex, bitValue in data.head["flags"]:
			font["head"].flags &= ~(1 << bitIndex)
			font["head"].flags |= (bitValue << bitIndex)
		font["head"].lowestRecPPEM = data.head.get(
			"lowestRecPPEM",
			font["head"].lowestRecPPEM
		)

	if data.prep is not None:
		font["prep"] = prep = ttLib.newTable("prep")
		prep.program = ttLib.tables.ttProgram.Program()
		prep.program.fromBytecode(bytes(data.prep))

	for name, program in data.glyphs.items():
		try:
			glyph = font["glyf"][name]
			glyph.program = ttLib.tables.ttProgram.Program()
			glyph.program.fromBytecode(bytes(program))
			if glyph.isComposite():
				# Remove empty glyph programs from composite glyphs
				if not glyph.program:
					delattr(glyph, "program")
				# Recalculate component flags
				found_metrics = False
				width, _lsb = font["hmtx"][name]
				for c in glyph.components:
					# Reset all flags we will calculate ourselves
					c.flags &= ~USE_MY_METRICS
					c.flags &= ~ROUND_XY_TO_GRID

					# Set ROUND_XY_TO_GRID if the component has an offset
					if c.x != 0 or c.y != 0:
						c.flags |= ROUND_XY_TO_GRID

					try:
						_baseName, transform = c.getComponentInfo()
					except AttributeError:
						continue
					try:
						baseMetrics = font["hmtx"][c.glyphName]
					except KeyError:
						continue
					else:
						# Set USE_MY_METRICS on the first matching component
						if (
							not found_metrics
							and baseMetrics[0] == width
							and transform[:-1] == (1, 0, 0, 1, 0)
						):
							c.flags |= USE_MY_METRICS
							found_metrics = True
		except Exception:
			print("Error with glyph: " + name)
			raise

	# Recalculate maxp.maxSizeOfInstructions
	sizes = [
		len(glyph.program.getBytecode())
		for glyph in font["glyf"].glyphs.values()
		if hasattr(glyph, "program")
	] + [0]
	font["maxp"].maxSizeOfInstructions = max(sizes)


# EXTEND Add to* function for new target type
