  /**
   * Stop the animation.
   */
  function stop() {
    //time_id holds the expression which calls the fwd or bkwd function
    if (anim_status == 1)
      clearTimeout (time_id);
    anim_status = 0;
  }

  /**
   * Step the animation forward in either loop or sweep mode.
   */
  function animateForward() {
    //increment image
    current_image++;

    //check if current image has exceeded loop bound
    if (current_image > last_image) {
      if (play_mode == 1) {
        //fwd loop mode - skip to first image
        current_image = first_image;
      }
      if (play_mode == 2) {
        //sweep mode - change directions (go bkwd)
        current_image = last_image;
        animateBackward();
        return;
      }
    }

    //display frame
    showFrame(current_image-first_image);

    delay_time = delay;
    if (current_image == first_image) delay_time = start_dwell_multiplier*delay;
    if (current_image == last_image) delay_time = end_dwell_multiplier*delay;

    //call animateForward() again after a set time (delay_time) has elapsed
    time_id = setTimeout("animateForward()", delay_time);
  }

  /**
   * Step the animation backward.
   */
  function animateBackward() {
    //decrement image number
    current_image--;

    //check if image number is before lower loop bound
    if (current_image < first_image) {
      if (play_mode == 1) {
        //bkwd loop mode - skip to last image
        current_image = last_image;
      }
      if (play_mode == 2) {
        //sweep mode - change directions (go fwd)
        current_image = first_image;
        animateForward();
        return;
      }
    }

    //display frame
    showFrame(current_image-first_image);

    delay_time = delay;
    if (current_image == first_image) delay_time = start_dwell_multiplier*delay;
    if (current_image == last_image) delay_time = end_dwell_multiplier*delay;

    //call animateBackward() again after a set amount of time (delay_time) has elapsed
    time_id = setTimeout("animateBackward()", delay_time);
  }

  /**
   * Changes playing speed by adding to or substracting from the delay between frames.
   */
  function changeSpeed(dv) {
    delay+=dv;
    //check to ensure max and min delay constraints have not been crossed
    if (delay > delay_max) delay = delay_max;
    if (delay < delay_min) delay = delay_min;
  }

  /**
   * Changes the dwell rate.
   */
  function changeDwellEnd(dv) {
    end_dwell_multiplier+=dv;
    if (end_dwell_multiplier < 1) end_dwell_multiplier = 1;
  }

  /**
   * Changes the dwell rate.
   */
  function changeDwellStart(dv) {
    start_dwell_multiplier+=dv;
    if (start_dwell_multiplier < 1) start_dwell_multiplier = 1;
  }

  /**
   * Increment to next image.
   */
  function incrementImage(number) {
    stop();

    //if image is last in loop, increment to first image
    if (number > last_image) number = first_image;

    current_image = number;

    //display frame
    showFrame(current_image-first_image);
  }

  /**
   * Decrement to next image.
   */
  function decrementImage(number) {
    stop();

    //if image is first in loop, decrement to last image
    if (number < first_image) number = last_image;

    current_image = number;

    //display frame
    showFrame(current_image-first_image);
  }

  /**
   * Play forward.
   */
  function playForward() {
    stop();
    anim_status = 1;
    play_mode = 1;
    animateForward();
  }

  /**
   * Play reverse.
   */
  function playBackward() {
    stop();
    anim_status = 1;
    play_mode = 1;
    animateBackward();
  }

  /**
   * Play sweep.
   */
  function playSweep() {
    stop();
    anim_status = 1;
    play_mode = 2;
    animateForward();
  }

  /**
   * Change play mode (normal, loop, swing).
   */
  function changeMode(mode) {
    play_mode = mode;
  }

  /**
   * Submit the control form resulting in a refresh.
   */
  function refresh() {
    var obj = getDOMObject('controlform');
    if (obj) obj.submit();
  }

  /**
   * Refresh with the new location.
   */
  function setLocation(type, code) {
    getDOMObject('lt').value=type;
    getDOMObject('lc').value=code;
    refresh();
  }

  /**
   * Refresh with the new location.
   */
  function setLocationAndImage(type, code, image) {
    getDOMObject('lt').value=type;
    getDOMObject('lc').value=code;
    getDOMObject('img').value=image;
    refresh();
  }

  /**
   * Set the displayed image to that at the given index.
   */
  function showFrame(i) {
    var img = getDOMObject('animation');
    var ts = getDOMObject('status_ts');

    if (img && ts) {

      if (fade == 1 && img.filters && i>0 && i<images.length-1) {
        img.style.filter="blendTrans(duration=speed)";
        img.style.filter="blendTrans(duration=crossFadeDuration)";
        img.filters.blendTrans.Apply();
      }

      img.src = images[i].src
      ts.innerHTML = dates[i];

      if (fade == 1 && img.filters && i>0 && i<images.length-1) {
        img.filters.blendTrans.Play();
      }

    }

  }

  /**
   * Toggle the animation mode.
   */
  function toggleAnimation() {
    var status = getDOMObject('anf');
    if (anim_status == 0) {
      playForward();
      if (status)
        status.value = 1;
    } else {
      stop();
      if (status)
        status.value = 0;
    }
    setControl();
  }

  /**
   * Toggle the animation mode.
   */
  function toggleMode() {
    var obj = getDOMObject('and');
    if (play_mode != 2) {
      playSweep();
      if (obj)
        obj.value = 2;
    } else {
      playForward();
      if (obj)
        obj.value = 1;
    }
    setControl();
  }

  /**
   * Set the symbol on the play control.
   */
  function setControl() {
    var control = getDOMObject('playcontrol');
    if (control) {
      if (anim_status == 0)
        control.src = '/images/widgets/anim_play.gif';
      else
        control.src = '/images/widgets/anim_pause.gif';
    }
    control = getDOMObject('modecontrol');
    if (control) {
      if (play_mode == 2)
        control.src = '/images/widgets/anim_mode_swing.gif';
      else
        control.src = '/images/widgets/anim_mode_loop.gif';
    }
  }

  /**
   * Clear the position display.
   */
  function clearDisplayPosition(e) {
    var status = getDOMObject('status_pos');
    var dist = getDOMObject('status_dist');
    if (status) status.innerHTML = ('&nbsp;');
    if (dist) dist.innerHTML = ('&nbsp;');
  }

  /**
   * Toggle a layer's display state.
   */
  function toggleLayer(layer, checkbox) {

    var obj = getDOMObject(layer);
    if (obj) {
      if (checkbox.checked)
        obj.style.visibility='visible';
      else
        obj.style.visibility='hidden';
    }

  }

  /**
   * Update the position display.
   */
  function updateDisplayPosition(e) {
    var status = getDOMObject('status_pos');
    var dist = getDOMObject('status_dist');
    var coords = getEventCoords(e);
    if (coords) {
      if (status) {
        status.innerHTML = (coords.x.toFixed(2)) + '&deg;E ' + (-coords.y.toFixed(2)) + '&deg;S ';
      }
      if (dist) {
        var vector = getVector(dm_x, dm_y, coords.x, coords.y);
        dist.innerHTML = vector.distance.toFixed(0) + 'km ' + vector.bearing.toFixed(0) + '&deg;';
      }
    }
  }
