module ram_sizes
  integer(kind=8), parameter :: bytes_per_real = 4
  integer(kind=8), parameter :: kB = 1024
  integer(kind=8), parameter :: MB = 1024**2
  integer(kind=8), parameter :: GB = 1024**3
end module ram_sizes
!
module imbfits_parameters
  !
  real(kind=4), parameter :: bad=-1000.e0
  real(kind=8), parameter :: bad8=-1000.d0
  !
  integer(kind=4), parameter :: code_imbfits_init = 0
  integer(kind=4), parameter :: code_imbfits_started = 1
  integer(kind=4), parameter :: code_imbfits_done = 2
  real(kind=4), parameter :: imbfits_version_min=1.1999  ! Min supported (included)
  real(kind=4), parameter :: imbfits_version_max=3.      ! Max supported (excluded)
  !
  integer(kind=4), parameter :: mhdukinds=8
  integer(kind=4), parameter :: hdu_scan=1           ! HDU Scan identifier
  integer(kind=4), parameter :: hdu_frontend=2       ! HDU Frontend identifier
  integer(kind=4), parameter :: hdu_backend=3        ! HDU Backend identifier
  integer(kind=4), parameter :: hdu_backdata=4       ! HDU BackEndXXX identifier
  integer(kind=4), parameter :: hdu_antslow=5        ! HDU AntennaSlow identifier
  integer(kind=4), parameter :: hdu_antfast=6        ! HDU AntennaFast identifier
  integer(kind=4), parameter :: hdu_subreflector=7   ! HDU Subreflector identifier
  integer(kind=4), parameter :: hdu_derot=8          ! HDU Derotator identifier
  !
