dialect "objectdraw"
import "sys" as system
import "animation" as animator
import "random" as rand

type Animated = {
  start -> Done
}

// Create a ball with diameter ballSize that bounces around in boundary and
// off the paddle.  Constrain the speed in x and y to between minVal and maxVal
class ballSize (ballSize: Number) inside (boundary: Graphic2D) 
              moveRange (minVal: Number, maxVal: Number) 
              hitBy (paddle: Graphic2D) on (canvas:DrawingCanvas) -> Animated {

    def pauseTime: Number = 30  // time gap between moves of ball

    // Choose random number for distance to move in x and y directions each move
    var xShift: Number := rand.integerIn (minVal) to (maxVal)
    var yShift: Number := rand.integerIn (minVal) to (maxVal)
    
    // pixels to move per millisecond
    var xSpeed: Number := xShift/pauseTime
    var ySpeed: Number := yShift/pauseTime
    
    // remember initial y speed to use later
    def initYSpeed: Number = ySpeed
    
    // Create ball and start it falling
    method start -> Done {
        // the ball for the game
        def theBall: Graphic2D = filledOvalAt (boundary.location + (1 @ 1)) 
                             size (ballSize @ ballSize) on (canvas)
                            
        // the farthest to right the ball can go before bouncing off right wall 
        def ballRight: Number = boundary.x + boundary.width - theBall.width
        
        // remember the last time the ball was moved
        var lastTime := system.elapsed

        // Move the ball so it bounces off the sides and paddle.
        animator.while {theBall.y < canvas.height} pausing (pauseTime) do {
            def millisElapsed = (system.elapsed - lastTime)*1000
            theBall.moveBy(xSpeed*millisElapsed,ySpeed*millisElapsed)
            lastTime := system.elapsed
            // Fix speed and position if goes off sides
            if (theBall.x < boundary.x) then {  // off court on left
                xSpeed := -xSpeed
                theBall.moveTo(boundary.x @ theBall.y)
            } elseif {theBall.x > ballRight} then { // off on right
                xSpeed := -xSpeed
                theBall.moveTo (ballRight @ theBall.y) 
            } 
            
            // Fix speed and position if goes off top or hits paddle
            if (theBall.y < boundary.y) then {
                ySpeed := -ySpeed
                theBall.moveTo (theBall.x @ boundary.y)
            } elseif {theBall.overlaps (paddle)} then {
                ySpeed := -initYSpeed
            }
        } finally {
            theBall.removeFromCanvas
        }

    }
}