local glue = require'glue'
local ffi = require'ffi'
local pp = require'pp'
local ft = require'freetype'

local function inspect_face(lib, facename)
	local face = lib:face(facename)

	print(facename)
	print(('-'):rep(78))

	local face_flag_names = {
		[ft.C.FT_FACE_FLAG_SCALABLE]            = 'SCALABLE',
		[ft.C.FT_FACE_FLAG_FIXED_SIZES]         = 'FIXED_SIZES',
		[ft.C.FT_FACE_FLAG_FIXED_WIDTH]         = 'FIXED_WIDTH',
		[ft.C.FT_FACE_FLAG_SFNT]                = 'SFNT',
		[ft.C.FT_FACE_FLAG_HORIZONTAL]          = 'HORIZONTAL',
		[ft.C.FT_FACE_FLAG_VERTICAL]            = 'VERTICAL',
		[ft.C.FT_FACE_FLAG_KERNING]             = 'KERNING',
		[ft.C.FT_FACE_FLAG_FAST_GLYPHS]         = 'FAST_GLYPHS',
		[ft.C.FT_FACE_FLAG_MULTIPLE_MASTERS]    = 'MULTIPLE_MASTERS',
		[ft.C.FT_FACE_FLAG_GLYPH_NAMES]         = 'GLYPH_NAMES',
		[ft.C.FT_FACE_FLAG_EXTERNAL_STREAM]     = 'EXTERNAL_STREAM',
		[ft.C.FT_FACE_FLAG_HINTER]              = 'HINTER',
		[ft.C.FT_FACE_FLAG_CID_KEYED]           = 'CID_KEYED',
		[ft.C.FT_FACE_FLAG_TRICKY]              = 'TRICKY',
	}

	local style_flag_names = {
		[ft.C.FT_STYLE_FLAG_ITALIC]  = 'ITALIC',
		[ft.C.FT_STYLE_FLAG_BOLD]    = 'BOLD',
	}

	local function flags(flags, flag_names)
		local s
		for k,v in pairs(flag_names) do
			s = bit.band(flags, k) ~= 0 and ((s and s..', ' or '')..v) or s
		end
		return s or ''
	end

	local function pad(s, n)
		return s..(' '):rep(n - #s)
	end

	local function struct(t,fields,decoders,indent)
		indent = indent or ''
		local s = ''
		for i,k in ipairs(fields) do
			s = s .. '\n   ' .. indent .. pad(k..':', 21 - #indent) .. (decoders and decoders[k] or glue.pass)(t[k])
		end
		return s
	end

	local function struct_array(t,n,fields,decoders,indent)
		indent = indent or ''
		local s = ''
		for i=0,n-1 do
			for j,k in ipairs(fields) do
				s = s .. '\n ' .. (j == 1 and '* ' or '  ') .. indent .. pad(k..':', 21 - #indent) ..
						(decoders and decoders[k] or glue.pass)(t[i][k])
			end
		end
		return s
	end

	local function x26_6(x)
		return tonumber(x) / 64
	end

	local bitmap_size_fields = {'height','width','size','x_ppem','y_ppem'}
	local bitmap_size_decoders = {height = tonumber, width = tonumber, size = x26_6, x_ppem = x26_6, y_ppem = x26_6}
	local charmap_fields = {'encoding','platform_id','encoding_id'}
	local charmap_decoders = {encoding = ft.tag_tostring}
	local bbox_fields = {'xMin','yMin','xMax','yMax'}
	local bbox_decoders = {xMin = x26_6, yMin = x26_6, xMax = x26_6, yMax = x26_6}
	local metrics_fields = {'x_ppem','y_ppem','x_scale','y_scale','ascender','descender','height','max_advance'}
	local metrics_decoders = { x_ppem = tonumber, y_ppem = tonumber, x_scale = tonumber, y_scale = tonumber, ascender = tonumber, descender = tonumber, height = tonumber, max_advance = tonumber}
	local size_fields = {'metrics'}
	local size_decoders = {metrics = function(m) return struct(m, metrics_fields, metrics_decoders, '   ') end}
	print('num_faces:           ', face.num_faces)
	print('face_index:          ', tonumber(face.face_index))
	print('face_flags:          ', flags(tonumber(face.face_flags), face_flag_names))
	print('style_flags:         ', flags(tonumber(face.style_flags), style_flag_names))
	print('num_glyphs:          ', face.num_glyphs)
	print('familiy_name:        ', ffi.string(face.family_name))
	print('style_name:          ', ffi.string(face.style_name))
	print('num_fixed_sizes:     ', face.num_fixed_sizes)
	print('available_sizes:     ', struct_array(face.available_sizes, face.num_fixed_sizes, bitmap_size_fields, bitmap_size_decoders))
	print('num_charmaps:        ', face.num_charmaps)
	print('charmaps:            ', struct_array(face.charmaps, face.num_charmaps, charmap_fields, charmap_decoders))
	print('bbox:                ', struct(face.bbox, bbox_fields, bbox_decoders))
	print('units_per_EM:        ', x26_6(face.units_per_EM))
	print('ascender:            ', x26_6(face.ascender))
	print('descender:           ', x26_6(face.descender))
	print('height:              ', x26_6(face.height))
	print('max_advance_width:   ', x26_6(face.max_advance_width))
	print('max_advance_height:  ', x26_6(face.max_advance_height))
	print('underline_position:  ', x26_6(face.underline_position))
	print('underline_thickness: ', x26_6(face.underline_thickness))
	print('charmap:             ', struct(face.charmap, charmap_fields, charmap_decoders))

	--print('size:                ', struct(face.size, size_fields, size_decoders))
	--face:set_pixel_sizes(16)

	for i=0,face.num_charmaps-1 do
		face:select_charmap(face.charmaps[i].encoding)
		local n = face:char_count()
		print(string.format('charmap %d:              %d\tentries', i, n))
	end

	print()
	face:free()
end

local lib = ft:new()

print(string.format('Freetype version: %d.%d.%d', lib:version()))

inspect_face(lib, 'media/fonts/DejaVuSerif.ttf')
inspect_face(lib, 'media/fonts/amiri-regular.ttf')
inspect_face(lib, 'media/fonts/fireflysung.ttf')
--inspect_face(lib, 'media/fonts/NotoColorEmoji.ttf')

lib:free()