end module imbfits_parameters
!
module imbfits_types
  use gildas_def
  use cfitsio_api
  use gkernel_types
  use eclass_types
  use imbfits_parameters
  !
  ! File description
  type imbfits_file_t
     integer(kind=4) :: status = code_imbfits_init
     integer(kind=4) :: unit = 0
     integer(kind=4) :: block = 0
     integer(kind=4) :: rwstatus = code_cfitsio_readonly
     character(len=filename_length) :: name = ''
     logical :: isholography = .false.  ! Is this an holography?
     logical :: isarray = .false.  ! Was a multipixel array used?
  end type imbfits_file_t
  !
  ! HDUs description
  type imbfits_hdus_t
     integer(kind=4) :: n = 0  ! Number of HDUs in file (unused)
     integer(kind=4) :: nlead = 0  ! Position of first HDU of first subscan
     integer(kind=4) :: npersubscan = 0   ! Number of HDUs per subscan
     integer(kind=4) :: pos(mhdukinds)    ! Positions (abs or rel) of HDUs (per kind)
  end type imbfits_hdus_t
  !
  ! Primary
  type imbfits_primary_t
     integer(kind=4) :: status = code_imbfits_init
     type(fits_logi_0d_t) :: simple
     type(fits_inte_0d_t) :: bitpix
     type(fits_inte_0d_t) :: naxis
     type(fits_logi_0d_t) :: extend
     type(fits_char_0d_t) :: telescop
     type(fits_char_0d_t) :: origin
     type(fits_char_0d_t) :: creator
     type(fits_dble_0d_t) :: imbftsve
     type(fits_char_0d_t) :: instrume
     type(fits_char_0d_t) :: object
     type(fits_dble_0d_t) :: longobj
     type(fits_dble_0d_t) :: latobj
     type(fits_char_0d_t) :: timesys
     type(fits_dble_0d_t) :: mjd_obs
     type(fits_char_0d_t) :: date_obs
     type(fits_dble_0d_t) :: lst
     type(fits_char_0d_t) :: projid
     type(fits_char_0d_t) :: queue
     type(fits_dble_0d_t) :: exptime
     type(fits_inte_0d_t) :: n_obs
     type(fits_inte_0d_t) :: n_obsp
     type(fits_char_0d_t) :: obstype
     type(fits_inte_0d_t) :: nusefeed
     type(fits_inte_0d_t) :: totant
     type(fits_inte_0d_t) :: totsubr
     type(fits_inte_0d_t) :: totback
  end type imbfits_primary_t
  type imbfits_header_t
     ! Status of reading
     integer(kind=4) :: status = code_imbfits_init
     ! HDU parameters
     type(fits_char_0d_t) :: xtension
     type(fits_inte_0d_t) :: bitpix
     type(fits_inte_0d_t) :: naxis
     type(fits_inte_0d_t) :: naxis1
     type(fits_inte_0d_t) :: naxis2
     type(fits_inte_0d_t) :: pcount
     type(fits_inte_0d_t) :: gcount
     type(fits_inte_0d_t) :: tfields
     type(fits_char_0d_t) :: extname
  end type imbfits_header_t
  ! Scan header and table
  type imbfits_scan_header_t
     type(imbfits_header_t) :: desc
     ! Telescope and site
     type(fits_char_0d_t) :: telescop
     type(fits_dble_0d_t) :: telsize
     type(fits_dble_0d_t) :: sitelong
     type(fits_dble_0d_t) :: sitelat
     type(fits_dble_0d_t) :: siteelev
     ! Project
     type(fits_char_0d_t) :: projid
     type(fits_char_0d_t) :: obsid
     type(fits_char_0d_t) :: operator
     ! Scan
     type(fits_inte_0d_t) :: scannum
     ! Date and time
     type(fits_char_0d_t) :: date_obs
     type(fits_char_0d_t) :: date
     type(fits_dble_0d_t) :: mjd
     type(fits_dble_0d_t) :: lst
     type(fits_inte_0d_t) :: n_obs
     type(fits_inte_0d_t) :: exptime
     type(fits_char_0d_t) :: timesys
     type(fits_dble_0d_t) :: ut1utc
     type(fits_dble_0d_t) :: taiutc
     type(fits_dble_0d_t) :: etutc
     type(fits_dble_0d_t) :: gpstai
     ! Fixed source parameters
     type(fits_dble_0d_t) :: polex
     type(fits_dble_0d_t) :: poley
     type(fits_char_0d_t) :: object
     !type(fits_unkn_0d_t) :: sbas
     !type(fits_unkn_0d_t) :: sbasflag
     type(fits_char_0d_t) :: ctype1
     type(fits_char_0d_t) :: ctype2
     type(fits_char_0d_t) :: radesys
     type(fits_dble_0d_t) :: equinox
     type(fits_dble_0d_t) :: crval1
     type(fits_dble_0d_t) :: crval2
     type(fits_dble_0d_t) :: lonpole
     type(fits_dble_0d_t) :: latpole
     type(fits_dble_0d_t) :: longobj
     type(fits_dble_0d_t) :: latobj
     !type(fits_unkn_0d_t) :: calcode
     ! Moving source parameters
     type(fits_logi_0d_t) :: movefram
     type(fits_dble_0d_t) :: peridate
     type(fits_dble_0d_t) :: peridist
     type(fits_dble_0d_t) :: longasc
     type(fits_dble_0d_t) :: omega
     type(fits_dble_0d_t) :: inclinat
     type(fits_dble_0d_t) :: eccentr
     type(fits_dble_0d_t) :: orbepoch
     type(fits_dble_0d_t) :: orbeqnox
     type(fits_dble_0d_t) :: distance
     ! Switch mode
     type(fits_char_0d_t) :: swtchmod
     type(fits_inte_0d_t) :: noswitch
     type(fits_dble_0d_t) :: phasetim
     type(fits_dble_0d_t) :: wobthrow
     type(fits_inte_0d_t) :: wobdir ! ???
     type(fits_dble_0d_t) :: wobcycle
     type(fits_char_0d_t) :: wobmode
     !
     type(fits_inte_0d_t) :: nfebe
     ! Pointing and focus
     type(fits_dble_0d_t) :: p1
     type(fits_dble_0d_t) :: p2
     type(fits_dble_0d_t) :: p3
     type(fits_dble_0d_t) :: p4
     type(fits_dble_0d_t) :: p5
     type(fits_dble_0d_t) :: p7
     type(fits_dble_0d_t) :: p8
     type(fits_dble_0d_t) :: p9
     type(fits_dble_0d_t) :: rxhori
     type(fits_dble_0d_t) :: rxvert
     type(fits_dble_0d_t) :: third_re
     type(fits_dble_0d_t) :: zero_pol
     type(fits_dble_0d_t) :: phi_pol
     type(fits_dble_0d_t) :: eps_pol
     type(fits_dble_0d_t) :: col_sin
     type(fits_dble_0d_t) :: col_cos
     type(fits_char_0d_t) :: date_poi
     type(fits_dble_0d_t) :: p1cor
     type(fits_dble_0d_t) :: p2cor
     type(fits_dble_0d_t) :: p3cor
     type(fits_dble_0d_t) :: p4cor
     type(fits_dble_0d_t) :: p5cor
     type(fits_dble_0d_t) :: p7cor
     type(fits_dble_0d_t) :: p8cor
     type(fits_dble_0d_t) :: p9cor
     type(fits_dble_0d_t) :: rxhorico
     type(fits_dble_0d_t) :: rxvertco
     type(fits_dble_0d_t) :: focusx
     type(fits_dble_0d_t) :: focusy
     type(fits_dble_0d_t) :: focusz
     type(fits_dble_0d_t) :: p4corinc
     type(fits_dble_0d_t) :: p5corinc
     type(fits_char_0d_t) :: date_inc
     ! Weather and calibration
     type(fits_dble_0d_t) :: pressure
     type(fits_dble_0d_t) :: tambient
     type(fits_dble_0d_t) :: humidity
     type(fits_dble_0d_t) :: winddir
     type(fits_dble_0d_t) :: windvel
     type(fits_dble_0d_t) :: windvelm
     type(fits_char_0d_t) :: date_wea
     type(fits_dble_0d_t) :: refracti ! ???
     type(fits_dble_0d_t) :: thot
     type(fits_char_0d_t) :: date_hot
     type(fits_dble_0d_t) :: tiptauz
     type(fits_dble_0d_t) :: tiptaue
     type(fits_dble_0d_t) :: tiptauc
     type(fits_char_0d_t) :: date_tip
     ! ???
     type(fits_inte_0d_t) :: recon
     type(fits_inte_0d_t) :: reccntrl
  end type imbfits_scan_header_t
  type imbfits_scan_table_t
     integer(kind=4) :: status = code_imbfits_init
     type(fits_char_1d_t) :: sysoff
     type(fits_real_1d_t) :: xoffset
     type(fits_real_1d_t) :: yoffset
  end type imbfits_scan_table_t
  type imbfits_scan_t
     integer(kind=4) :: status = code_imbfits_init
     type(imbfits_scan_header_t) :: head
     type(imbfits_scan_table_t) :: table
  end type imbfits_scan_t
  ! Frontend header and scan
  type imbfits_front_header_t
     type(imbfits_header_t) :: desc
     !
     type(fits_inte_0d_t) :: scannum
     type(fits_char_0d_t) :: date_obs
     type(fits_char_0d_t) :: dewrtmod
     type(fits_dble_0d_t) :: dewang
     type(fits_inte_0d_t) :: febeband
     type(fits_inte_0d_t) :: febefeed
     type(fits_inte_0d_t) :: nusefeed
     type(fits_dble_0d_t) :: velosys
     type(fits_char_0d_t) :: specsys
     type(fits_char_0d_t) :: veloconv
     type(fits_char_0d_t) :: emirbeam
  end type imbfits_front_header_t
  type imbfits_front_table_t
     integer(kind=4) :: status = code_imbfits_init
     ! Frequency axis
     type(fits_char_1d_t) :: recname
     type(fits_char_1d_t) :: linename
     type(fits_dble_1d_t) :: restfreq
     ! Calibration
     type(fits_real_1d_t) :: beameff
     type(fits_real_1d_t) :: etafss
     type(fits_real_1d_t) :: gainimag
     type(fits_char_1d_t) :: sideband
     type(fits_dble_1d_t) :: sbsep
     type(fits_char_1d_t) :: widenar
     type(fits_real_1d_t) :: tcold
     type(fits_real_1d_t) :: thot
     ! Pixel description
     type(fits_inte_1d_t) :: ifeed
     type(fits_inte_1d_t) :: nofeeds
     type(fits_char_1d_t) :: pola
     ! Frequency axis
     type(fits_char_1d_t) :: doppler
     type(fits_real_1d_t) :: ifcenter
     type(fits_real_1d_t) :: bandwid
     type(fits_logi_1d_t) :: ifflipps ! ???
     type(fits_logi_1d_t) :: speclo   ! ???
     ! Brightness axis
     type(fits_char_1d_t) :: tscale
     ! Frequency switching
     type(fits_real_1d_t) :: frqthrow
     type(fits_real_1d_t) :: frqoff1
     type(fits_real_1d_t) :: frqoff2
  end type imbfits_front_table_t
  type imbfits_front_t
     integer(kind=4) :: status = code_imbfits_init
     type(imbfits_front_header_t) :: head
     type(imbfits_front_table_t) :: table
  end type imbfits_front_t
  ! Backend header and scan
  type imbfits_back_header_t
     type(imbfits_header_t) :: desc
     !
     type(fits_inte_0d_t) :: scannum
     type(fits_char_0d_t) :: date_obs
     type(fits_inte_0d_t) :: febeband
     type(fits_inte_0d_t) :: febefeed
     type(fits_inte_0d_t) :: nusefeed
     !type(fits_inte_0d_t) :: if1freqs ! ???
  end type imbfits_back_header_t
  type imbfits_back_table_t
     integer(kind=4) :: status = code_imbfits_init
     ! Channel information
     type(fits_inte_1d_t) :: part
     type(fits_inte_1d_t) :: refchan
     type(fits_inte_1d_t) :: chans
     type(fits_inte_1d_t) :: dropped
     type(fits_inte_1d_t) :: used
     ! Receiver information
     type(fits_inte_1d_t) :: pixel
     type(fits_char_1d_t) :: receiver
     type(fits_char_1d_t) :: band
     type(fits_char_1d_t) :: frontend  ! Frontend name to be used in telescope name (memory only)
     type(fits_char_1d_t) :: polar
     type(fits_logi_1d_t) :: dataflip  ! Data needs sign flip? (memory only)
     type(fits_inte_1d_t) :: ifront    ! Backpointer to frontend table (memory only)
     ! Frequency information
     type(fits_real_1d_t) :: reffreq
     type(fits_real_1d_t) :: spacing
     type(fits_char_1d_t) :: linename
  end type imbfits_back_table_t
  type imbfits_back_chunks_t
     ! Description of the chunks in the BACKEND table
     type(eclass_2inte2char_t)    :: eclass   ! Chunk equivalence classes
     integer(kind=4), allocatable :: used(:)  ! (Size Nchunks) Chunks used for those classes
     integer(kind=4), allocatable :: kind(:)  ! (Size Nset) See codes in stokesset_book_t
  end type imbfits_back_chunks_t
  type imbfits_back_t
     integer(kind=4) :: status = code_imbfits_init
     type(imbfits_back_header_t) :: head
     type(imbfits_back_table_t) :: table
     ! Derived data:
     logical :: polchunks  ! The table provides or not polarimetric chunks
     type(imbfits_back_chunks_t) :: chunks  ! NONE, AXIS, REAL, IMAG chunks description
  end type imbfits_back_t
  !
  type imbfits_backdata_header_t
     type(imbfits_header_t) :: desc
     !
     type(fits_inte_0d_t) :: scannum
     type(fits_inte_0d_t) :: obsnum
     type(fits_char_0d_t) :: baseband
     type(fits_char_0d_t) :: date_obs
     type(fits_dble_0d_t) :: mjd_beg  ! [MJD] Duplicate of 'date_obs' (memory only)
     type(fits_char_0d_t) :: date_end
     type(fits_dble_0d_t) :: mjd_end  ! [MJD] Duplicate of 'date_end' (memory only)
     type(fits_inte_0d_t) :: channels
     type(fits_inte_0d_t) :: nphases
     type(fits_char_0d_t) :: phaseone
     type(fits_dble_0d_t) :: tstamped
  end type imbfits_backdata_header_t
  type imbfits_backdata_table_t
     integer(kind=4) :: status = code_imbfits_init
   ! type(fits_inte_1d_t) :: integnum  ! No more meaning
     type(fits_dble_1d_t) :: mjd
     type(fits_dble_1d_t) :: integtim
     type(fits_inte_1d_t) :: iswitch
     ! Support for compressed columns. This is specific to the BackendXXX
     ! table. Use type(fits) for simplicity i.e. for using the various
     ! associated utilities.
     type(fits_inte_1d_t) :: forepoin  ! Forward pointer from non-compressed columns to compressed
     type(fits_inte_1d_t) :: backpoin  ! Back pointer from compressed columns to non-compressed
  end type imbfits_backdata_table_t
  type imbfits_backdata_t
     type(imbfits_backdata_header_t) :: head
     type(imbfits_backdata_table_t) :: table
  end type imbfits_backdata_t
  ! Antenna slow traces
  type imbfits_antslow_header_t
     ! NB: this type for both antslow and antfast
     type(imbfits_header_t) :: desc
     !
     type(fits_inte_0d_t) :: scannum
     type(fits_inte_0d_t) :: obsnum
     type(fits_char_0d_t) :: date_obs
     type(fits_dble_0d_t) :: mjd_beg  ! [MJD] Duplicate of 'date_obs' (memory only)
     type(fits_char_0d_t) :: date_end
     type(fits_dble_0d_t) :: mjd_end  ! [MJD] Duplicate of 'date_end' (memory only)
     type(fits_char_0d_t) :: obstype
     type(fits_char_0d_t) :: substype
     type(fits_dble_0d_t) :: substime
     type(fits_char_0d_t) :: systemof
     type(fits_dble_0d_t) :: subsxoff
     type(fits_dble_0d_t) :: subsyoff
     ! Segment
     type(fits_char_0d_t) :: setype01
     type(fits_dble_0d_t) :: setime01
     type(fits_dble_0d_t) :: sexoff01
     type(fits_dble_0d_t) :: seyoff01
     type(fits_dble_0d_t) :: sexsta01
     type(fits_dble_0d_t) :: seysta01
     type(fits_dble_0d_t) :: sexend01
     type(fits_dble_0d_t) :: seyend01
     type(fits_dble_0d_t) :: sespes01
     type(fits_dble_0d_t) :: sespee01
     ! Doppler
     type(fits_dble_0d_t) :: dopplerc
     type(fits_dble_0d_t) :: obsvelrf
     ! Fast traces
     type(fits_inte_0d_t) :: tracerat
  end type imbfits_antslow_header_t
  type imbfits_antslow_table_t
     integer(kind=4) :: status = code_imbfits_init
     type(fits_dble_1d_t) :: mjd
     type(fits_dble_1d_t) :: lst
     type(fits_dble_1d_t) :: longoff
     type(fits_dble_1d_t) :: latoff
     type(fits_dble_1d_t) :: cazimuth
     type(fits_dble_1d_t) :: celevatio
     type(fits_inte_1d_t) :: traceflag
  end type imbfits_antslow_table_t
  ! Antenna fast traces
  type imbfits_antfast_table_t
     integer(kind=4) :: status = code_imbfits_init
     type(fits_dble_1d_t) :: mjd
     type(fits_dble_1d_t) :: azimuth
     type(fits_dble_1d_t) :: elevation
     type(fits_dble_1d_t) :: tracking_az
     type(fits_dble_1d_t) :: tracking_el
  end type imbfits_antfast_table_t
  !
  type imbfits_antslow_t
     integer(kind=4) :: status = code_imbfits_init
     type(imbfits_antslow_header_t) :: head
     type(imbfits_antslow_table_t)  :: table
  end type imbfits_antslow_t
  !
  type imbfits_antfast_t
     integer(kind=4) :: status = code_imbfits_init
     type(imbfits_antslow_header_t) :: head ! There is not yet an antfast header
     type(imbfits_antfast_table_t)  :: table
  end type imbfits_antfast_t
  !
  ! Derotator
  type imbfits_derot_header_t
     ! NB: this type for both antslow and antfast
     type(imbfits_header_t) :: desc
     !
     type(fits_inte_0d_t) :: scannum
     type(fits_inte_0d_t) :: obsnum
     type(fits_char_0d_t) :: date_obs
     type(fits_dble_0d_t) :: mjd_beg  ! [MJD] Duplicate of 'date_obs' (memory only)
     type(fits_char_0d_t) :: date_end
     type(fits_dble_0d_t) :: mjd_end  ! [MJD] Duplicate of 'date_end' (memory only)
     type(fits_dble_0d_t) :: substime
  end type imbfits_derot_header_t
  type imbfits_derot_table_t
     integer(kind=4) :: status = code_imbfits_init
     type(fits_dble_1d_t) :: mjd
     type(fits_char_1d_t) :: system
     type(fits_real_1d_t) :: fwant
     type(fits_real_1d_t) :: hwant
     type(fits_real_1d_t) :: swant
     type(fits_real_1d_t) :: fact
     type(fits_real_1d_t) :: hact
     type(fits_real_1d_t) :: sact
  end type imbfits_derot_table_t
  type imbfits_derot_t
     integer(kind=4) :: status = code_imbfits_init
     type(imbfits_derot_header_t) :: head
     type(imbfits_derot_table_t) :: table
  end type imbfits_derot_t
  !
  type imbfits_t
     type(imbfits_file_t)    :: file
     type(imbfits_hdus_t)    :: hdus
     type(imbfits_primary_t) :: primary
     type(imbfits_scan_t)    :: scan
     type(imbfits_front_t)   :: front
     type(imbfits_back_t)    :: back
     type(imbfits_derot_t)   :: derot    ! Derotator
     type(eclass_char_t)     :: seclass  ! Subscans equiv class
  end type imbfits_t
  !
  ! Type specific for the DATA column. Note that this is the only
  ! column we do not read entirely
  type imbfits_data_t
     integer(kind=4) :: ntime = 0  ! Number of 'time' rows read
     integer(kind=4) :: npix  = 0  !
     integer(kind=4) :: nchan = 0  ! Number of channels in first dimension of 'VAL'
     real(kind=4), pointer :: val(:,:,:) => null()  ! [nchan x npix x ntimes] The DATA block
     real(kind=4), pointer :: wei(:)     => null()  ! [nchan] The WEIGHT array (use the same for all channels and pixels)
  end type imbfits_data_t
  !
  type imbfits_subscan_t
     integer(kind=4) :: isub = 0           ! Subscan number
     logical         :: onsky = .false.    ! Was the subscan looking at sky?
     integer(kind=4) :: calkind = 0        ! 0: not a cal, 1: sky/hot/cold, 2: grid  ZZZ useless?
     type(imbfits_backdata_t) :: backdata  !
     type(imbfits_antslow_t)  :: antslow   ! slow traces
     type(imbfits_antfast_t)  :: antfast   ! fast traces
  end type imbfits_subscan_t
  !
  integer(kind=4), parameter :: mstokes=4
  integer(kind=4), parameter :: code_n=0
  integer(kind=4), parameter :: code_h=1
  integer(kind=4), parameter :: code_v=2
  integer(kind=4), parameter :: code_r=3
  integer(kind=4), parameter :: code_i=4
  type stokesset_book_t
    integer(kind=4) :: nstokes        ! Number of chunksets per stokeset
    integer(kind=4) :: kind(mstokes)  ! Kind of each chunkset
    integer(kind=4) :: iset(mstokes)  ! Number of each chunkset
    logical         :: found          ! Found a stokesset?
    integer(kind=4) :: next           ! Next chunkset after the stokeset
  end type stokesset_book_t
  !
end module imbfits_types
!
module imbfits_messaging
  use gbl_message
  !---------------------------------------------------------------------
  ! This module provides:
  !  - the usual seve%? severities from the Gildas kernel (no need
  !    to USE GBL_MESSAGE)
  !  - the imbfits specific severities which can be dynamically changed
  !    thanks to the appropriate command
  !---------------------------------------------------------------------
  !
  type :: imbfits_debug_message_t
    integer(kind=4) :: alloc
    integer(kind=4) :: other
  end type imbfits_debug_message_t
  !
  ! Set the default at startup:
  !  iseve%alloc = seve%d
  !  iseve%other = seve%d
  type(imbfits_debug_message_t) :: iseve = imbfits_debug_message_t(seve%d,seve%d)
  !
end module imbfits_messaging
