/*******************************************************************************
*                                                                              *
*  File:        BouncingBall.js                         Revision:  1.0         *
*                                                                              *
*  Purpose:     basic routines for the "BouncingBall" demo                     *
*                                                                              *
*  Creation:    25.06.1998                     Last Modification:  05.05.2002  *
*                                                                              *
*  Platform:    IBM-compatible PC running Windows 98SE                         *
*                                                                              *
*  Environment: JavaScript 1.3                                                 *
*                                                                              *
*  Author:      Andreas Rozek           Phone:  ++49 (711) 6770682             *
*               Kirschblütenweg 15      Fax:    -                              *
*             D-70569 Stuttgart         EMail:  Andreas.Rozek@T-Online.De      *
*               Germany                                                        *
*                                                                              *
*  URL:         http://www.Andreas-Rozek.de/                                   *
*                                                                              *
*  Copyright:   this software is published under the  "GNU Lesser General Pub- *
*               lic  License"  (see  "http://www.fsf.org/copyleft/lesser.html" *
*               for additional information)                                    *
*                                                                              *
*  Comments:    (none)                                                         *
*                                                                              *
*******************************************************************************/

/**** table of supported colors (each color requires a corresponding pixel image) ****/

  function newImage (ImageURL) {
    var Result = new Image(_PixelSize,_PixelSize);
      Result.src = ImageURL;
    return Result;
  };

  var Black   = newImage("./BlackPixel.gif");
  var Gray    = newImage("./GrayPixel.gif");
  var Maroon  = newImage("./MaroonPixel.gif");
  var Red     = newImage("./RedPixel.gif");
  var Green   = newImage("./GreenPixel.gif");
  var Lime    = newImage("./LimePixel.gif");
  var Olive   = newImage("./OlivePixel.gif");
  var Yellow  = newImage("./YellowPixel.gif");
  var Navy    = newImage("./NavyPixel.gif");
  var Blue    = newImage("./BluePixel.gif");
  var Purple  = newImage("./PurplePixel.gif");
  var Fuchsia = newImage("./FuchsiaPixel.gif");
  var Teal    = newImage("./TealPixel.gif");
  var Aqua    = newImage("./AquaPixel.gif");
  var Silver  = newImage("./SilverPixel.gif");
  var White   = newImage("./WhitePixel.gif");

  var _ColorTable = new Object();
    _ColorTable["black"]   = Black;   _ColorTable[0]  = Black;
    _ColorTable["gray"]    = Gray;    _ColorTable[1]  = Gray;
    _ColorTable["maroon"]  = Maroon;  _ColorTable[2]  = Maroon;
    _ColorTable["red"]     = Red;     _ColorTable[3]  = Red;
    _ColorTable["green"]   = Green;   _ColorTable[4]  = Green;
    _ColorTable["lime"]    = Lime;    _ColorTable[5]  = Lime;
    _ColorTable["olive"]   = Olive;   _ColorTable[6]  = Olive;
    _ColorTable["yellow"]  = Yellow;  _ColorTable[7]  = Yellow;
    _ColorTable["navy"]    = Navy;    _ColorTable[8]  = Navy;
    _ColorTable["blue"]    = Blue;    _ColorTable[9]  = Blue;
    _ColorTable["purple"]  = Purple;  _ColorTable[10] = Purple;
    _ColorTable["fuchsia"] = Fuchsia; _ColorTable[11] = Fuchsia;
    _ColorTable["teal"]    = Teal;    _ColorTable[12] = Teal;
    _ColorTable["aqua"]    = Aqua;    _ColorTable[13] = Aqua;
    _ColorTable["silver"]  = Silver;  _ColorTable[14] = Silver;
    _ColorTable["white"]   = White;   _ColorTable[15] = White;

/**** global constants ****/

  var _Prefix    = "BouncingBall";                            // image id prefix
  var _PixelSize = 5;                // defines the "natural" size of each pixel

  var _DisplayWidth  = 60;                              // display width [pixel]
  var _DisplayHeight = 45;                             // display height [pixel]

  var _Background = Black;                                   // background color
  var _Border     = Green;                                       // border color
  var _Ball       = Yellow;                                        // ball color

  var _BallX  = Math.floor(1 +  (_DisplayWidth-2)*Math.random()); // don't forget borders
  var _BallY  = Math.floor(1 + (_DisplayHeight-2)*Math.random());                 // dto.

  var _BallSpeed = 3;                 // max. ball displacement per "clock tick"
  var _BallDX = _BallSpeed * 2*(Math.random()-0.5);
  var _BallDY = _BallSpeed * 2*(Math.random()-0.5);
  var _BallThread = null;     // stores a reference to the ball animation thread

/*******************************************************************************
*                                                                              *
* _clearBall                            clears the ball at its actual position *
*                                                                              *
*******************************************************************************/

  function _clearBall () {
    _setPixel(_BallX,_BallY, _Background);
  };

