#!/usr/bin/env python

import StringIO
import struct
import sys

def xord(v):
	w = ord(v)
	#print w
	return w

def read_type_2_operand(stream, b0):
	if b0 == 28:
		return struct.unpack(">h", stream.read(2))
	elif b0 == 255:
		return float(struct.unpack(">i", stream.read(4))) / 65536.0
		# Fixed point with 16 bit fraction!
	else:
		return read_operand(stream, b0)

def read_operand(stream, b0):
	if b0 < 29:
		print >>sys.stderr, "info: b0 was: %d" % b0
	assert(b0 >= 29) # FIXME what about 31?
	if b0 == 29:
		return struct.unpack(">i", stream.read(4))
	elif b0 == 30:
		result = StringIO.StringIO()
		B_done = False
		while not B_done:
			input = xord(stream.read(1))
			for nibble in [input >> 4, input & 7]:
				if nibble < 10:
					result.write(chr(ord("0") + nibble))
				elif nibble == 0xa:
					result.write(".")
				elif nibble == 0xb:
					result.write("E")
				elif nibble == 0xc:
					result.write("E-")
				elif nibble == 0xd:
					pass # reserved
				elif nibble == 0xe:
					result.write("-")
				elif nibble == 0xf: # EOF
					B_done = True
					break

		return float(result.getvalue())
	elif b0 < 247:
		assert(b0 >= 32)
		return b0 - 139
	elif b0 < 251:
		return (b0 - 247) * 256 + xord(stream.read(1)) + 108
	elif b0 < 255:
		return -(b0 - 251) * 256 - xord(stream.read(1)) - 108
	else:
		assert(False)

class Table(object):
	@classmethod
	def read_from_stream(klass, stream, **kwargs):
		result = klass()
		for name, value in kwargs.items():
			setattr(result, name, value)
		for entry in klass.definition:
			name, type_spec = entry
			size = struct.calcsize(type_spec)
			value = struct.unpack(type_spec, stream.read(size))[0]
			setattr(result, name, value)
		result.read_remainder_from_stream(stream)
		return result

	def read_remainder_from_stream(self, stream):
		pass

	extra_field_names = []

	def __repr__(self):
		field_names = [entry[0] for entry in self.__class__.definition] + self.__class__.extra_field_names
		return "%s(%s)" % (self.__class__.__name__, ", ".join(["%s=%r" % (field_name, getattr(self, field_name)) for field_name in field_names]))

