import sys
import DefaultTable
import numpy
from fontTools import ttLib
from fontTools.misc.textTools import safeEval
import warnings


class table__h_m_t_x(DefaultTable.DefaultTable):
	
	headerTag = 'hhea'
	advanceName = 'width'
	sideBearingName = 'lsb'
	numberOfMetricsName = 'numberOfHMetrics'
	
	def decompile(self, data, ttFont):
		numberOfMetrics = int(getattr(ttFont[self.headerTag], self.numberOfMetricsName))
		metrics = numpy.fromstring(data[:4 * numberOfMetrics], 
				numpy.int16)
		if sys.byteorder <> "big":
			metrics = metrics.byteswap()
		metrics.shape = (numberOfMetrics, 2)
		data = data[4 * numberOfMetrics:]
		numberOfSideBearings = ttFont['maxp'].numGlyphs - numberOfMetrics
		numberOfSideBearings = int(numberOfSideBearings)
		if numberOfSideBearings:
			assert numberOfSideBearings > 0, "bad hmtx/vmtx table"
			lastAdvance = metrics[-1][0]
			advances = numpy.array([lastAdvance] * numberOfSideBearings, 
					numpy.int16)
			sideBearings = numpy.fromstring(data[:2 * numberOfSideBearings], 
					numpy.int16)
			if sys.byteorder <> "big":
				sideBearings = sideBearings.byteswap()
			data = data[2 * numberOfSideBearings:]
			if len(advances) and len(sideBearings):
				additionalMetrics = numpy.array([advances, sideBearings], numpy.int16)
				metrics = numpy.concatenate((metrics, numpy.transpose(additionalMetrics)))
			else:
				warnings.warn('Unable to include additional metrics')
		if data:
			sys.stderr.write("too much data for hmtx/vmtx table\n")
		metrics = metrics.tolist()
		self.metrics = {}
		for i in range(len(metrics)):
			glyphName = ttFont.getGlyphName(i)
			self.metrics[glyphName] = metrics[i]
	
	def compile(self, ttFont):
		metrics = []
		for glyphName in ttFont.getGlyphOrder():
			metrics.append(self.metrics[glyphName])
		lastAdvance = metrics[-1][0]
		lastIndex = len(metrics)
		while metrics[lastIndex-2][0] == lastAdvance:
			lastIndex = lastIndex - 1
			if lastIndex <= 1:
				# all advances are equal
				lastIndex = 1
				break
		additionalMetrics = metrics[lastIndex:]
		additionalMetrics = map(lambda (advance, sb): sb, additionalMetrics)
		metrics = metrics[:lastIndex]
		setattr(ttFont[self.headerTag], self.numberOfMetricsName, len(metrics))
		
		metrics = numpy.array(metrics, numpy.int16)
		if sys.byteorder <> "big":
			metrics = metrics.byteswap()
		data = metrics.tostring()
		
		additionalMetrics = numpy.array(additionalMetrics, numpy.int16)
		if sys.byteorder <> "big":
			additionalMetrics = additionalMetrics.byteswap()
		data = data + additionalMetrics.tostring()
		return data
	
	def toXML(self, writer, ttFont):
		names = self.metrics.keys()
		names.sort()
		for glyphName in names:
			advance, sb = self.metrics[glyphName]
			writer.simpletag("mtx", [
					("name", glyphName), 
					(self.advanceName, advance), 
					(self.sideBearingName, sb),
					])
			writer.newline()
	
	def fromXML(self, (name, attrs, content), ttFont):
		if not hasattr(self, "metrics"):
			self.metrics = {}
		if name == "mtx":
			self.metrics[attrs["name"]] = [safeEval(attrs[self.advanceName]), 
					safeEval(attrs[self.sideBearingName])]
	
	def __getitem__(self, glyphName):
		return self.metrics[glyphName]
	
	def __setitem__(self, glyphName, (advance, sb)):
		self.metrics[glyphName] = advance, sb

