"""
Helper functions for biblinks management.

You will usually use these from within an postCreation (or perhaps afterMeta,
if you would like to update them independently of the content) script.
"""

#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 import base
from gavo import rsc
from gavo import svcs


# use this to prefix ivoids in dataset-ref-s
IVO_SCHEMA_RESOLVER = "http://reg.g-vo.org/LP/"


def defineLinks(connection, rd, links, bibFormat=None, linkSource=None):
	"""Inserts links into the system's bibliography links table.

	It does this through connection (which must be a writable admin connection);
	rd is the RD of the table managing the datasets in question (or the
	RD of the service pointed to), bibFormat can be "doi" if the bibliographic
	identifiers are not bibcodes, and linkSource is a user-controlled
	string to be used with incremental imports.

	links, finally, is a sequence of triples::

		(bib-ref, relationship, dataset-ref)
	
	or quadruples::

		(bib-ref, relationship, biblinks-service-ref, nlinks)
	
	See the reference documentation for what to put where.  Note that
	dataset-ref-s with an ivo schema will be mangled to point to a landing
	page.
	"""
	sourceRD = rd.sourceId

	links_table = rsc.TableForDef(
		base.resolveCrossId("//biblinks#biblinks"), connection=connection)
	feeder = links_table.getFeeder()

	with feeder:
		for linkDef in links:
			
			if len(linkDef)==3:
				bibRef, relationship, datasetRef = linkDef
				nlinks = None
			elif len(linkDef)==4:
				bibRef, relationship, datasetRef, nlinks = linkDef
			else:
				raise TypeError(f"Uninterpretable link def: {linkDef}")

			# change ivoids to a landing page.
			if datasetRef.startswith("ivo://"):
				datasetRef = IVO_SCHEMA_RESOLVER+datasetRef[6:]

			feeder.add({
				"bib_ref": bibRef,
				"relationship": relationship,
				"dataset_ref": datasetRef,
				"bib_format": bibFormat,
				"sourcerd": sourceRD,
				"link_source": linkSource,
				"cardinality": nlinks})


def clearLinks(connection, rd, linkSource=None):
	"""drops bibliography links from the system biblink table.

	connection, rd, and linkSource are as in defineLinks.

	This function should usually be called first in scripts defining
	bibliography links to clear the results of any previous import.
	"""
	sourceRD = rd.sourceId
	query = "DELETE FROM {} WHERE sourcerd=%(sourceRD)s".format(
		base.resolveCrossId("//biblinks#biblinks").getQName())
	if linkSource is not None:
		query += " AND link_source=%(linkSource)s"

	connection.execute(query, locals())


class BiblinksCore(svcs.Core):
	"""A core retrieving biblinks-harvest records from dc.biblinks.

	Probably is only place in which this makes sense is in //biblinks#links;
	consider making this a pythonCore there.

	(since 2.8.2)
	"""
	name_ = "biblinksCore"

	def __init__(self, parent, **kwargs):
		kwargs["inputTable"] = base.makeStruct(svcs.InputTD)
		kwargs["outputTable"] = svcs.OutputTableDef.fromTableDef(
			base.resolveCrossId("//biblinks#core-output"))
		super().__init__(parent, **kwargs)

	def run(self, service, inputData, queryMeta):
		with base.getTableConn() as conn:
			return rsc.TableForDef(self.outputTable,
				rows=list(conn.queryToDicts("select * from dc.biblinks")))
