from __future__ import print_function, division, absolute_import
from fontTools.misc.py23 import *
from fontTools.misc import sstruct
from fontTools.misc.textTools import safeEval, num2binary, binary2num
from . import DefaultTable
import warnings


# panose classification

panoseFormat = """
	bFamilyType:        B
	bSerifStyle:        B
	bWeight:            B
	bProportion:        B
	bContrast:          B
	bStrokeVariation:   B
	bArmStyle:          B
	bLetterForm:        B
	bMidline:           B
	bXHeight:           B
"""

class Panose(object):

	def toXML(self, writer, ttFont):
		formatstring, names, fixes = sstruct.getformat(panoseFormat)
		for name in names:
			writer.simpletag(name, value=getattr(self, name))
			writer.newline()

	def fromXML(self, name, attrs, content, ttFont):
		setattr(self, name, safeEval(attrs["value"]))


# 'sfnt' OS/2 and Windows Metrics table - 'OS/2'

OS2_format_0 = """
	>   # big endian
	version:                H       # version
	xAvgCharWidth:          h       # average character width
	usWeightClass:          H       # degree of thickness of strokes
	usWidthClass:           H       # aspect ratio
	fsType:                 h       # type flags
	ySubscriptXSize:        h       # subscript horizontal font size
	ySubscriptYSize:        h       # subscript vertical font size
	ySubscriptXOffset:      h       # subscript x offset
	ySubscriptYOffset:      h       # subscript y offset
	ySuperscriptXSize:      h       # superscript horizontal font size
	ySuperscriptYSize:      h       # superscript vertical font size
	ySuperscriptXOffset:    h       # superscript x offset
	ySuperscriptYOffset:    h       # superscript y offset
	yStrikeoutSize:         h       # strikeout size
	yStrikeoutPosition:     h       # strikeout position
	sFamilyClass:           h       # font family class and subclass
	panose:                 10s     # panose classification number
	ulUnicodeRange1:        L       # character range
	ulUnicodeRange2:        L       # character range
	ulUnicodeRange3:        L       # character range
	ulUnicodeRange4:        L       # character range
	achVendID:              4s      # font vendor identification
	fsSelection:            H       # font selection flags
	fsFirstCharIndex:       H       # first unicode character index
	fsLastCharIndex:        H       # last unicode character index
	sTypoAscender:          h       # typographic ascender
	sTypoDescender:         h       # typographic descender
	sTypoLineGap:           h       # typographic line gap
	usWinAscent:            H       # Windows ascender
	usWinDescent:           H       # Windows descender
"""

OS2_format_1_addition =  """
	ulCodePageRange1:   L
	ulCodePageRange2:   L
"""

OS2_format_2_addition =  OS2_format_1_addition + """
	sxHeight:           h
	sCapHeight:         h
	usDefaultChar:      H
	usBreakChar:        H
	usMaxContex:        H
"""

OS2_format_5_addition =  OS2_format_2_addition + """
	usLowerOpticalPointSize:    H
	usUpperOpticalPointSize:    H
"""

bigendian = "	>	# big endian\n"

OS2_format_1 = OS2_format_0 + OS2_format_1_addition
OS2_format_2 = OS2_format_0 + OS2_format_2_addition
OS2_format_5 = OS2_format_0 + OS2_format_5_addition
OS2_format_1_addition = bigendian + OS2_format_1_addition
OS2_format_2_addition = bigendian + OS2_format_2_addition
OS2_format_5_addition = bigendian + OS2_format_5_addition


class table_O_S_2f_2(DefaultTable.DefaultTable):

	"""the OS/2 table"""

	def decompile(self, data, ttFont):
		dummy, data = sstruct.unpack2(OS2_format_0, data, self)

		if self.version == 1:
			dummy, data = sstruct.unpack2(OS2_format_1_addition, data, self)
		elif self.version in (2, 3, 4):
			dummy, data = sstruct.unpack2(OS2_format_2_addition, data, self)
		elif self.version == 5:
			dummy, data = sstruct.unpack2(OS2_format_5_addition, data, self)
			self.usLowerOpticalPointSize /= 20
			self.usUpperOpticalPointSize /= 20
		elif self.version != 0:
			from fontTools import ttLib
			raise ttLib.TTLibError("unknown format for OS/2 table: version %s" % self.version)
		if len(data):
			warnings.warn("too much 'OS/2' table data")

		self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())

	def compile(self, ttFont):
		self.updateFirstAndLastCharIndex(ttFont)
		panose = self.panose
		self.panose = sstruct.pack(panoseFormat, self.panose)
		if self.version == 0:
			data = sstruct.pack(OS2_format_0, self)
		elif self.version == 1:
			data = sstruct.pack(OS2_format_1, self)
		elif self.version in (2, 3, 4):
			data = sstruct.pack(OS2_format_2, self)
		elif self.version == 5:
			d = self.__dict__.copy()
			d['usLowerOpticalPointSize'] = int(round(self.usLowerOpticalPointSize * 20))
			d['usUpperOpticalPointSize'] = int(round(self.usUpperOpticalPointSize * 20))
			data = sstruct.pack(OS2_format_5, d)
		else:
			from fontTools import ttLib
			raise ttLib.TTLibError("unknown format for OS/2 table: version %s" % self.version)
		self.panose = panose
		return data

	def toXML(self, writer, ttFont):
		writer.comment(
			"The fields 'fsFirstCharIndex' and 'fsLastCharIndex'\n"
			"will be recalculated by the compiler")
		writer.newline()
		if self.version == 1:
			format = OS2_format_1
		elif self.version in (2, 3, 4):
			format = OS2_format_2
		elif self.version == 5:
			format = OS2_format_5
		else:
			format = OS2_format_0
		formatstring, names, fixes = sstruct.getformat(format)
		for name in names:
			value = getattr(self, name)
			if name=="panose":
				writer.begintag("panose")
				writer.newline()
				value.toXML(writer, ttFont)
				writer.endtag("panose")
			elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
					"ulUnicodeRange3", "ulUnicodeRange4",
					"ulCodePageRange1", "ulCodePageRange2"):
				writer.simpletag(name, value=num2binary(value))
			elif name in ("fsType", "fsSelection"):
				writer.simpletag(name, value=num2binary(value, 16))
			elif name == "achVendID":
				writer.simpletag(name, value=repr(value)[1:-1])
			else:
				writer.simpletag(name, value=value)
			writer.newline()

	def fromXML(self, name, attrs, content, ttFont):
		if name == "panose":
			self.panose = panose = Panose()
			for element in content:
				if isinstance(element, tuple):
					name, attrs, content = element
					panose.fromXML(name, attrs, content, ttFont)
		elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
				"ulUnicodeRange3", "ulUnicodeRange4",
				"ulCodePageRange1", "ulCodePageRange2",
				"fsType", "fsSelection"):
			setattr(self, name, binary2num(attrs["value"]))
		elif name == "achVendID":
			setattr(self, name, safeEval("'''" + attrs["value"] + "'''"))
		else:
			setattr(self, name, safeEval(attrs["value"]))

	def updateFirstAndLastCharIndex(self, ttFont):
		codes = set()
		for table in ttFont['cmap'].tables:
			if table.isUnicode():
				codes.update(table.cmap.keys())
		if codes:
			minCode = min(codes)
			maxCode = max(codes)
			# USHORT cannot hold codepoints greater than 0xFFFF
			self.fsFirstCharIndex = 0xFFFF if minCode > 0xFFFF else minCode
			self.fsLastCharIndex = 0xFFFF if maxCode > 0xFFFF else maxCode
