!! Module to handle constraints in linear molecules
!!
!! Reference
module MW_linear_molecule
   use MW_kinds, only: wp
   use MW_box, only: MW_box_t
   use MW_ion, only: MW_ion_t
   use MW_molecule, only: MW_molecule_t
   implicit none
   private

   ! Public subroutines
   ! ------------------
   public :: constrain_positions
   public :: constrain_velocities

contains

   ! ===========================================================================
   ! Linear_Molecule algorithm part 1 - Update positions
   subroutine constrain_positions(num_pbc, molecule, dt, box, ions, &
         xyz_now, forces_now, xyz_next, velocity_next)
      implicit none
      ! Passed in
      ! ---------
      integer, intent(in) :: num_pbc
      type(MW_molecule_t), intent(in) :: molecule
      real(wp), intent(in) :: dt ! time step
      type(MW_box_t), intent(in) :: box ! simulation box
      type(MW_ion_t), intent(in)      :: ions(:)

      real(wp), intent(in) :: xyz_now(:,:)       ! coordinates at t
      real(wp), intent(in) :: forces_now(:,:)       ! coordinates at t

      ! Passed in/out
      ! -------------
      real(wp), intent(inout) :: xyz_next(:,:) !< coodinates at t+dt
      real(wp), intent(inout) :: velocity_next(:,:) !< velocities at t+dt

      select case(num_pbc)
      case(2)
         call constrain_positions_2DPBC(molecule, dt, box, ions, &
         xyz_now, forces_now, xyz_next, velocity_next)
      case(3)
         call constrain_positions_3DPBC(molecule, dt, box, ions, &
         xyz_now, forces_now, xyz_next, velocity_next)
      end select

   end subroutine constrain_positions

   ! ===========================================================================
   ! Linear_Molecule algorithm part 2 - Update velocities
   subroutine constrain_velocities(num_pbc, molecule, dt, box, ions, &
         xyz_next, forces_next, velocity_next)
      implicit none
      ! Passed in
      ! ---------
      integer, intent(in) :: num_pbc
      type(MW_molecule_t), intent(in) :: molecule
      real(wp), intent(in) :: dt !< time step
      type(MW_box_t), intent(in) :: box
      type(MW_ion_t), intent(in) :: ions(:)
      real(wp), intent(in) :: xyz_next(:,:) ! coordinates at t + dt
      real(wp), intent(in) :: forces_next(:,:) ! forces at t + dt

      ! Passed out
      ! ----------
      real(wp), intent(inout) :: velocity_next(:,:)   ! coordinates at t+dt


      select case(num_pbc)
      case(2)
         call constrain_velocities_2DPBC(molecule, dt, box, ions, &
         xyz_next, forces_next, velocity_next)
      case(3)
         call constrain_velocities_3DPBC(molecule, dt, box, ions, &
         xyz_next, forces_next, velocity_next)
      end select

   end subroutine constrain_velocities

   ! ================================================================================
   include 'linear_molecule_2DPBC.inc'
   include 'linear_molecule_3DPBC.inc'
   ! ================================================================================
   include 'minimum_image_displacement_2DPBC.inc'
   include 'minimum_image_displacement_3DPBC.inc'

end module MW_linear_molecule
