local function Polar( x, y )
  local arctan = math.atan2( y, x )
  --maybe we don't need this line?
  --if arctan < 0.0 then arctan = arctan + 2.0 * math.pi end
  return math.sqrt( x * x + y * y ), arctan
end

local function tPolar( t )
  return Polar( t.x, t.y )
end

local function LerpWave( cur, new, alpha, x )
  local a = cur:Interpolate( x )
  local b = new:Interpolate( x )
  return alpha * b + ( 1.0 - alpha ) * a
end

--Peak of alpha * cur + (1 - alpha) * new on interval [xi, xf]
local function GetMinimum( cur, new, alpha, xi, xf )
  local ri, rf = LerpWave( cur, new, alpha, xi ), LerpWave( cur, new, alpha, xf )
  local xm = 0.5 * ( xi + xf )
  local rm = LerpWave( cur, new, alpha, 0.5 * ( xi + xf ) )
  return math.min( ri, rf )
end

local function GetTimeFromAlpha( alpha, curM, newM )
  return alpha * newM.t + ( 1.0 - alpha ) * curM.t
end

local function DetectCollision( curMarble, newMarble, curWave, newWave )
  local t, dt, r, th, normal


  --Polar coordinates:
  local iRadius, iTheta = tPolar( curMarble )
  local fRadius, fTheta = tPolar( newMarble )
  local iWaveRadius = curWave:Interpolate( iTheta )
  local fWaveRadius = curWave:Interpolate( fTheta )
  
  local speed = newMarble.dx * newMarble.dx + newMarble.dy * newMarble.dy

  --Case 1: marble is already outside the curve.
  if iRadius > iWaveRadius then
    return {
      speed = speed,
      dt = newMarble.t - curMarble.t,
      t = curMarble.t,
      r = iWaveRadius,
      th = iTheta,
      normal = iTheta - math.atan( curWave:Derivative( iTheta ) ), }
  end
  
  --Case 2: marble is outside the curve by tick end.
  if fRadius > fWaveRadius then
    --This isn't right, fix later.
    return {
      speed = speed,
      dt = 0,
      t = newMarble.t,
      r = fWaveRadius,
      th = fTheta,
      normal = fTheta - math.atan( curWave:Derivative( iTheta ) ) }
  end
  
  --Case 3: check whether marble passed through analog peak.
  
  --Case 4: marble must have remained inside curve.
  return
end

return DetectCollision