import galsim
import numpy as np

class FocalPlane(object):
    def __init__(self, config=None, survey_type='Photometric', bad_chips=None):
        """Get the focal plane layout
        Note: (If applicable) make sure the config file have the most basic info, e.g.: "nchip_x"...
        """
        if bad_chips == None:
            self.bad_chips = []
        else:
            self.bad_chips = bad_chips
        
        self.ignore_chips = []
        if survey_type == 'Photometric':
            # for i in range(6):
            #     self.ignore_chips.append(i+1)
            #     self.ignore_chips.append(i+25)
            for i in range(5):
                self.ignore_chips.append(i+1)
                self.ignore_chips.append(i+26)
            self.ignore_chips.append(10)
            self.ignore_chips.append(21)
        elif survey_type == 'Spectroscopic':
            # for i in range(18):
            #     self.ignore_chips.append(i+7)
            for i in range(6, 26):
                if i == 10 or i == 21:
                    continue
                else:
                    self.ignore_chips.append(i)

        if config is not None:
            self.nchip_x    = config["nchip_x"]
            self.nchip_y    = config["nchip_y"]
            self.npix_tot_x = config["npix_tot_x"]
            self.npix_tot_y = config["npix_tot_y"]
            self.npix_gap_x = config["npix_gap_x"]
            self.npix_gap_y = config["npix_gap_y"]
            if "chipLabelIDs" in config:
                self.chipLabelIDs = config["chipLabelIDs"]
            if "bad_chips" in config:
                self.bad_chips = config["bad_chips"]
        else:
            # self.nchip_x = 5
            # self.nchip_y = 6
            # self.npix_tot_x = 49752
            # self.npix_tot_y = 59516
            # self.npix_gap_x = 898
            # self.npix_gap_y = (534, 1309)
            self.nchip_x = 6
            self.nchip_y = 5
            self.npix_tot_x = 59516
            self.npix_tot_y = 49752
            self.npix_gap_x = (534, 1309)
            self.npix_gap_y = 898
        
        self._getCenter()

    def _getCenter(self):
        # self.cen_pix_x = 0.5 * (self.npix_tot_x + 1.0)
        # self.cen_pix_y = 0.5 * (self.npix_tot_y + 1.0)
        self.cen_pix_x = 0
        self.cen_pix_y = 0

    def getChipLabel(self, chipID):
        return str("0%d"%chipID)[-2:]

    def isBadChip(self, chipID):
        """Check if chip #(chipID) on the focal plane is bad or not
        """
        return (chipID in self.bad_chips)

    def isIgnored(self, chipID):
        return (chipID in self.ignore_chips)

    def getTanWCS(self, ra, dec, img_rot, pix_scale, xcen=None, ycen=None, logger=None):
        """ Get the WCS of the image mosaic using Gnomonic/TAN projection

        Parameter:
            ra, dec:    float
                        (RA, Dec) of pointing of optical axis
            img_rot:    galsim Angle object
                        Rotation of image
            pix_scale:  float
                        Pixel size in unit of as/pix
        Returns:
            WCS of the focal plane
        """
        if logger is not None:
            logger.info("    Construct the wcs of the entire image mosaic using Gnomonic/TAN projection")
        if (xcen == None) or (ycen == None):
            xcen = self.cen_pix_x
            ycen = self.cen_pix_y
        dudx =  -np.cos(img_rot.rad) * pix_scale
        dudy =  -np.sin(img_rot.rad) * pix_scale
        dvdx =  -np.sin(img_rot.rad) * pix_scale
        dvdy =  +np.cos(img_rot.rad) * pix_scale
        
        # dudx =  +np.sin(img_rot.rad) * pix_scale
        # dudy =  +np.cos(img_rot.rad) * pix_scale
        # dvdx =  -np.cos(img_rot.rad) * pix_scale
        # dvdy =  +np.sin(img_rot.rad) * pix_scale
        moscen = galsim.PositionD(x=xcen, y=ycen)
        sky_center = galsim.CelestialCoord(ra=ra*galsim.degrees, dec=dec*galsim.degrees)
        affine = galsim.AffineTransform(dudx, dudy, dvdx, dvdy, origin=moscen)
        WCS = galsim.TanWCS(affine, sky_center, units=galsim.arcsec)

        return WCS

    def getSkyCoverage(self, wcs, x0, x1, y0, y1):
        """
        The sky coverage of an area
        """
        r2d = 180.0/np.pi
        s1 = wcs.toWorld(galsim.PositionD(x0,y0))
        s2 = wcs.toWorld(galsim.PositionD(x0,y1))
        s3 = wcs.toWorld(galsim.PositionD(x1,y0))
        s4 = wcs.toWorld(galsim.PositionD(x1,y1))
        ra = [s1.ra.rad*r2d, s2.ra.rad*r2d, s3.ra.rad*r2d, s4.ra.rad*r2d]
        dec = [s1.dec.rad*r2d, s2.dec.rad*r2d, s3.dec.rad*r2d, s4.dec.rad*r2d]

        return galsim.BoundsD(min(ra), max(ra), min(dec), max(dec))
