"""
Tests for handling ivoa defined ucds and generation of NL expressions from 
them.
"""

import unittest

import ucdresolve
from ucdresolve import ivoawords
from ucdresolve import ucdmodel


class ValidationTests(unittest.TestCase):
	def setUp(self):
		self.words = ivoawords.getStandardWords()
	
	def testLegalUcds(self):
		for u in ["pos.eq.ra;arith.diff", "pos.eq.ra;meta.main", 
				"phot.mag;em.opt.V", "meta.code;src.var"]:
			self.assertEqual(self.words.validate(ucdmodel.UCD.fromUCDLiteral(u)),
				None)

	def testIllegalUcds(self):
		for u in ["fantasy.more.power.to", "pos.eq.ra;all.made.up", 
				"arith.diff", "arith.diff;pos.eq.ra"]:
			self.assertRaises(ucdresolve.InvalidUCD,
				self.words.validate, ucdmodel.UCD.fromUCDLiteral(u))


class NLGenerTest(unittest.TestCase):
	"""tests for correct generation of explanations from compound UCDs.
	"""
	def setUp(self):
		self.words = ivoawords.getStandardWords()
	
	def testSomeNL(self):
		"""tests for some natural language explanations for ucds.
		"""
		for u, expl in [
				("pos.eq.ra;meta.main", 'Main value of right ascension in'	
					' equatorial coordinates'),
				("phot.mag;em.opt.V", 'Photometric magnitude in the optical'
					' band between 500 and 600 nm'),
				("pos.pm;pos.eq.ra", 'Proper motion in right ascension in'	
					' equatorial coordinates'),
				("arith.factor;phot.mag;em.IR.H",
					"Numerical factor of photometric magnitude in the infrared"
						" between 1.5 and 2 micron"),
				("arith.rate;phys.atmol.collisional",
					"Rate (per time unit) related to collisions"),
				("arith.rate;phys.atmol.transition",
					"Rate (per time unit) of transition between states"),
				("em.freq;arith.ratio",
					"Ratio between two values of frequency value in the em frame"),
				("instr.bandwidth;stat.min",
					"Minimum or lowest limit of bandwidth of the instrument"),
				("meta.code.error;phot.color;em.opt.U",
					"Limit uncertainty error flag describing a color index"
					" or magnitude difference in the optical band between"
					" 300 and 400 nm"),
				("meta.code.error;pos.cartesian.y",
					"Limit uncertainty error flag describing a cartesian"
					" coordinate along the y-axis"),
				("meta.code.error;src.redshift",
					"Limit uncertainty error flag describing a redshift"),
				("meta.code.qual;spect.dopplerVeloc",
					"Quality, precision, reliability flag or code describing"
						" a radial velocity, derived from the shift of some"
						" spectral feature"),
				("meta.code;obs",
					"Code or flag describing an observation"),
				("meta.id.part;meta.main",
					"Main value of part of identifier, suffix or sub-component"),
				("meta.id;instr",
					"Identifier, name or designation of an instrument"),
				("meta.id;meta.dataset",
					"Identifier, name or designation of a dataset, archive"),
				("meta.id;meta.file",
					"Identifier, name or designation of a file"),
				("meta.id;meta.main",
					"Main value of identifier, name or designation"),
				("meta.id;obs",
					"Identifier, name or designation of an observation"),
				("meta.id;phys.atmol.transition",
					"Identifier, name or designation of transition between states"),
				("meta.id;spect.line",
					"Identifier, name or designation of a spectral line"),
				("meta.id;stat.fit",
					"Identifier, name or designation of a fit"),
				("meta.note;phot",
					"Note or remark (longer than a code or flag) on photometry"),
				("meta.number;phys.abund.Z",
					"Number (of things; e.g. nb of object in an image)"
						" of metallicity abundance"),
				("meta.ref;phys.abund.Y",
					"Reference, or origin of helium abundance"),
				("meta.ref;pos.frame",
					"Reference, or origin of reference frame used for "
						"positions (FK5, ICRS,..)"),
				("phot.color;em.IR.H;em.IR.K",
					"Color index or magnitude difference between infrared between"
					" 1.5 and 2 micron and infrared between 2 and 3 micron"),
				("phot.count;em.X-ray",
					"Flux expressed in counts in the x-ray part of the spectrum"),
				("phot.flux.density;em.IR.15-30um",
					"Flux density (per wl/freq/energy interval) in the infrared"
					" between 15 and 30 micron"),
				("phot.flux;arith.ratio",
					"Ratio between two values of photon flux"),
				("phot.flux;em.X-ray",
					"Photon flux in the x-ray part of the spectrum"),
				("phot.flux;em.X-ray.soft",
					"Photon flux in the soft X-ray (0.12 - 2 keV)"),
				("phot.mag.sb;em.opt.U",
					"Surface brightness in magnitude units in the optical"
					" band between 300 and 400 nm"),
				("phot.mag;arith.diff",
					"Difference between two values of photometric magnitude"),
				("phot.mag;arith.ratio",
					"Ratio between two values of photometric magnitude"),
				("phot.mag;em.opt",
					"Photometric magnitude in the optical part of the spectrum"),
				("phot.mag;em.opt.B",
					"Photometric magnitude in the optical band between 400 and 500 nm"),
				("phot.mag;stat.mean",
					"Mean, average value of photometric magnitude"),
				("phys.abund.Fe;stat.mean",
					"Mean, average value of fe/H abundance"),
				("phys.abund;em.wl.central",
					"Abundance of central wavelength"),  # WTF?
				("phys.angSize.smajAxis;src.orbital",
					"Angular size, extent or extension of semi-major axis"
					" of orbital parameters"),
				("phys.angSize;instr.beam",
					"Angular size, width, diameter, dimension, extension, major"
					" minor axis, extraction radius of beam"),
				("phys.angSize;instr.pixel",
					"Angular size, width, diameter, dimension, extension,"
					" major minor axis, extraction radius of pixel"
					" (default size: angular)"),
				("phys.angSize;src",
					"Angular size, width, diameter, dimension, extension, major minor"
					" axis, extraction radius of observed source viewed on the sky"),
				("phys.area;instr",
					"Area (in linear units) of instrument"),
				("phys.atmol.qn;phys.mol.rotation",
					"Molecular rotation of atomic/molecular quantum number"),
				("phys.atmol.qn;stat.min",
					"Minimum or lowest limit of atomic/molecular quantum number"),
				("phys.columnDensity;pos.galactic",
					"Column density of galactic coordinates"),  # BAD! -> in
				("phys.luminosity;arith.ratio",
					"Ratio between two values of luminosity"),
				("phys.luminosity;em.IR",
					"Luminosity of infrared part of the spectrum"),
				("phys.luminosity;em.X-ray",
					"Luminosity of x-ray part of the spectrum"),
				("phys.luminosity;em.opt.B",
					"Luminosity of optical band between 400 and 500 nm"),
				("phys.luminosity;em.radio",
					"Luminosity of radio part of the spectrum"),
				("phys.magAbs;em.opt",
					"Absolute magnitude of optical part of the spectrum"),
				("phys.magAbs;em.opt.B",
					"Absolute magnitude of optical band between 400 and 500 nm"),
				("phys.mass;arith.ratio",
					"Ratio between two values of mass"),
				("phys.transmission;instr.filter",
					"Transmission (of filter, instrument, ...) of filter"),
				("phys.veloc;pos.cartesian.x",
					"Space velocity of cartesian coordinate along the x-axis"), # in
				("phys.veloc;pos.heliocentric",
					"Space velocity of heliocentric position coordinate"	# in
					" (solar system bodies)"),
				("phys.veloc;pos.lg",
					"Space velocity of local Group reference frame"), # BAD -> in the
				("phys.veloc;pos.lsr", # BAD -> in the
					"Space velocity of local Standard of Rest reference frame"),
				("pos.angDistance;obs.field",
					"Angular distance, elongation in region covered by the observation"),
				("pos.cartesian.x;instr.det", # BETTER: "in the"
					"Cartesian coordinate along the x-axis in detector"),
				("pos.cartesian.x;stat.min",
					"Minimum or lowest limit of cartesian coordinate along the x-axis"),
				("pos.cartesian.y;instr.det",# BETTER: "of the"
					"Cartesian coordinate along the y-axis in detector"),
				("pos.cartesian;instr.det",
					"Cartesian (rectangular) coordinates in detector"),
				("pos.distance;pos.galactocentric",# BETTER: "in the"
					"Linear distance in galactocentric coordinate system"),
				("pos.distance;src.orbital",
					"Linear distance in orbital parameters"),
				("pos.eq.dec;arith.diff",
					"Difference between two values of declination in"
					" equatorial coordinates"),
				("pos.eq.dec;meta.main",
					"Main value of declination in equatorial coordinates"),
				("pos.pm;pos.eq.dec",
					"Proper motion in declination in equatorial coordinates"),
				("pos.posAng;phys.polarization",
					"Polarization degree (or percentage) of position angle of"
					" a given vector"),
				("pos.posAng;stat.mean",
					"Mean, average value of position angle of a given vector"),
				("pos;arith.diff",
					"Difference between two values of position and coordinates"),
				("spect.line.eqWidth;em.opt.I",
					"Line equivalent width in the optical band between 750 and 1000 nm"),
				("spect.line.intensity;arith.ratio",
					"Ratio between two values of line intensity"),
				("src.orbital.eccentricity;pos.galactic",
					"Orbit eccentricity in galactic coordinates"),
				("src.orbital.inclination;pos.ecliptic",
					"Orbit inclination in ecliptic coordinates"),
				("stat.error;phot.mag",
					"Statistical error of photometric magnitude"),
				("stat.error;phot.mag;em.opt.B",
					"Statistical error of photometric magnitude in the"
					" optical band between 400 and 500 nm"),
				("stat.error;phys.abund",
					"Statistical error of abundance"),
				("stat.error;phys.abund.Fe",
					"Statistical error of fe/H abundance"),
				("stat.error;phys.temperature.effective",
					"Statistical error of effective temperature"),
				("stat.error;stat.max",
					"Maximum or upper limit of statistical error"),
				("stat.error;time.age",
					"Statistical error of age"),
				("stat.stdev;instr.det.noise",
					"Standard deviation of instrument noise"),
				("time.duration;obs.exposure",
					"Interval of time describing the duration of exposure"),
				("time.epoch;pos.heliocentric", # Crazy UCD, should go away
					"Instant of time of heliocentric position coordinate"
					" (solar system bodies)"),
				("time.lifetime;phys.atmol.level",  # BAD: lifetime of atomic level
					"Atomic level of lifetime"),
				]:
			self.assertEqual(self.words.explain(ucdmodel.UCD.fromUCDLiteral(u)),	
				expl)


if __name__=="__main__":
	unittest.main()
