!===============================================================================
!
! ildg_restart_info.F90 - handle restart information in ILDG files
!
!-------------------------------------------------------------------------------
!
! Copyright (C) 2012-2016 Hinnerk Stueben
!
! This file is part of BQCD -- Berlin Quantum ChromoDynamics program
!
! BQCD is free software: you can redistribute it and/or modify
! it under the terms of the GNU General Public License as published by
! the Free Software Foundation, either version 3 of the License, or
! (at your option) any later version.
!
! BQCD is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with BQCD.  If not, see <http://www.gnu.org/licenses/>.
!
!-------------------------------------------------------------------------------
! cs[] is input from C
! C has to take care of trailing \0
! len_s = strlen(cs)
!
! ildg_get_*  routines get information from the program at writing (called from C)
! ildg_put_*  routines put information into the program at reading (called from C)
! ildg_set_*  routines set/initialise variables (called from Fortran)
!
!-------------------------------------------------------------------------------
# include "defs.h"

!-------------------------------------------------------------------------------
subroutine ildg_read_restart_info(flags)

  use typedef_flags
  use module_input
  use module_ildg_conf
  implicit none 
  type(type_flags), intent(in) :: flags
  FILENAME :: filename

  if (.not. flags%continuation_job) return
  if (input%io_restart_format /= "ildg") return

  call ildg_lime_file(filename, READ, .true.)
  call ildg_read_info(filename)

end  

!-------------------------------------------------------------------------------
subroutine ildg_put_bqcd_input(cs, len_s)  bind(c)

  use iso_c_binding
  use module_ildg_restart_info
  implicit none
  character(kind=c_char), intent(in) :: cs(*)
  integer(c_int), intent(in)         :: len_s

  integer :: i

  ildg_restart_info%input = ""

  do i = 1, len_s
     ildg_restart_info%input(i:i) = cs(i)
  enddo

  ildg_restart_info%input_is_initialised = .true.  

end

!-------------------------------------------------------------------------------
subroutine ildg_put_bqcd_counters(cs, len_s)  bind(c)

  use iso_c_binding
  use module_ildg_restart_info
  implicit none
  character(kind=c_char), intent(in) :: cs(*)
  integer(c_int), intent(in)         :: len_s

  integer :: i

  ildg_restart_info%counters = ""

  do i = 1, len_s
     ildg_restart_info%counters(i:i) = cs(i)
  enddo

  read(ildg_restart_info%counters, *) &
       ildg_restart_info%run, &
       ildg_restart_info%job, &
       ildg_restart_info%traj

  ildg_restart_info%counters_is_initialised = .true.  

end

!-------------------------------------------------------------------------------
subroutine ildg_put_bqcd_cksum(cs, len_s)  bind(c)

  use iso_c_binding
  use module_ildg_restart_info
  implicit none
  character(kind=c_char), intent(in) :: cs(*)
  integer(c_int), intent(in)         :: len_s

  integer :: i

  ildg_restart_info%cksum_str = ""

  do i = 1, len_s
     ildg_restart_info%cksum_str(i:i) = cs(i)
  enddo

  read(ildg_restart_info%cksum_str, *) ildg_restart_info%cksum

  ildg_restart_info%cksum_is_initialised = .true.  

end

!-------------------------------------------------------------------------------
subroutine ildg_put_bqcd_ran_name(cs, len_s)  bind(c)

  use iso_c_binding
  use module_ildg_restart_info
  use module_function_decl
  implicit none
  character(kind=c_char), intent(in) :: cs(*)
  integer(c_int), intent(in)         :: len_s

  integer :: i

  ildg_restart_info%ran_name = ""

  do i = 1, len_s
     ildg_restart_info%ran_name(i:i) = cs(i)
  enddo

  CHECK(ildg_restart_info%ran_name == ran_name())

  ildg_restart_info%ran_name_is_initialised = .true.  

end

!-------------------------------------------------------------------------------
subroutine ildg_put_bqcd_ran_state(cs, len_s)  bind(c)

  use iso_c_binding
  use module_ildg_restart_info
  use module_function_decl
  implicit none
  character(kind=c_char), intent(in) :: cs(*)
  integer(c_int), intent(in)         :: len_s

  integer :: i

  if (ildg_restart_info%ran_state_is_initialised) then
     call die("ildg_put_bqcd_ran_state(): memory leak")
  else
     allocate(ildg_restart_info%ran_state(len_s))
  endif

  do i = 1, len_s
     ildg_restart_info%ran_state(i) = cs(i)
  enddo
  
  ildg_restart_info%len_ran_state = len_s
  ildg_restart_info%ran_state_is_initialised = .true.  

end

