# 
# LSST Data Management System
# Copyright 2008, 2009, 2010 LSST Corporation.
# 
# This product includes software developed by the
# LSST Project (http://www.lsst.org/).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the LSST License Statement and 
# the GNU General Public License along with this program.  If not, 
# see <http://www.lsstcorp.org/LegalNotices/>.
#

"""
Utilities to manipulate CFHT data
"""
import sys

from lsst.pex.policy import Policy
import lsst.afw.image as afwImage
import lsst.afw.detection as afwDetection
import lsst.afw.detection.utils as afwDetectionUtils

import lsst.afw.display.ds9 as ds9

class CcdInfo(object):
    """Information about the layout of a CCD"""
    
    def __init__(self):
        self.nCcd = 0                   # Number of CCDs (0-indexed)
        self.nAmp = 0                   # Number of amplifiers (0-indexed)
        self.ampBBox = {}               # BBox for usable pixels for given amplifier; whole-CCD trimmed coords
        self.trimSecBBox = {}           # BBox for usable pixels for given amplifier; whole-CCD UN-trimmed coords

    def ccdList(self):
        """Return a list of all the CCDs"""
        return range(0, self.nCcd)
        
    def ampList(self):
        """Return a list of all the amplifiers"""
        return range(0, self.nAmp)
        
    def getAmpBBox(self, amp):
        """Return the given amplifier's BBox in the whole-CCD coordinate system (i.e. post trimming)"""

        return self.ampBBox[amp].clone()

    def getTrimSecBBox(self, amp):
        """Return the given amplifier's good-data BBox in the raw whole-CCD coordinate system (i.e. pre trimming)"""

        return self.trimSecBBox[amp].clone()

#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

class CfhtCcdInfo(CcdInfo):
    """Information about the layout of a CFHT CCD"""
    
    def __init__(self, ampPolicy="cfhtAmpBBoxPolicy.paf"):
        CcdInfo.__init__(self)          # Is this the best way to do this?
        
        self.nCcd = 36                  # Number of CCDs (0-indexed)
        self.nAmp = 8                   # Number of amplifiers (0-indexed)

        ampBBoxDb = Policy(ampPolicy)

        for amp in self.ampList():
            p = ampBBoxDb.get("CcdBBox.Amp%d" % amp)
            self.ampBBox[amp] = afwGeom.Box2I(afwGeom.Point2I(p.get("x0"), p.get("y0")),
                                              afwGeom.Extent2I(p.get("width"), p.get("height")))
            
        for amp in self.ampList():      # Build by hand
            bbox = self.getAmpBBox(amp)
            bbox.shift(32, 0)           # Allow for overclock
        
            self.trimSecBBox[amp] = bbox

    def writeDefects(self, maskFile, ccd, format=None):
        """Given a Mask, find the defects for each amp in the specified CCD (0-indexed).
        If format is provided, it's expected to be used as "format % (ccd, amp)" to generate
        a .paf filename to write the defects too.  If it's "-", write to stdout"""

        # Metadata should have validity range keywords, but it doesn't.
        if False:
            metaData = afwImage.readMetadata(maskFile, 0)

        hdu = ccd + 2
        im = afwImage.ImageF(maskFile, hdu)
        im -= 1
        im *= -1
        mask = afwImage.MaskU(im.getBBox(afwImage.PARENT)); mask.set(0x0)
        mask = afwImage.makeMaskedImage(im, mask)

        for amp in self.ampList():
            subMask = mask.Factory(mask, self.getTrimSecBBox(amp), afwImage.LOCAL)

            ds = afwDetection.makeFootprintSet(subMask, afwDetection.Threshold(0.5), "INTRP")

            if False:
                ds9.setDefaultFrame(amp)
                
                ds9.mtv(subMask)
                ds9.dot("Amp %d" % amp, 0, 0)

            if not format:
                return

            if format == "-":
                fd = sys.stdout
            else:
                fd = open(format % (ccd, amp), "w")

            print >> fd, """\
#<?cfg paf policy ?>
#
# Defects for CCD%03d amp %02d generated from %s, HDU %d
#
# Coordinates are trimmed and per-amp not per-CCD.  If you change this, the ISR will have to change
#
# Generated by $HeadURL$
#
""" % (ccd, amp, maskFile, hdu),
                          
            for foot in ds.getFootprints():
                afwDetectionUtils.writeFootprintAsDefects(fd, foot)
