#! /usr/bin/env python

import os
import sys
import numpy
import math
import struct

def BinRead(filin,filout=''):

	from MatlabFuncs import *
	from EnumDefinitions import *
	from EnumToString import EnumToString

	print "reading binary file."
	f=open(filin,'rb')

	if filout:
		sys.stdout=open(filout,'w')

	while True:
		try:
			#Step 1: read the enum to identify this record uniquely
			enum=struct.unpack('i',f.read(struct.calcsize('i')))[0]
		except struct.error as e:
			print "probable EOF: %s" % e
			break
		print "\nenum = %d (%s)" % (enum,EnumToString(enum)[0])

		#Step 2: read the data itself.
		#first read length of record
		reclen=struct.unpack('i',f.read(struct.calcsize('i')))[0]
		print "reclen = %d" % reclen

		#read data code: 
		code=struct.unpack('i',f.read(struct.calcsize('i')))[0]
		print "code = %d" % code

		if   code == FormatToCode('Boolean'):
#			bval=struct.unpack('b',f.read(reclen-struct.calcsize('i')))[0]
			bval=struct.unpack('i',f.read(reclen-struct.calcsize('i')))[0]
			print "bval = %d" % bval

		elif code == FormatToCode('Integer'):
			ival=struct.unpack('i',f.read(reclen-struct.calcsize('i')))[0]
			print "ival = %d" % ival

		elif code == FormatToCode('Double'):
			dval=struct.unpack('d',f.read(reclen-struct.calcsize('i')))[0]
			print "dval = %f" % dval

		elif code == FormatToCode('String'):
			strlen=struct.unpack('i',f.read(struct.calcsize('i')))[0]
			print "strlen = %d" % strlen
			sval=struct.unpack('%ds' % strlen,f.read(strlen))[0]
			print "sval = '%s'" % sval

		elif code == FormatToCode('BooleanMat'):
			#read matrix type: 
			mattype=struct.unpack('i',f.read(struct.calcsize('i')))[0]
			print "mattype = %d" % mattype

			#now read matrix
			s=[0,0]
			s[0]=struct.unpack('i',f.read(struct.calcsize('i')))[0]
			s[1]=struct.unpack('i',f.read(struct.calcsize('i')))[0]
			print "s = [%dx%d]" % (s[0],s[1])
			data=numpy.zeros((s[0],s[1]))
			for i in xrange(s[0]):
				for j in xrange(s[1]):
					data[i][j]=struct.unpack('d',f.read(struct.calcsize('d')))[0]    #get to the "c" convention, hence the transpose
					print "data[%d,%d] = %f" % (i,j,data[i][j])

		elif code == FormatToCode('IntMat'):
			#read matrix type: 
			mattype=struct.unpack('i',f.read(struct.calcsize('i')))[0]
			print "mattype = %d" % mattype

			#now read matrix
			s=[0,0]
			s[0]=struct.unpack('i',f.read(struct.calcsize('i')))[0]
			s[1]=struct.unpack('i',f.read(struct.calcsize('i')))[0]
			print "s = [%dx%d]" % (s[0],s[1])
			data=numpy.zeros((s[0],s[1]))
			for i in xrange(s[0]):
				for j in xrange(s[1]):
					data[i][j]=struct.unpack('d',f.read(struct.calcsize('d')))[0]    #get to the "c" convention, hence the transpose
					print "data[%d,%d] = %f" % (i,j,data[i][j])

		elif code == FormatToCode('DoubleMat'):
			#read matrix type: 
			mattype=struct.unpack('i',f.read(struct.calcsize('i')))[0]
			print "mattype = %d" % mattype

			#now read matrix
			s=[0,0]
			s[0]=struct.unpack('i',f.read(struct.calcsize('i')))[0]
			s[1]=struct.unpack('i',f.read(struct.calcsize('i')))[0]
			print "s = [%dx%d]" % (s[0],s[1])
			data=numpy.zeros((s[0],s[1]))
			for i in xrange(s[0]):
				for j in xrange(s[1]):
					data[i][j]=struct.unpack('d',f.read(struct.calcsize('d')))[0]    #get to the "c" convention, hence the transpose
					print "data[%d,%d] = %f" % (i,j,data[i][j])

		elif code == FormatToCode('MatArray'):
			fid.seek(reclen-4,1)
			print "skipping %d bytes for code %d." % (code, reclen-4)

		elif code == FormatToCode('StringArray'):
			fid.seek(reclen-4,1)
			print "skipping %d bytes for code %d." % (code, reclen-4)

		else:
			raise TypeError('BinRead error message: data type: %d not supported yet! (%s)' % (code,EnumToString(enum)[0]))

	f.close()

def FormatToCode(format): # {{{
	"""
	This routine takes the format string, and hardcodes it into an integer, which 
	is passed along the record, in order to identify the nature of the dataset being 
	sent.
	"""
	from MatlabFuncs import *

	if   strcmpi(format,'Boolean'):
		code=1
	elif strcmpi(format,'Integer'):
		code=2
	elif strcmpi(format,'Double'):
		code=3
	elif strcmpi(format,'String'):
		code=4
	elif strcmpi(format,'BooleanMat'):
		code=5
	elif strcmpi(format,'IntMat'):
		code=6
	elif strcmpi(format,'DoubleMat'):
		code=7
	elif strcmpi(format,'MatArray'):
		code=8
	elif strcmpi(format,'StringArray'):
		code=9
	else:
		raise InputError('FormatToCode error message: data type not supported yet!')

	return code
# }}}

if __name__ == '__main__':
	if 'PYTHONSTARTUP' in os.environ:
		PYTHONSTARTUP=os.environ['PYTHONSTARTUP']
		print 'PYTHONSTARTUP =',PYTHONSTARTUP
		if os.path.exists(PYTHONSTARTUP):
			try:
				execfile(PYTHONSTARTUP)
			except Exception as e:
				print "PYTHONSTARTUP error: ",e
		else:
			print "PYTHONSTARTUP file '%s' does not exist." % PYTHONSTARTUP

	import argparse
	parser = argparse.ArgumentParser(description='BinRead - function to read binary input file.')
	parser.add_argument('-f','--filin', help='name of binary input file', default='')
	args = parser.parse_args()

	BinRead(args.filin)