!-------------------------------------------------------------------------------
subroutine ildg_put_bqcd_ranfield_state(cs, clen_s, cz, ct)  bind(c)

  use iso_c_binding
  use module_ildg_restart_info
  use module_function_decl
  use module_lattice
  implicit none
  character(kind=c_char), intent(in) :: cs(*)
  integer(c_int), intent(in)         :: clen_s
  integer(c_int), intent(in)         :: cz, ct

  character(clen_s) :: s
  integer           :: len_s, z, t, i
  integer, external :: ran_state_strlen

  CHECK(ildg_restart_info%ran_state_is_initialised)

  z = cz
  t = ct
  len_s = clen_s

  do i = 1, len_s
     s(i:i) = cs(i)
  enddo

  call ranfield_restore_ildg(s, len_s, z, t)
end

!-------------------------------------------------------------------------------
subroutine ildg_put_bqcd_plaquette(cs, len_s)  bind(c)

  use iso_c_binding
  use module_ildg_restart_info
  implicit none
  character(kind=c_char), intent(in) :: cs(*)
  integer(c_int), intent(in)         :: len_s

  integer :: i

  ildg_restart_info%plaquette_str = ""

  do i = 1, len_s
     ildg_restart_info%plaquette_str(i:i) = cs(i)
  enddo

  read(ildg_restart_info%plaquette_str, *) ildg_restart_info%plaquette

  ildg_restart_info%plaquette_is_initialised = .true.  

end

!-------------------------------------------------------------------------------
subroutine ildg_get_bqcd_input(cs, len_s)  bind(c)

  use iso_c_binding
  use module_input
  implicit none
  character(kind=c_char), intent(out) :: cs(*)
  integer(c_int), intent(in)          :: len_s

  character(len_s) :: s
  integer          :: i

  call input_dump_to_string(s)

  do i = 1, len_s
     cs(i) = s(i:i)
  enddo

end

!-------------------------------------------------------------------------------
subroutine ildg_get_bqcd_counters(run, job, traj)  bind(c)

  use iso_c_binding
  use module_counter
  implicit none
  integer(c_int) :: run, job, traj

  run = counter%run
  job = counter%job
  traj = counter%traj

end

!-------------------------------------------------------------------------------
subroutine ildg_get_bqcd_ran_name(cs, len_s)  bind(c)

  use iso_c_binding
  use module_function_decl
  implicit none
  character(kind=c_char), intent(out) :: cs(*)
  integer(c_int), intent(in)          :: len_s

  RAN_NAME :: name
  integer  :: i, len_n

  name = ran_name()
  len_n = len(trim(name))

  ASSERT(len_s >= len_n)

  do i = 1, len_n
     cs(i) = name(i:i)
  enddo

  do i = len_n + 1, len_s
     cs(i) = ' '
  enddo

end

!-------------------------------------------------------------------------------
subroutine ildg_get_bqcd_ran_state_strlen(len)  bind(c)

  use iso_c_binding
  implicit none
  integer(c_int), intent(out) :: len
  integer, external :: ran_state_strlen
  
  len = ran_state_strlen()

end

!-------------------------------------------------------------------------------
subroutine ildg_get_bqcd_ran_state(cs, len_s)  bind(c)

  use iso_c_binding
  use module_input
  implicit none
  character(kind=c_char), intent(out) :: cs(*)
  integer(c_int), intent(in)          :: len_s

  character(len_s) :: s
  integer          :: i
  integer, external :: ran_state_strlen

  ASSERT(len_s >= ran_state_strlen())

  call ran_state_to_string(s)

  do i = 1, len_s
     cs(i) = s(i:i)
  enddo

end

!-------------------------------------------------------------------------------
subroutine ildg_get_bqcd_ranfield_info(cz, ct)  bind(c)

  use iso_c_binding
  implicit none
  integer(c_int), intent(out) :: cz, ct
  integer :: z, t

  call ranfield_info(z, t)

  cz = z
  ct = t
end

!-------------------------------------------------------------------------------
subroutine ildg_get_bqcd_ranfield_state(cs, clen_s, cz, ct)  bind(c)

  use iso_c_binding
  implicit none
  character(kind=c_char), intent(out) :: cs(*)
  integer(c_int), intent(in)          :: clen_s
  integer(c_int), intent(in)          :: cz, ct

  character(clen_s) :: s
  integer           :: len_s
  integer           :: z, t
  integer           :: i
  integer, external :: ran_state_strlen

  len_s = clen_s
  z = cz
  t = ct

  call ranfield_dump_ildg(s, len_s, z, t)

  do i = 1, len_s
     cs(i) = s(i:i)
  enddo
end

!-------------------------------------------------------------------------------
subroutine ildg_get_bqcd_plaquette(plaq)  bind(c)

  use iso_c_binding
  use module_ildg_conf

  real(c_double), intent(out) :: plaq

  plaq = plaquette

end

!-------------------------------------------------------------------------------
subroutine ildg_get_bqcd_plaquette_qed(plaq_qed)  bind(c)

  use iso_c_binding
  use module_ildg_conf

  real(c_double), intent(out) :: plaq_qed

  plaq_qed = plaquette_qed

end

!===============================================================================
