"""
The grammar to parse sp_ace's output.

This output is essentially a key-value list turned sideways, so you
have a single table row.  We want to turn the actual metadata from that into
the doc row, whereas all the elements become a table.

There are a few single values, but normally all values are furnished with
inf and sup.
"""

import re

from gavo import base
from gavo.grammars.customgrammar import CustomRowIterator


class RowIterator(CustomRowIterator):
	def _parseTriple(self, mainLabel, pairsIter, destDict):
		"""enters a triple (val, inf, sup) for mainLabel into destDict.

		There's an extra hack: since the column captions contain relevant
		information (the element name), we return the caption of the main column.
		"""
		sourceLabel, val = next(pairsIter)
		destDict[mainLabel] = val

		label, val = next(pairsIter)
		if not label.endswith("_l"):
			raise base.SourceParseError(
				"Expected label ending with _l, found %s"%label, offending=label)
		destDict[mainLabel+"_low"] = val

		label, val = next(pairsIter)
		assert label.endswith("_h")
		destDict[mainLabel+"_up"] = val

		return sourceLabel

	def _getParsedInput(self):
		"""returns a pair of (document row, rows) for Corrados crazy format.
		"""
		with open(self.sourceToken) as f:
			lines = [l for l in f if l.strip()]
		assert len(lines)==2

		pairs = iter(zip(lines[0].split(), lines[1].split()))

		# first there are five singletons (conv, rv, fwhm, s/n, chisq)
		docRow = {}
		for i in range(5):
			label, value = next(pairs)
			docRow[label] = value
		
		# then three metadata items also intended for the docrow
		self._parseTriple("teff", pairs, docRow)
		self._parseTriple("logg", pairs, docRow)
		self._parseTriple("metals", pairs, docRow)
		
		rows = []
		# for the rows (abundances), just iterate until we've exhausted our input
		while True:
			row = {}
			try:
				caption = self._parseTriple("ab", pairs, row)
				row["element"] = caption

				# Additional hack: with "alpha" set, you only get back "m"
				# and "a", which really means...
				if row["element"]=="a":
					row["element"] = "Alpha elements"
				elif row["element"]=="m":
					row["element"] = "Non-alpha metals"
				row["nlines"] = next(pairs)[1]
			except StopIteration:
				# we will accept malformed input this way as we don't
				# care whether we've already started parsing a triple;
				# as this is program output, I'm not terribly concerned.
				break
			rows.append(row)

		return docRow, rows
				
	def getParameters(self):
		docRow, _ = self._getParsedInput()
		return docRow
		
	def _iterRows(self):
		_, rows = self._getParsedInput()
		return iter(rows)


if __name__=="__main__":
	# for checking out what the grammar actually spits out, call it
	# stand-alone
	class fakegrammar:
		ignoreOn = None

	ri = RowIterator(fakegrammar, "test_data/response_scaffold.dat")
	print(ri.getParameters())
	print(list(ri))
