// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0

///|
/// One receive window, connection or stream (RFC 9113 ยง6.9): how much the peer may
/// still send, and how much of what it sent has been handed back.
priv struct Window {
  mut max : Int32
  mut now : Int32
  mut processed : Int32
}

///|
fn Window::new(size : Int32) -> Window {
  { max: size, now: size, processed: 0, }
}

///|
/// Take `n` octets out of the window; `false` when the peer sent more than it may.
fn Window::consume(self : Window, n : Int32) -> Bool {
  if n > self.now {
    return false
  }
  self.now = self.now - n
  true
}

///|
/// Hand `n` processed octets back, and the WINDOW_UPDATE increment that is due,
/// zero when none is.
///
/// The rule is h2's `WindowManager`: wait until half the window has been processed,
/// or, when the window is shut, until a quarter of it or a kibibyte has. One update
/// per octet read would double the frames on the wire.
fn Window::process(self : Window, n : Int32) -> Int32 {
  self.processed = self.processed + n
  if self.processed == 0 {
    return 0
  }
  let quarter = if self.max / 4 < 1024 { self.max / 4 } else { 1024 }
  let due = (self.now == 0 && self.processed > quarter) ||
    self.processed >= self.max / 2
  if !due {
    return 0
  }
  let room = self.max - self.now
  let inc = if self.processed < room { self.processed } else { room }
  self.processed = 0
  self.now = self.now + inc
  inc
}

///|
/// Widen the window by `n`, as an explicit WINDOW_UPDATE does.
fn Window::open(self : Window, n : Int32) -> Unit {
  self.now = self.now + n
  if self.now > self.max {
    self.max = self.now
  }
}