"""
This script queries a registry using a RegTAP endpoint to retrieve
VOResource records of TAP services and synchronizes the list of them
with the services table within the glots schema.
"""

import datetime
import os

from gavo import api
from gavo import base
from gavo import votable
from gavo.utils import StartEndHandler
from gavo.votable import tapquery


RDID = "glots/q"
RD = api.getRD(RDID)

TAP_REGISTRY_ENDPOINT = "http://dc.g-vo.org/tap"
TAP_PROTOCOL_ID = "ivo://ivoa.net/std/tap"


def getTAPServices():
	"""returns pairs of ivoid, accessurl for registred TAP services
	"""
	# the GROUP BY/MIN(access_url) hack is to cope with services giving
	# multiple TAP capabilities; for now, these are generally misguided,
	# and I'm fine with using any access URL, preferably a constant one.
	job = tapquery.ADQLSyncJob(TAP_REGISTRY_ENDPOINT,
		"SELECT ivoid, MIN(access_url)"
  	"  FROM rr.capability"
    "  NATURAL JOIN rr.interface"
  	" WHERE standard_id='%s'"
  	"   AND intf_type='vs:paramhttp'"
  	" GROUP BY ivoid"%TAP_PROTOCOL_ID)
	job.run()
	data, metadata = votable.load(job.openResult())

	# HACK: cope with people wantonly appending ? to their accessURLs
	for row in data:
		row[1] = row[1].rstrip('?')

	return data


def updateServices(currentServices):
	"""updates the service table in the glots schema from the (ivoid, accessurl)
	pairs in currentServices.

	This comprises inserting records so far unknown and removing those
	no longer available.
	"""
	newServices = []
	serviceTD = RD.getById("services")
	with api.getWritableAdminConn() as conn:
		serviceTable = api.TableForDef(serviceTD, connection=conn)
		knownIds = dict((r["ivoid"], r["accessurl"])
			for r in serviceTable.iterQuery([
				serviceTD.getColumnByName("ivoid"),
				serviceTD.getColumnByName("accessurl")], ""))

		# Ingest new services
		for id, accessURL in currentServices:
			if id in knownIds:
				# update accessURL if it's changed.
				if knownIds[id]!=accessURL:
					conn.execute("UPDATE glots.services SET accessurl=%(accessurl)s,"
						" nextharvest=%(nextharvest)s"
						" WHERE ivoid=%(ivoid)s", {
							"accessurl": accessURL,
							"nextharvest": datetime.datetime.utcnow(),
							"ivoid": id})
				del knownIds[id]

			else:
				serviceTable.addRow({
					"ivoid": id,
					"accessurl": accessURL,
					"nextharvest": datetime.datetime.utcnow(),
					"lastsuccess": None,
					"harvestinterval": 30})
				newServices.append(id)

		# All that's left in knownIds now are services no longer registred.
		# We remove them, and by foreign key constraints, all data for them should
		# vanish, too.
		for id in knownIds:
			serviceTable.connection.execute(
				"DELETE FROM glots.services WHERE ivoid=%(ivoid)s",
				{"ivoid": id})
		
		return newServices


if __name__=="__main__":
	from gavo.user import logui
	logui.LoggingUI(base.ui)
	newServices = updateServices(
		getTAPServices())
