///|
pub(all) enum Boundary1D {
  Periodic
  Reflecting
  Absorbing
} derive(Debug, ToJson, Eq)

///|
pub(all) struct BoundaryResult {
  x : Double
  v : Double
  alive : Bool
} derive(Debug, ToJson)

///|
pub fn apply_boundary(
  grid : Grid1D,
  boundary : Boundary1D,
  x : Double,
  v : Double,
) -> BoundaryResult {
  match boundary {
    Periodic => { x: grid.wrap(x), v, alive: true }
    Reflecting =>
      if x < 0.0 {
        { x: -x, v: -v, alive: true }
      } else if x >= grid.length {
        { x: 2.0 * grid.length - x, v: -v, alive: true }
      } else {
        { x, v, alive: true }
      }
    Absorbing =>
      if x < 0.0 || x >= grid.length {
        { x, v, alive: false }
      } else {
        { x, v, alive: true }
      }
  }
}

///|
pub fn apply_boundary_to_particle(
  grid : Grid1D,
  boundary : Boundary1D,
  particle : Particle,
) -> Particle? {
  let result = apply_boundary(grid, boundary, particle.x, particle.v)
  if result.alive {
    Some(
      Particle::new(
        x=result.x,
        v=result.v,
        weight=particle.weight,
        charge=particle.charge,
        mass=particle.mass,
      ),
    )
  } else {
    None
  }
}