"""
Code dealing with product (i.e., fits file) delivery.
"""

#c Copyright 2008-2024, 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.


import base64

from twisted.web import resource
from twisted.web import server

from gavo import base
from gavo import utils
from gavo.protocols import products
from gavo.web import grend
from gavo.web import producttar
from gavo.web import weberrors


class MissingPreview(resource.Resource):
	"""A twisted resource returning a 404 image.
	"""
	noPreviewImg = base64.b64decode(
		'iVBORw0KGgoAAAANSUhEUgAAAMgAAABkAgMAAAC+6JeYAAAADFBMV'
		'EUQEg9OUE2Qko/8//texVsLAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAA'
		'Ad0SU1FB+QIDAwjFnjAPBkAAAK0SURBVFjD7dQ/aBNRHAfwbh0ydCoiBzlUcEpz4CBC/zzo0'
		'EVQqKOgg0MRioKDZLiagmKHgsF20amUCiJCtVAhyl0eWNpAb2jTGwp1ae8NRRya97zAS3t3P'
		'393bcy1TaEddOlluPfL5T653yXv+2uDM7/aEpKQhCQkIQk5f6Su/D0RkLWA4FprXiNaEWeyS'
		'bTvfh5X3nifb02s2BnthUdjxCetSRncxxtP3/rhteobz1TAv+Qr4E3DgEyBGKsrUz8qFF7TJ'
		'qnQdWtxbtgI69vDRc6A85oATx/RTQLVuT1WWEkTKJEmkalxe6Hq5cK60POFCXC44yLJmb0EO'
		'TjWK6Lhc8Z+ZLvAyjy4HpbLvU+2BpEwCZ6RC5AIHkys3+vU4GeciAKzBFwOy6Vn1xgAO0SEw'
		'7LYVDZGdsS4jeRO9FylKw5+R9SYETUmOHOcPuyrL0aWnpfHkYztYr1J2/ku8C3uINFzpe6Qr'
		'1WJ+inoihFXdTUklot1FW76KfCv4sEz8/2ggKjJIUlXKbzMH9tjK2ffllNnJjKfBPnfE20/u'
		'h3R4tEonbXTEBkdtw8IBnq7MQRObMzdT1AEImI3hkCcbKgbIxhvWvlar8MmGfDfw6gxHQTtO'
		'APqymhpQKqVYurwuBhbnMN4a+kb1Rq4vm7cxbtk9OIehniP2YFkO+new3ex7AUmrEKWZOYFu'
		'NLsIUh0vYgTDnNvg5wJSNcRwspbg+v3s52ZDzNIgp48EkM3FCTBhA3vPj/qPEYsBkzLEv/hg'
		'4jQiNBJnAHCsb1i6RbxjzZmOeCQrBakL0SNHRAR5d6Wki5rRwgmn+9WiabOdqTA9XIGBWYY+'
		'rffOAOcNVac/7iiznb/ipNFzfJTkmqrVO2AOvTjf8INUzfDGSCHeOmiix8p9klj/JR77P+QJ'
		'MgJSUhCEnJ+yB+3JLSzGAuzmQAAAABJRU5ErkJggg==')

	def render(self, request):
		request.setResponseCode(404)
		request.setHeader("content-type", "image/png")
		request.write(self.noPreviewImg)
		request.finish()

_MISSING_PREVIEW = MissingPreview()


class ProductRenderer(grend.ServiceBasedPage):
	"""The renderer used for delivering products.

	This will only work with a ProductCore since the resulting
	data set has to contain products.Resources.  Thus, you probably
	will not use this in user RDs.
	"""
	name = "get"
	pathFromSegments = ""

	def render(self, request):
		if len(request.strargs.get("accref", []))>1:
			# more than one accref passed in: produce a tar
			assert not self.pathFromSegments
			data = request.strargs
		else:
			data = {"accref":
					products.RAccref.fromRequest(self.pathFromSegments, request)}

		self.runAsyncWithFormalData(data, request
			).addCallback(self._deliver, request
			).addErrback(weberrors.renderDCErrorPage, request)
		return server.NOT_DONE_YET
	
	def _deliver(self, result, request):
		if len(result)>1:
			# TODO: presumably we should have the option of producing
			# tars with 0 and 1 item(s); we should probably have
			# a special renderer for that.
			return producttar.getTarMaker()._streamOutTar(
				result, request, self.queryMeta, "products.tar")

		else:
			return self._deliverSingle(result, request)

	def _deliverSingle(self, result, request):
		doPreview = self.queryMeta.ctxArgs.get("preview")
		product = result[0]

		# This catches cases where people want previews of processed
		# products (in particular cutouts).  I doubt this is a good
		# idea, but getting out of this hack again is hard.
		try:
			if doPreview and not "Preview" in product.__class__.__name__:
				return products.PreviewCacheManager.getPreviewFor(product
					).addCallback(self._deliverPreview, product, request
					).addErrback(self._deliverPreviewFailure, request)
		except base.DataError:
			return _MISSING_PREVIEW.render(request)

		else:
			if hasattr(product, "render"):
				res = product.render(request)
				if res not in (None, b"", server.NOT_DONE_YET):
					base.ui.notifyError("Product.render returned nonempty result"
						" %s. This is no longer supported, and the client won't see it."%
						utils.makeEllipsis(repr(res)))
			else:
				base.ui.notifyWarning("Non-product result in product renderer:"
					" %s"%repr(product))
				from gavo.svcs import streaming
				return streaming.streamOut(lambda w, q: w.write(product), request)

	def _deliverPreview(self, content, product, request):
		previewMime = product.pr["preview_mime"] or "image/jpeg"
		request.setHeader("content-type", str(previewMime))
		request.setHeader("content-length", str(len(content)))
		request.write(content)
		request.finish()
	
	def _deliverPreviewFailure(self, failure, request):
		failure.printTraceback()
		data = b"Not an image (preview generation failed, please report)"
		request.setResponseCode(500)
		request.setHeader("content-type", "text/plain")
		request.setHeader("content-length", str(len(data)))
		request.write(data)
		request.finish()

	def getChild(self, name, request):
		self.pathFromSegments = "/".join(request.popSegments(name))
		return self
