"""
BINARY2 VOTable decoding

BINARY2 is like BINARY, except every record is preceded by a mask which
columns are NULL.

Sorry for gratuituously peeking into the guts of dec_binary here.  But well,
it's family.
"""

#c Copyright 2008-2025, the GAVO project <gavo@ari.uni-heidelberg.de>
#c
#c This program is free software, covered by the GNU GPL.  See the
#c COPYING file in the source distribution.


from gavo.votable import coding      #noflake: used by generated code
from gavo.votable import common
from gavo.votable import dec_binary
from gavo.votable.model import VOTable

from gavo.utils.dachstypes import Any, Dict


def getRowDecoderSource(tableDefinition: VOTable.TABLE) -> str:
	"""returns the source for a function deserializing a BINARY stream.

	tableDefinition is a VOTable.TABLE instance.  The function returned
	expects a file-like object.
	"""
	source = [
		"def codec(inF):",
		"  row = []",
		"  try:",
		"    nullMap = nullFlags.getFromFile(inF)",
		"  except IOError:",  # EOF while reading null map: correct end of stream.
		"    return None",
		]

	for index, field in enumerate(
			tableDefinition.iterChildrenOfType(VOTable.FIELD)):
		source.extend([
			"  try:",]+
			common.indentList(getLinesFor(field), "    ")+[
			"  except common.VOTableError:",
			"    raise",
			"  except:",
#			"    raise",
			"    raise common.BadVOTableLiteral('%s', repr(inF.lastRes), name=%r)"%(
				field.datatype, field.name),
			])

	source.extend([
		"  for index, isNull in enumerate(nullMap):",
		"    if isNull:",
		"      row[index] = None",
		"  return row"])
	return "\n".join(source)


def getGlobals(tableDefinition: VOTable.TABLE) -> Dict[str, Any]:
	vars = dict((n, getattr(dec_binary, n)) for n in dir(dec_binary))
	vars["nullFlags"] = common.NULLFlags(len(tableDefinition.getFields()))
	return vars


getLinesFor = dec_binary.getLinesFor