/*******************************************************************************
*                                                                              *
* _drawBall                              draws the ball at its actual position *
*                                                                              *
*******************************************************************************/

  function _drawBall () {
    _setPixel(_BallX,_BallY, _Ball);
  };

/*******************************************************************************
*                                                                              *
* _proceed                         calculates and shows the next ball position *
*                                                                              *
*******************************************************************************/

  function _proceed () {
    _clearBall();
    if (_BallThread == null) return;                     // animation has stopped

    var newBallX = Math.round(_BallX + _BallDX);
      if (newBallX < 1)               {newBallX = 1-newBallX;                   _BallDX = -_BallDX};
      if (newBallX > _DisplayWidth-2) {newBallX = 2*(_DisplayWidth-2)-newBallX; _BallDX = -_BallDX};
    _BallX = newBallX;

    var newBallY = Math.round(_BallY + _BallDY);
      if (newBallY < 1)                {newBallY = 1-newBallY;                    _BallDY = -_BallDY};
      if (newBallY > _DisplayHeight-2) {newBallY = 2*(_DisplayHeight-2)-newBallY; _BallDY = -_BallDY};
    _BallY = newBallY;

    _drawBall();
  };

/*******************************************************************************
*                                                                              *
* _reset                                              sets new ball parameters *
*                                                                              *
*******************************************************************************/

  function _reset () {
    _BallX  = Math.floor(1 +  (_DisplayWidth-2)*Math.random()); // don't forget display borders!
    _BallY  = Math.floor(1 + (_DisplayHeight-2)*Math.random());                          // dto.

    _BallDX = _BallSpeed * 2*(Math.random()-0.5);
    _BallDY = _BallSpeed * 2*(Math.random()-0.5);
  };

/*******************************************************************************
*                                                                              *
* _setPixel                              sets the given pixel to a given color *
*                                                                              *
*******************************************************************************/

  function _setPixel (x,y, Color) {                      // no parameter checks!
    try {
      x++; y++;                  // really weird: JavaScript may produce "-0"!!!
      document.images[_Prefix+x+"_"+y].src = Color.src;
    } catch (Exception) {
      document.writeln("manipulation of Pixel ",x,",",y," failed!<br>");
    };
  };

/*******************************************************************************
*                                                                              *
* createDisplay                        sets up the "BouncingBall" display area *
*                                                                              *
*******************************************************************************/

  function createDisplay () {

  /**** construct cell template ****/

    var CellTemplate =
      "<img name=\"" + _Prefix + "[_]\" src=\"" + _Background.src + "\" " +
      "width=" + _PixelSize + " height=" + _PixelSize + ">";

  /**** construct row template ****/

    var RowTemplate = "  <tr><td nowrap height=" + _PixelSize + ">";
      for (var Col = 1; Col <= _DisplayWidth; Col++) {
        RowTemplate += CellTemplate.replace(/\[/,Col);
      };
    RowTemplate += "<\/td><\/tr>";

  /**** construct display table ****/

    document.writeln("<table border=0 cellspacing=0 cellpadding=0 width=" + (_DisplayWidth*_PixelSize) + ">");
    document.writeln("  <colgroup span=1><\/colgroup>");
      for (var Row = 1; Row <= _DisplayHeight; Row++) {
        document.writeln(RowTemplate.replace(/\]/g,Row));
      };
    document.writeln("<\/table>");

  /**** now draw arena borders ****/

    for (var i = 0; i < _DisplayWidth; i++) {
      _setPixel(i,0,                _Border);
      _setPixel(i,_DisplayHeight-1, _Border);
    };

    for (var i = 1; i < _DisplayHeight-1; i++) {
      _setPixel(0,i,               _Border);
      _setPixel(_DisplayWidth-1,i, _Border);
    };
  };

/*******************************************************************************
*                                                                              *
* hideBall                                 stops the "bouncing ball" animation *
*                                                                              *
*******************************************************************************/

  function hideBall () {
    if (_BallThread != null) {
      window.clearInterval(_BallThread); _BallThread = null;
      _clearBall();                                       // just to be complete
    };
  };

/*******************************************************************************
*                                                                              *
* resetBall                                     calculates new ball parameters *
*                                                                              *
*******************************************************************************/

  function resetBall () {
    if (_BallThread != null) {
      hideBall();                                           // suspend animation
        _reset();
      showBall();                                            // resume animation
    } else {
      _reset();                                // just reset the ball parameters
    };
  };

/*******************************************************************************
*                                                                              *
* showBall                                starts the "bouncing ball" animation *
*                                                                              *
*******************************************************************************/

  function showBall () {
    if (_BallThread == null) {
      _BallThread = window.setInterval("_proceed()",100);
    };
  };

