import io
import itertools
from fontTools import ttLib
from fontTools.ttLib.tables._g_l_y_f import Glyph
from fontTools.fontBuilder import FontBuilder
from fontTools.merge import Merger
import unittest
import pytest


class MergeIntegrationTest(unittest.TestCase):
	# TODO
	pass

class gaspMergeUnitTest(unittest.TestCase):
	def setUp(self):
		self.merger = Merger()

		self.table1 = ttLib.newTable('gasp')
		self.table1.version = 1
		self.table1.gaspRange = {
			0x8: 0xA ,
			0x10: 0x5,
		}

		self.table2 = ttLib.newTable('gasp')
		self.table2.version = 1
		self.table2.gaspRange = {
			0x6: 0xB ,
			0xFF: 0x4,
		}

		self.result = ttLib.newTable('gasp')

	def test_gasp_merge_basic(self):
		result = self.result.merge(self.merger, [self.table1, self.table2])
		self.assertEqual(result, self.table1)

		result = self.result.merge(self.merger, [self.table2, self.table1])
		self.assertEqual(result, self.table2)

	def test_gasp_merge_notImplemented(self):
		result = self.result.merge(self.merger, [NotImplemented, self.table1])
		self.assertEqual(result, NotImplemented)

		result = self.result.merge(self.merger, [self.table1, NotImplemented])
		self.assertEqual(result, self.table1)


class CmapMergeUnitTest(unittest.TestCase):
	def setUp(self):
		self.merger = Merger()
		self.table1 = ttLib.newTable('cmap')
		self.table2 = ttLib.newTable('cmap')
		self.mergedTable = ttLib.newTable('cmap')
		pass

	def tearDown(self):
		pass


	def makeSubtable(self, format, platformID, platEncID, cmap):
		module = ttLib.getTableModule('cmap')
		subtable = module.cmap_classes[format](format)
		(subtable.platformID,
			subtable.platEncID,
			subtable.language,
			subtable.cmap) = (platformID, platEncID, 0, cmap)
		return subtable

	# 4-3-1 table merged with 12-3-10 table with no dupes with codepoints outside BMP
	def test_cmap_merge_no_dupes(self):
		table1 = self.table1
		table2 = self.table2
		mergedTable = self.mergedTable

		cmap1 = {0x2603: 'SNOWMAN'}
		table1.tables = [self.makeSubtable(4,3,1, cmap1)]

		cmap2 = {0x26C4: 'SNOWMAN WITHOUT SNOW'}
		cmap2Extended = {0x1F93C: 'WRESTLERS'}
		cmap2Extended.update(cmap2)
		table2.tables = [self.makeSubtable(4,3,1, cmap2), self.makeSubtable(12,3,10, cmap2Extended)]

		self.merger.alternateGlyphsPerFont = [{},{}]
		mergedTable.merge(self.merger, [table1, table2])

		expectedCmap = cmap2.copy()
		expectedCmap.update(cmap1)
		expectedCmapExtended = cmap2Extended.copy()
		expectedCmapExtended.update(cmap1)
		self.assertEqual(mergedTable.numSubTables, 2)
		self.assertEqual([(table.format, table.platformID, table.platEncID, table.language) for table in mergedTable.tables],
			[(4,3,1,0),(12,3,10,0)])
		self.assertEqual(mergedTable.tables[0].cmap, expectedCmap)
		self.assertEqual(mergedTable.tables[1].cmap, expectedCmapExtended)

	# Tests Issue #322
	def test_cmap_merge_three_dupes(self):
		table1 = self.table1
		table2 = self.table2
		mergedTable = self.mergedTable

		cmap1 = {0x20: 'space#0', 0xA0: 'space#0'}
		table1.tables = [self.makeSubtable(4,3,1,cmap1)]
		cmap2 = {0x20: 'space#1', 0xA0: 'uni00A0#1'}
		table2.tables = [self.makeSubtable(4,3,1,cmap2)]

		self.merger.duplicateGlyphsPerFont = [{},{}]
		mergedTable.merge(self.merger, [table1, table2])

		expectedCmap = cmap1.copy()
		self.assertEqual(mergedTable.numSubTables, 1)
		table = mergedTable.tables[0]
		self.assertEqual((table.format, table.platformID, table.platEncID, table.language), (4,3,1,0))
		self.assertEqual(table.cmap, expectedCmap)
		self.assertEqual(self.merger.duplicateGlyphsPerFont, [{}, {'space#0': 'space#1'}])


def _compile(ttFont):
	buf = io.BytesIO()
	ttFont.save(buf)
	buf.seek(0)
	return buf


def _make_fontfile_with_OS2(*, version, **kwargs):
	upem = 1000
	glyphOrder = [".notdef", "a"]
	cmap = {0x61: "a"}
	glyphs = {gn: Glyph() for gn in glyphOrder}
	hmtx = {gn: (500, 0) for gn in glyphOrder}
	names = {"familyName": "TestOS2", "styleName": "Regular"}

	fb = FontBuilder(unitsPerEm=upem)
	fb.setupGlyphOrder(glyphOrder)
	fb.setupCharacterMap(cmap)
	fb.setupGlyf(glyphs)
	fb.setupHorizontalMetrics(hmtx)
	fb.setupHorizontalHeader()
	fb.setupNameTable(names)
	fb.setupOS2(version=version, **kwargs)

	return _compile(fb.font)


def _merge_and_recompile(fontfiles, options=None):
	merger = Merger(options)
	merged = merger.merge(fontfiles)
	buf = _compile(merged)
	return ttLib.TTFont(buf)


@pytest.mark.parametrize(
	"v1, v2", list(itertools.permutations(range(5+1), 2))
)
def test_merge_OS2_mixed_versions(v1, v2):
	# https://github.com/fonttools/fonttools/issues/1865
	fontfiles = [
		_make_fontfile_with_OS2(version=v1),
		_make_fontfile_with_OS2(version=v2),
	]
	merged = _merge_and_recompile(fontfiles)
	assert merged["OS/2"].version == max(v1, v2)


if __name__ == "__main__":
	import sys
	sys.exit(unittest.main())