module mt_data

! The structures defined in this module follow the standard laid out in Thomas etal 2014.
! They should not be modified without good reason.

  use hdf5
  use h5lt
  use iso_c_binding

  ! Use fixed string size (or else gets very easy to make mistakes)
  integer, parameter :: csize=1024
  
  integer(hid_t) :: mt_fid  ! File identifier
 
  ! Attributes
  real(c_float) :: box;
  real(c_float) :: h100;
  real(c_float) :: omega_baryon;
  real(c_float) :: omega_cdm;
  real(c_float) :: omega_lambda;
  real(c_float) :: sigma8;
  character(c_char) :: title*(csize)

  ! Snapshot table
  integer(hsize_t) :: NSnap
  type, bind(c) :: snaptable_t
     integer(c_int32_t) :: snapnum
     real(c_float)    :: a
     real(c_float)    :: z
     real(c_float)    :: t
     real(c_float)    :: t0
  end type snaptable_t
  type(snaptable_t), target, allocatable :: Snap(:)
  integer(hsize_t), parameter :: snaptable_nfields=5
  ! Note: YOU MUST MATCH DATA TYPES (no automatice type or size conversion)
  !       field types: i - int32, l - int64, f - float, d - double
  character(c_char), parameter :: snaptable_field_types(snaptable_nfields)=(/'i','f','f','f','f'/)
  ! This format is required to make a table...
  character(c_char), target :: snaptable_field_names(snaptable_nfields)*(csize)=&
       &(/'snapnum','a      ','z      ','t      ','t0     '/)
  ! ...and this format to read a table.  Really!
  character(c_char) :: snaptable_fieldnames*(csize)='snapnum,a,z,t,t0'
  ! Note: If you get these names wrong HDF5 won't complain - just return garbage
  !       You can omit fields from a table but you MUST PRESERVE ORDER

  ! Snapshot table properties
  integer(hsize_t) :: NSnapProp
  type, bind(c) :: snapprop_t
     character(c_char) :: Name*(csize)
     character(c_char) :: Description*(csize)
     character(c_char) :: Units*(csize)
  end type snapprop_t
  type(snapprop_t), target, allocatable :: SnapProp(:)
  integer(hsize_t), parameter :: snapprop_nfields=3
  character(c_char), target :: snapprop_field_names(snapprop_nfields)*(csize) = &
       & (/ 'name       ','description','Units      ' /)
  ! Note how I messed up the input file by having just Units capitalised.  If you alter the case
  ! of any of these entries then they will be omitted without warning and the others filled with garbage.
  character(c_char) :: snapprop_fieldnames*(csize) = 'name,description,Units'
  character(c_char), parameter :: snapprop_field_types(snapprop_nfields) = &
       & (/ 's','s','s' /)

  ! Merger Tree arrays
  integer(hsize_t) :: NHalo               !Number of halos in merger tree
  integer(c_int) :: HaloIndexOffset=1   !Pointer offset
  integer(c_int) :: TableFlag=0         !Flag to say whether stored in table or not
  integer(c_int64_t), target, allocatable :: mtHaloID(:)
  integer(c_int32_t), target, allocatable :: mtSnapshot(:)
  real(c_float), target, allocatable :: mtDensity(:)
  real(c_float), target, allocatable :: mtMass(:)
  integer(c_int32_t), target, allocatable :: mtFirstSubhaloIndex(:)
  integer(c_int32_t), target, allocatable :: mtNeighbourIndex(:)
  integer(c_int32_t), target, allocatable :: mtHostHaloIndex(:)
  integer(c_int32_t), target, allocatable :: mtFirstProgenitorIndex(:)
  integer(c_int32_t), target, allocatable :: mtNextSiblingIndex(:)
  integer(c_int32_t), target, allocatable :: mtDescendantIndex(:)

end module mt_data
