/* 
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. 
 * 
 * This file is available and licensed under the following license:
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 *   * Neither the name of Sun Microsystems nor the names of its contributors 
 *     may be used to endorse or promote products derived from this software 
 *     without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
import javafx.scene.Cursor;
import javafx.scene.CustomNode;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;

public class Ball extends CustomNode {
  public-init var sign: Boolean;
  public-init var radius: Number;
  var vx: Number;
  var vy: Number;
  var event: MouseEvent on replace old {
    if (event != null) {
      vx = event.dragX - old.dragX;
      vy = event.dragY - old.dragY;
      translateX += vx;
      translateY += vy;
    }
  }
  override function create() {
    def color = if (sign)  then Color.RED  else Color.BLUE;
    Circle {
      radius: radius - 1
      stroke: color
      fill: RadialGradient {
        radius: radius
        focusX: radius * 0.8
        focusY: radius * -0.8
        proportional: false
        stops: [
          Stop {offset: 0   color: Color.WHITE},
          Stop {offset: 1   color: color}
        ]
      }
      cursor: Cursor.HAND
      onMouseDragged: function(event) {
        this.event = event;
      }
      onMouseReleased: function(event) {
        this.event = null;
      }
    }
  }
  public function update() {
    if (event == null) {
      translateX += (vx *= 0.9);
      translateY += (vy *= 0.9);
      if (translateX < radius) { vx = -vx;  translateX = radius + radius - translateX }
      if (translateY < radius) { vy = -vy;  translateY = radius + radius - translateY }
      var w = scene.width  - radius;
      var h = scene.height - radius;
      if (translateX > w) { vx = -vx;  translateX = w + w - translateX }
      if (translateY > h) { vy = -vy;  translateY = h + h - translateY }
    }
  }
  public function process(ball: Ball) {
    var d  = ball.radius + radius;
    var dx = ball.translateX - translateX;
    var dy = ball.translateY - translateY;
    var dd = (dx * dx) + (dy * dy);
    var collision = dd <= (d * d);
    // process collision
    if (collision) {
      var dvx = ball.vx - vx;
      var dvy = ball.vy - vy;

      var mag = dvx * dx + dvy * dy;
      if (mag <= 0) {
        mag /= dd;
      
        var delta_vx = dx * mag;
        var delta_vy = dy * mag;

        ball.vx -= delta_vx * radius / d;
        ball.vy -= delta_vy * radius / d;

        vx += delta_vx * ball.radius / d;
        vy += delta_vy * ball.radius / d;
      }
    }
    // process gravity
    if (dd > 0) {
      var f = 0.05 * ball.radius * radius / dd;

      var delta_vx = dx * f;
      var delta_vy = dy * f;
      if (collision or (ball.sign == sign)) {
        delta_vx = -delta_vx;
        delta_vy = -delta_vy;
      }

      ball.vx -= delta_vx * radius / d;
      ball.vy -= delta_vy * radius / d;

      vx += delta_vx * ball.radius / d;
      vy += delta_vy * ball.radius / d;
    }
  }
}