import datetime
import os
import re
import shutil

from gavo import api
from gavo.utils import fitstools
from gavo.utils import pyfits

# some exposures have tracks; we don't want to try to calibrate
# those
TRACK_IMGS = set(["ESO040_013819.fits", "ESO040_013801.fits", "ESO040_013793.fits"])

def parseExposureTimes(srcPath):
# we have to add the exposure times of for multi-exp plates manually.
# we got those from Milcho in the WFPDB notes (in a funky format)
# The result is a mapping from plateno to (hour, minute) pairs in UT.
		expTimes = {}
		with open(srcPath) as f:
			for ln in f:
				plateno = ln[7:14].lstrip("0")
				mat = re.search(r"EXP1[_-](\d).*=(.*);", ln)
				if not mat:
					print ln
				if mat.group(1)=="1":
					# direct exposure, don't bother
					continue
				else:
					expTimes[plateno.strip()] = [
						tuple(
							tuple(int(v) for v in t.split(":"))
							for t in interval.split("-"))
						for interval in mat.group(2).split(",")]
		return expTimes


class Calibrator(api.AnetHeaderProcessor):
	sp_indices = ["index-211.fits", "index-210.fits",
		"index-209.fits", "index-208.fits", "index-207"]
	sp_total_timelimit = 40
	sp_endob = 50

	sexControl = """DETECT_THRESH  4
		SEEING_FWHM      1.2
		WEIGHT_TYPE BACKGROUND
		BACK_SIZE 40
		BACK_FILTERSIZE 3x3
		DETECT_TYPE CCD
		MEMORY_PIXSTACK 8000000
		MEMORY_OBJSTACK 8000
		MEMORY_BUFSIZE 2048
		"""

	def objectFilter(self, inName):
		"""throws out funny-looking objects from inName and throws out objects
		near the border.
 		"""
		shutil.copy(inName, "origData.fits")
		hdulist = pyfits.open(inName)
		data = hdulist[1].data
		width = max(data.field("X_IMAGE")) # XXX TODO: get from image
		height = max(data.field("Y_IMAGE"))

		data = data[data.field("ELONGATION")<1.5]

		badBorder = 0.05
		data = data[data.field("X_IMAGE")>width*badBorder]
		data = data[data.field("X_IMAGE")<width-width*badBorder]
		data = data[data.field("Y_IMAGE")>height*badBorder]
		data = data[data.field("Y_IMAGE")<height-height*badBorder]
		hdu = pyfits.BinTableHDU(data)
		hdu.writeto("foo.xyls")
		hdulist.close()
		os.rename("foo.xyls", inName)

	def _createAuxiliaries(self, dd):
		self.expTimes = parseExposureTimes(
			os.path.join(dd.rd.resdir,
				"data", "metadata", "ESO040notes.txt"))

	def classify(self, srcName, hdr=None):
		if hdr is None:
			with open(srcName) as f:
				hdr = fitstools.readPrimaryHeaderQuick(f)

		
		if hdr["MULTIEXP"]>1 or srcName.split("/")[-1] in TRACK_IMGS:
			return "not calibratable"
		if "CD1_1" in hdr:
			return "calibrated"
		return "uncalibrated"

	def _shouldRunAnet(self, srcName, hdr):
		return self.classify(srcName, hdr=hdr)!="not calibratable"

	def _mungeHeader(self, srcName, origHeader):
		# X/YPIXELSZ are fatal for wcslib.  use newer Taavi convention
		if "XPIXELSZ" in origHeader:
			origHeader["PIXELSZ1"] = origHeader.pop("XPIXELSZ")
		if "YPIXELSZ" in origHeader:
			origHeader["PIXELSZ2"] = origHeader.pop("YPIXELSZ")

		# CUNITn was a bad mistake in first Taavi convention
		if "CUNIT1" in origHeader:
			origHeader["FOV1"] = origHeader.pop("CUNIT1")
		if "CUNIT2" in origHeader:
			origHeader["FOV2"] = origHeader.pop("CUNIT2")

		platenum = origHeader["PLATENUM"].lstrip("0")
		if platenum in self.expTimes:
			baseDate = api.parseISODT(origHeader["DATE-OBS"])
			# ASSUMPTION: no observations across midnight UT
			for index, ((hr0, min0), (hr1, min1)
					) in enumerate(self.expTimes[platenum]):
				obsno = index+1
				obsStart = datetime.datetime.combine(
					baseDate, datetime.time(hr0, min0))
				obsEnd = datetime.datetime.combine(
					baseDate, datetime.time(hr1, min1))
				obsTime = (obsEnd-obsStart)
				origHeader["DT-OBS%s"%obsno] = api.formatISODT(obsStart)
				origHeader["DT-AVG%s"%obsno] = api.formatISODT(obsStart+obsTime/2)
				origHeader["DT-END%s"%obsno] = api.formatISODT(obsEnd)
				origHeader["EXPTIM%s"%obsno] = obsTime.total_seconds()
		return origHeader
	
if __name__=="__main__":
	api.procmain(Calibrator, "flare_survey/q.rd", "import")
