!============================================================================
!
! (3) bse_hdf5_setup
!
!============================================================================

#include "f_defs.h"

module epswrite_hdf5_m
#ifdef HDF5

  use h5lt
  use hdf5
  use global_m
  use hdf5_io_m
  implicit none

  private

  public :: &
    eps_hdf5_setup, &
    set_qpt_done, &
    is_qpt_done

contains


subroutine eps_hdf5_setup(freq_dep,nFreq,dFreqGrid,dFreqBrd,ecuts,kgrid,&
  ng,gcomponents,nq,qpts,nmtx_of_q,nmtxmax,nspin,name,restart)
  integer, intent(in) :: freq_dep
  integer, intent(in) :: nFreq
  real(DP), intent(in) :: dFreqGrid(:) !< (nFreq)
  complex(DPC), intent(in) :: dFreqBrd(:) !< (nFreq)
  real(DP), intent(in) :: ecuts 
  integer, intent(in) :: ng
  integer, intent(in) :: gcomponents(:,:) !< (3,ng)
  integer, intent(in) :: kgrid(3)
  integer, intent(in) :: nq
  real(DP), intent(in) :: qpts(:,:) !< (3,nq)
  integer, intent(in) :: nmtx_of_q(:) !< (nq)
  integer, intent(in) :: nmtxmax
  integer, intent(in) :: nspin !< number of spins in the dielectric matrix/polarizability!
  character(len=*), intent(in) :: name
  logical, intent(inout), optional :: restart

  integer(HID_T) :: file_id       ! File identifier
  integer(HID_T) :: matrix_id     ! Dataset identifier
  integer(HID_T) :: filespace     ! Dataspace identifier in file
  integer(HID_T) :: qpointspace
  integer(HID_T) :: qpoints_id
  integer(HSIZE_T) :: dims(6)

  integer :: error, intinfo(9), intinfo_old(9), ii, eps_size, num_matrix, intdata(1), qpt_done(nq)
  real(DP), allocatable :: tmp(:,:)
  real(DP) :: realdata(1)
  logical :: restart_, file_exists, file_ok

  PUSH_SUB(eps_hdf5_setup)

  intinfo(1) = SCALARSIZE - 1 !FHJ: FIXME - don`t subtract unity!
  intinfo(2) = nq
  intinfo(3) = freq_dep
  intinfo(4) = nFreq
  intinfo(5) = ng
  intinfo(6) = nmtxmax
  intinfo(7:9) = kgrid(1:3)

  restart_=.false.
  if (present(restart)) restart_ = restart
! XXX NEED THIS?
  !write(13) "ajname,ajdate"

  ! FHJ: try to restart the calculation, if possible and desired.
  ! We ignore the restart flags if the file doesn`t exist. However, the code
  ! dies if the file exists and is incompatible or looks corrupted.
  if (restart_) then
    write(6,'(1x,2a)') "Trying to restart file ", trim(name)
    inquire(file=trim(name), exist=file_exists)
    if (file_exists) then
      call h5fopen_f(trim(name), H5F_ACC_RDONLY_F, file_id, error)
      if (error==0) then
        ! FHJ: a simply consistency checks. Could be improved..
        file_ok = h5ltfind_dataset_f(file_id, 'qpt_done')==1
        if (file_ok) then
          call hdf5_read_int_array(file_id, 'intinfo', (/9/), intinfo_old, error)
          file_ok = error==0 .and. all(intinfo_old==intinfo)
        endif
        call h5fclose_f(file_id, error)
        if (file_ok) then
          ! FHJ: File *seems* alright, we don`t have to initialize it
          write(6,'(1x,2a)') "Everything looks ok: restarting file ", trim(name)
          return
        endif
        write(0,'(3a)') "ERROR: file ", trim(name), " is incompatible with the current calculation."
        write(0,'(a,9(i0,1x))') 'old intinfo: ', intinfo_old
        write(0,'(a,9(i0,1x))') 'new intinfo: ', intinfo
        call die("file "//trim(name)//" is incompatible with the current calculation.", only_root_writes=.true.)
      else
        write(0,'(3a,i0,a)') "ERROR: ", trim(name), " is not a valid HDF5 file (error code: ", error," )."
        write(0,'(a)') 'Make sure the file is not corrupted'
        call die("file "//trim(name)//" looks corrupted", only_root_writes=.true.)
      endif
    endif
    write(0,'(3a)') "WARNING: file ", trim(name), " doesn`t exist. We`ll start the calculation from scratch."   
    restart_ = .false.
    if (present(restart)) restart = .false.
  endif

  ! JRD: Create the file
  write(6,'(1x,2a)') "Initializing ", trim(name)
  call h5fcreate_f(trim(name), H5F_ACC_TRUNC_F, file_id, error)

! FHJ: FF calculations always compute complex dielectric matrices, and
! need two matrices (retarded+advanced)
  num_matrix = 1
  eps_size = SCALARSIZE
  if (freq_dep/=0) then
    num_matrix = SCALARSIZE
    eps_size = 2
  endif

! JRD: Create Space For Matrix
  dims(1) = eps_size
  if (freq_dep .eq. 0) then
    dims(2) = 1
  else
    dims(2) = nFreq
  endif
  dims(3) = nmtxmax
  dims(4) = nmtxmax
  dims(5) = num_matrix*nspin
  dims(6) = nq
  call h5screate_simple_f(6, dims, filespace, error)
  call h5dcreate_f(file_id, 'matrix', H5T_NATIVE_DOUBLE, filespace, matrix_id, error)
  call h5dclose_f(matrix_id, error)
  call h5sclose_f(filespace, error)

! Create Space for static matrix diagonal
  dims(1:3) = (/eps_size,nmtxmax,nq/)
  call h5screate_simple_f(3, dims(1:3), filespace, error)
  call h5dcreate_f(file_id, 'matrix-diagonal', H5T_NATIVE_DOUBLE, filespace, matrix_id, error)
  call h5dclose_f(matrix_id, error)
  call h5sclose_f(filespace, error)

! JRD: Write integer MetaData
  dims(1) = 9
  call H5LTmake_dataset_int_f(file_id, 'intinfo', 1, dims(1:1), intinfo, error)

! JRD: Write file version number
  dims(1) = 1
  intdata(1) = 1
  call H5LTmake_dataset_int_f(file_id, 'versionnumber', 1, dims(1:1), intdata, error)

! JRD: Write double precision metadata (ecuts)
  dims(1:1) = 1
  realdata(1) = ecuts
  call H5LTmake_dataset_double_f(file_id, 'dblinfo', 1, dims(1:1), realdata, error)

! JRD: Write g-vecs
  dims(1:2) = (/3,ng/)
  call H5LTmake_dataset_int_f(file_id, 'gvecs', 2, dims(1:2), gcomponents, error)

! JRD: Write q-points
  dims(1:2) = (/3,nq/)
  call H5LTmake_dataset_double_f(file_id, 'qpoints', 2, dims(1:2), qpts, error)

! JRD: Create Space for q-gvec-index
  dims(1:3) = (/ng,2,nq/)
  call h5screate_simple_f(3, dims(1:3), qpointspace, error)
  call h5dcreate_f(file_id, 'q-gvec-index', H5T_NATIVE_INTEGER, qpointspace, &
                      qpoints_id, error)
  call h5dclose_f(qpoints_id, error)
  call h5sclose_f(qpointspace, error)

! JRD: Create Space for q-gvec-ekin
  dims(1:2) = (/ng,nq/)
  call h5screate_simple_f(2, dims(1:2), qpointspace, error)
  call h5dcreate_f(file_id, 'q-gvec-ekin', H5T_NATIVE_DOUBLE, qpointspace, &
                      qpoints_id, error)
  call h5dclose_f(qpoints_id, error)
  call h5sclose_f(qpointspace, error)

! JRD: Write nmtx list
  dims(1) = nq
  call H5LTmake_dataset_int_f(file_id, 'nmtx-of-q', 1, dims(1:1), nmtx_of_q, error)

! JRD: Write frequencies
  if (freq_dep .ne. 0) then 
    dims(1:1) = (/nFreq/)
    call H5LTmake_dataset_double_f(file_id, 'freqs', 1, dims(1:1), dFreqGrid, error)

    SAFE_ALLOCATE(tmp,(2,nFreq))
    do ii = 1, nFreq
      tmp(1,ii) = DBLE(dFreqBrd(ii))
      tmp(2,ii) = IMAG(dFreqBrd(ii))
    enddo
    dims(1:2) = (/2,nFreq/)
    call H5LTmake_dataset_double_f(file_id, 'freqbrds', 2, dims(1:2), tmp, error)
    SAFE_DEALLOCATE(tmp) 
  endif

  call hdf5_write_int(file_id, 'nspin', nspin, error)
  qpt_done = 0
  call hdf5_write_int_array(file_id, 'qpt_done', (/nq/), qpt_done, error)

  call h5fclose_f(file_id, error)

  POP_SUB(eps_hdf5_setup)

end subroutine eps_hdf5_setup


subroutine set_qpt_done(fname, iq)
  character(len=*), intent(in) :: fname
  integer, intent(in) :: iq

  integer(HID_T) :: file_id
  integer :: nq, error, intinfo(9)
  integer, allocatable :: qpt_done(:)

  PUSH_SUB(set_qpt_done)

  call h5fopen_f(trim(fname), H5F_ACC_RDWR_F, file_id, error)
  call hdf5_read_int_array(file_id, 'intinfo', (/9/), intinfo, error)
  nq = intinfo(2)
  SAFE_ALLOCATE(qpt_done, (nq))
  call hdf5_read_int_array(file_id, 'qpt_done', (/nq/), qpt_done, error)
  qpt_done(iq) = 1
  call hdf5_write_int_array(file_id, 'qpt_done', (/nq/), qpt_done, error)
  call h5fclose_f(file_id, error)
  SAFE_DEALLOCATE(qpt_done)

  POP_SUB(set_qpt_done)

end subroutine set_qpt_done


logical function is_qpt_done(fname, iq)
  character(len=*), intent(in) :: fname
  integer, intent(in) :: iq

  integer(HID_T) :: file_id
  integer :: nq, error, intinfo(9)
  integer, allocatable :: qpt_done(:)

  PUSH_SUB(is_qpt_done)

  call h5fopen_f(trim(fname), H5F_ACC_RDONLY_F, file_id, error)
  call hdf5_read_int_array(file_id, 'intinfo', (/9/), intinfo, error)
  nq = intinfo(2)
  SAFE_ALLOCATE(qpt_done, (nq))
  call hdf5_read_int_array(file_id, 'qpt_done', (/nq/), qpt_done, error)
  is_qpt_done = qpt_done(iq)==1
  call h5fclose_f(file_id, error)
  SAFE_DEALLOCATE(qpt_done)

  POP_SUB(is_qpt_done)

end function is_qpt_done

#endif
end module epswrite_hdf5_m
