#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May 27 17:30:51 2019

@author: rfetick
"""

from paompy.utils import circarr, airy, RAD2ARCSEC

#%% INSTRUMENT CLASS AND ITS SUBCLASSES

class Instrument(object):
    """Represents an optical system
    
    Attributes
    ----------
    D : float
        Entrance aperture diameter [meter]
    occ : float
        Aperture occultation ratio
    resolution_rad : float
        Resolution [rad]
    filters : dict
        Dictionary of available filters as tuples (central wvl, width) [meter]
    Nact : int
        Linear number of AO actuators
    gainADU : float
        Detector gain [e-/ADU]
    RON : float
        Detector read out noise [e-]
    binning : int
        Pixel binning factor (default=1)
    """

    def __init__(self,D=None,occ=0.,res=None,Nact=0,gain=1.,ron=0.):
        
        if D is None:
            raise ValueError("Please enter keyword `D` to set Instrument's aperture diameter")
        if res is None:
            raise ValueError("Please enter keyword `res` to set instrument resolution in rad")
        
        if D <= 0:
            raise ValueError("Keyword `D` must be strictly positive")
        if res <= 0:
            raise ValueError("Keyword `res` must be strictly positive")
        
        self.D = D
        self.occ = occ # occultation ratio
        self.filters = {}
        self.Nact = Nact
        
        self._resolution_rad = res
        self.gain = gain
        self.ron = ron
        self.binning = 1
        
        self.name = "(unamed)"
        
    def __repr__(self):
        s  = "PAOMPY Instrument\n"
        s += "----------------------------\n" 
        s += "Diameter   : %.2f m (occ=%u%%)\n" % (self.D,self.occ*100)
        s += "Resolution : %.2f mas (binning=%u)\n" % (self.resolution_mas,self.binning)
        s += "Nact       : %u\n" % self.Nact
        K = tuple(self.filters.keys())
        s += "Filters    : " # %u" % len(self.filters)
        for k in K:
            s += "%s " % k
        s += "\n"
        s += "Detector   : (gain=%.1f e-/ADU) (RON=%.1f e-)"%(self.gain,self.ron)
        return s
    
    @property
    def resolution_rad(self):
        return self._resolution_rad * self.binning
    
    @property
    def resolution_mas(self):
        return self.resolution_rad * RAD2ARCSEC * 1e3
    
    def pupil(self,Npix,wvl=None,samp=None):
        """Returns the 2D array of the pupil transmission function"""
        Dpix = min(Npix)/2
        pup = circarr(Npix)
        return (pup < Dpix) * (pup >= Dpix*self.occ)
    
    def samp(self,wvl):
        """Returns sampling value for the given wavelength"""
        return wvl/(self.resolution_rad*self.D)
    
    def wvl(self,samp):
        """Returns wavelength for the given sampling"""
        return samp*(self.resolution_rad*self.D)
    
    
    def PSFdl(self,Npix,wvl):
        """Returns the diffraction limited PSF
        
        Parameters
        ----------
        Npix : tuple, list of 2 elements
            Size of the output 2D array
        wvl : float
            Observation wavelength
        """
        return airy(Npix,self.samp(wvl),self.occ)





ZIMPOL = Instrument(D=8.,occ=0.14,res=30*1e-6/1768.,gain=10.5,ron=20.,Nact=40)
ZIMPOL.filters["V"] = (554*1e-9, 80.6*1e-9)
ZIMPOL.filters["N_R"] = (645.9*1e-9, 56.7*1e-9)
ZIMPOL.name = "VLT SPHERE/ZIMPOL"


MUSE = Instrument(D=8.,occ=0.14,res=237.15*1e-6/1980.,gain=5.,ron=15.,Nact=39)
MUSE.name = "VLT MUSE"