///|
/// Structuring element shape for mathematical morphology operations.
pub(all) enum MorphShape {
  Rect
  Cross
  Ellipse
} derive(Debug, Eq)

///|
/// Structuring element with 2D binary kernel.
pub(all) struct StructuringElement {
  shape : MorphShape
  radius : Int
  width : Int
  height : Int
  data : Array[Bool]
} derive(Debug, Eq)

///|
/// Creates a structuring element of specified shape and radius.
pub fn StructuringElement::new(
  shape : MorphShape,
  radius : Int,
) -> StructuringElement {
  let r = if radius < 1 { 1 } else { radius }
  let size = 2 * r + 1
  let data = Array::make(size * size, false)

  for dy in -r..<=r {
    for dx in -r..<=r {
      let is_active = match shape {
        Rect => true
        Cross => dx == 0 || dy == 0
        Ellipse =>
          (dx * dx).to_double() / (r * r).to_double() +
          (dy * dy).to_double() / (r * r).to_double() <=
          1.0001
      }
      let idx = (dy + r) * size + (dx + r)
      data[idx] = is_active
    }
  }

  { shape, radius: r, width: size, height: size, data }
}

///|
/// Morphological Dilation (local maximum operator).
pub fn morph_dilate(img : Image, element : StructuringElement) -> Image {
  let w = img.width
  let h = img.height
  let res = Image::new(w, h)
  let r = element.radius
  let size = element.width

  for y in 0..= 0 && px < w && py >= 0 && py < h {
              let v = img.get(px, py)
              if v > max_val {
                max_val = v
              }
            }
          }
        }
      }
      res.set(x, y, max_val)
    }
  }

  res
}

///|
/// Morphological Erosion (local minimum operator).
pub fn morph_erode(img : Image, element : StructuringElement) -> Image {
  let w = img.width
  let h = img.height
  let res = Image::new(w, h)
  let r = element.radius
  let size = element.width

  for y in 0..= 0 && px < w && py >= 0 && py < h {
              let v = img.get(px, py)
              if v < min_val {
                min_val = v
              }
            } else {
              min_val = 0
            }
          }
        }
      }
      res.set(x, y, min_val)
    }
  }

  res
}

///|
/// Morphological Opening: Erode followed by Dilate (removes small bright noise).
pub fn morph_open(img : Image, element : StructuringElement) -> Image {
  let eroded = morph_erode(img, element)
  morph_dilate(eroded, element)
}

///|
/// Morphological Closing: Dilate followed by Erode (fills small dark holes).
pub fn morph_close(img : Image, element : StructuringElement) -> Image {
  let dilated = morph_dilate(img, element)
  morph_erode(dilated, element)
}

///|
/// Morphological Gradient: Dilate minus Erode (highlights object boundaries).
pub fn morph_gradient(img : Image, element : StructuringElement) -> Image {
  let dilated = morph_dilate(img, element)
  let eroded = morph_erode(img, element)
  let w = img.width
  let h = img.height
  let res = Image::new(w, h)

  for y in 0.. Image {
  let opened = morph_open(img, element)
  let w = img.width
  let h = img.height
  let res = Image::new(w, h)

  for y in 0.. Image {
  let closed = morph_close(img, element)
  let w = img.width
  let h = img.height
  let res = Image::new(w, h)

  for y in 0.. Image {
  let w = binary_img.width
  let h = binary_img.height
  let img = binary_img.clone()

  let mut changed = true
  let to_delete : Array[(Int, Int)] = []

  while changed {
    changed = false

    // Step 1
    to_delete.clear()
    for y in 1..<(h - 1) {
      for x in 1..<(w - 1) {
        if img.get(x, y) > 0 {
          let p2 = if img.get(x, y - 1) > 0 { 1 } else { 0 }
          let p3 = if img.get(x + 1, y - 1) > 0 { 1 } else { 0 }
          let p4 = if img.get(x + 1, y) > 0 { 1 } else { 0 }
          let p5 = if img.get(x + 1, y + 1) > 0 { 1 } else { 0 }
          let p6 = if img.get(x, y + 1) > 0 { 1 } else { 0 }
          let p7 = if img.get(x - 1, y + 1) > 0 { 1 } else { 0 }
          let p8 = if img.get(x - 1, y) > 0 { 1 } else { 0 }
          let p9 = if img.get(x - 1, y - 1) > 0 { 1 } else { 0 }

          let b = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9
          if b >= 2 && b <= 6 {
            let mut a = 0
            if p2 == 0 && p3 == 1 {
              a += 1
            }
            if p3 == 0 && p4 == 1 {
              a += 1
            }
            if p4 == 0 && p5 == 1 {
              a += 1
            }
            if p5 == 0 && p6 == 1 {
              a += 1
            }
            if p6 == 0 && p7 == 1 {
              a += 1
            }
            if p7 == 0 && p8 == 1 {
              a += 1
            }
            if p8 == 0 && p9 == 1 {
              a += 1
            }
            if p9 == 0 && p2 == 1 {
              a += 1
            }

            if a == 1 && p2 * p4 * p6 == 0 && p4 * p6 * p8 == 0 {
              to_delete.push((x, y))
            }
          }
        }
      }
    }

    if to_delete.length() > 0 {
      changed = true
      for pt in to_delete {
        img.set(pt.0, pt.1, 0)
      }
    }

    // Step 2
    to_delete.clear()
    for y in 1..<(h - 1) {
      for x in 1..<(w - 1) {
        if img.get(x, y) > 0 {
          let p2 = if img.get(x, y - 1) > 0 { 1 } else { 0 }
          let p3 = if img.get(x + 1, y - 1) > 0 { 1 } else { 0 }
          let p4 = if img.get(x + 1, y) > 0 { 1 } else { 0 }
          let p5 = if img.get(x + 1, y + 1) > 0 { 1 } else { 0 }
          let p6 = if img.get(x, y + 1) > 0 { 1 } else { 0 }
          let p7 = if img.get(x - 1, y + 1) > 0 { 1 } else { 0 }
          let p8 = if img.get(x - 1, y) > 0 { 1 } else { 0 }
          let p9 = if img.get(x - 1, y - 1) > 0 { 1 } else { 0 }

          let b = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9
          if b >= 2 && b <= 6 {
            let mut a = 0
            if p2 == 0 && p3 == 1 {
              a += 1
            }
            if p3 == 0 && p4 == 1 {
              a += 1
            }
            if p4 == 0 && p5 == 1 {
              a += 1
            }
            if p5 == 0 && p6 == 1 {
              a += 1
            }
            if p6 == 0 && p7 == 1 {
              a += 1
            }
            if p7 == 0 && p8 == 1 {
              a += 1
            }
            if p8 == 0 && p9 == 1 {
              a += 1
            }
            if p9 == 0 && p2 == 1 {
              a += 1
            }

            if a == 1 && p2 * p4 * p8 == 0 && p2 * p6 * p8 == 0 {
              to_delete.push((x, y))
            }
          }
        }
      }
    }

    if to_delete.length() > 0 {
      changed = true
      for pt in to_delete {
        img.set(pt.0, pt.1, 0)
      }
    }
  }

  img
}