#ifdef MW_USE_PLUMED   
module MW_plumed
  
   use MW_kinds, only : wp
   use MW_constants, only: hartree2kJpermol, boltzmann, me2amu, bohr2angstrom, au2ps
   use MW_parallel, only: MW_COMM_WORLD
   use MW_stdio, only: MW_stdout, &
         MW_stdio_set_stdout => set_stdout

   implicit none

   ! private
   public :: init
   public :: calc
   public :: terminate

   ! A data structure to hold plumed related variable
   real(wp)    :: htmp(3,3), dummyvir(3,3)

   ! Add a couple of variables for plumed
   integer     :: total_atoms, plumed_version
   real(wp), dimension(:), allocatable :: massofions
   logical     :: plumedstart = .false.

contains

   subroutine init(temp, plumed_file, num_ions, num_atoms, num_ion_types, dt, ions)
      use MW_ion, only: MW_ion_t

      implicit none

      ! Parameters
      ! ----------
      real(wp), intent(in) :: temp, dt
      integer, intent(in) :: num_ions, num_atoms, num_ion_types
      character(50), intent(in) :: plumed_file
      type(MW_ion_t), intent(in), allocatable :: ions(:)

      ! Local
      ! -----
      character(50) :: plumedout = "plumed.out"
      integer :: itype, iion

      ! Initialized plumed
      call plumed_f_gcreate()
      call plumed_f_gcmd("getApiVersion"//char(0), plumed_version)
      if (plumed_version > 1) then
         call plumed_f_gcmd("setKbT"//char(0), boltzmann * temp)
      else
         print*, 'kT is not set properly and automatically in plumed,'//&
               ' you can probably set it in the plumed input file'//&
               ', please check it carefully'
      end if
      !set double precision
      call plumed_f_gcmd("setRealPrecision"//char(0), 8) 
      !set plumed units 
      total_atoms = num_ions + num_atoms !all the atoms in the MD run i.e solution + electrode
      call plumed_f_gcmd("setMDEnergyUnits"//char(0), hartree2kJpermol)
      call plumed_f_gcmd("setMDLengthUnits"//char(0), bohr2angstrom * 0.1_wp)
      call plumed_f_gcmd("setMDTimeUnits"//char(0), au2ps)
      call plumed_f_gcmd("setPlumedDat"//char(0), trim(adjustl(plumed_file))//char(0))
      call plumed_f_gcmd("setNatoms"//char(0), num_ions)
      call plumed_f_gcmd("setMDEngine"//char(0),"metalwalls")  ! I really have no clue of what is the point to do that
      call plumed_f_gcmd("setTimestep"//char(0), dt)!  system%dt
      call plumed_f_gcmd("setMPIFComm"//char(0), MW_COMM_WORLD)
      call plumed_f_gcmd("setLogFile"//char(0), trim(adjustl(plumedout))//char(0))
      call plumed_f_gcmd("init"//char(0), 0)

      allocate(massofions(num_ions))
      do itype = 1, num_ion_types
         do iion = ions(itype)%offset + 1, ions(itype)%offset + ions(itype)%count
            massofions(iion) = ions(itype)%mass * me2amu
         end do
      end do

      plumedstart = .true. !start to request plumed to do stuff, especially to avoind crashed when calling ener.f90 previous plumed initialisation 
   end subroutine init

!===============================================================================================
 
   subroutine calc(istep, forces_ions, xyz_ions, box, energy)

      use MW_lookup_table, only: MW_lut_t, &
            MW_lookup_table_lut_set => lut_set
      use MW_box, only: MW_box_t
      
      implicit none
 
      ! Parameters
      ! ----------
      integer, intent(in) :: istep
      real(wp), intent(in) :: xyz_ions(:,:)
      real(wp), intent(inout) :: forces_ions(:,:)
      type(MW_box_t), intent(in) :: box
      type(MW_lut_t), intent(inout) :: energy

      ! Local
      ! -----
      real(wp) :: bias
 
      if (plumedstart) then
         call plumed_f_gcmd("setStep"//char(0), istep)
         call plumed_f_gcmd("setPositionsX"//char(0), xyz_ions(:,1))
         call plumed_f_gcmd("setPositionsY"//char(0), xyz_ions(:,2))
         call plumed_f_gcmd("setPositionsZ"//char(0), xyz_ions(:,3))
         call plumed_f_gcmd("setMasses"//char(0),massofions(:))
         !call plumed_f_gcmd("setCharges"//char(0),system%xyz_ions(:,1,xyz_now))
         ! TODO energy refactoring for plumed required because energy array does not exist anymore
         !call plumed_f_gcmd("setEnergy"//char(0),system%energy(1))
         call plumed_f_gcmd("setForcesX"//char(0), forces_ions(:,1))
         call plumed_f_gcmd("setForcesY"//char(0), forces_ions(:,2))
         call plumed_f_gcmd("setForcesZ"//char(0), forces_ions(:,3))
         call plumed_f_gcmd("setVirial"//char(0), dummyvir) !I am not confident at all on the fact that is pint2 is the virial
         htmp = 0.0_wp
         htmp(1,1) = box%length(1)
         htmp(2,2) = box%length(2)
         htmp(3,3) = box%length(3)
         call plumed_f_gcmd("setBox"//char(0), htmp)
         call plumed_f_gcmd("calc"//char(0), 0)
         call plumed_f_gcmd("getBias"//char(0), bias)
         call MW_lookup_table_lut_set(energy, "Plumed_bias", bias)
      end if
 
   end subroutine calc
 
!===============================================================================================
 
   subroutine terminate()
      implicit none
      
      call plumed_f_gfinalize()
      deallocate(massofions)

   end subroutine terminate
 
end module
#endif
