// Copyright 2001 by Bob Kanefsky, developer@roving-mouse.com.

var reasonable_trajectory_interval = 100.0;

var next_trajectory_id = 0;

function make_movable (image, object) {
     if (!object) object = new movable_object();
     if (image) {
          object.image = image;
          image.object = object;
      }
     return object;
}

function set_in_motion (object, trajectory) {
   if (!object.moving_along_trajectories) object.moving_along_trajectories = new Array();
   if (!object.started_moving_along_trajectory) object.started_moving_along_trajectory = new Array();
   stop_motion (object, trajectory); ///// does this still stop other trajectories too?
   object.started_moving_along_trajectory[trajectory.id] = new Date();
   if (!object.trajectories) object.trajectories = new Array();
   // Note:  IE 5.1 on Mac does not support Array.push()
   object.trajectories[object.trajectories.length]=trajectory; // all known trajectories [slightly leaky]
   update_along_trajectory(object, trajectory); // immediately in case it's about to be displayed for first time
   object.moving_along_trajectories[trajectory.id] =
      // setInterval (update_along_trajectory, reasonable_trajectory_interval, object, trajectory);                                                                                    
      // Above is Netscape version.  Below theoreticaly works in IE 5+ on Windows
    my_setInterval (function () {update_along_trajectory(object, trajectory)}, reasonable_trajectory_interval);                                                                                    
  }

function my_setInterval (func, interval) {
   if (setInterval_function_pointer_okay)
     // This works in Netscape 4, Mozilla/NS6, and theoretically in IE 5 and 6 on Windows.
     return setInterval(func,interval)
  else {
    // IE 5.0 and 5.1 on Mac only take a string.
    n = ie_setInterval_functions.length;
    ie_setInterval_functions[n] = func;
    return setInterval ("ie_setInterval_functions["+n+"]"+"()", interval);
  }
}

function stop_motion (object, trajectory) {
    if (!trajectory)
     {
        for (i in object.trajectories)
           stop_motion(object, object.trajectories[i]);
     }
    else {
      if (object.moving_along_trajectories[trajectory.id])
         clearInterval(object.moving_along_trajectories[trajectory.id]);
      object.moving_along_trajectories[trajectory.id] = null;
   }
}

function update_along_trajectory (object, trajectory) {
   trajectory.update(object, new Date() - object.started_moving_along_trajectory[trajectory.id]);
}

function move_object_to (object, x, y) {
   move_object_component (object.image, x, y);
   move_object_component (object.hotspot, x, y);
   object.current_x = x; // if also using drag.js and it's a draggable burden, 
   object.current_y = y;  // act just as if moved with jump_object()
}

function move_object_component (component, x, y) {
   if (component) {
     pos = component.style;
     pos.position = "absolute";
     pos.left = Math.round(x);
     pos.top  = Math.round(y);
  }
}

function movable_object () {
   }

function browser_allows_motion (object) {
   if (!object) object = document.body;
   if (object && object.image) object = object.image;
   return !!(object && object.style)
}

/////////// Specific "classes" of trajectory:

function linear_trajectory (start_x, start_y, end_x, end_y, duration) {
   this.id = next_trajectory_id++;
   if (!duration) duration = 1000;
   this.update = function(object, ms) {
        if (ms > duration) {
                stop_motion(object, this);
                move_object_to(object, end_x, end_y);
           }
       else {
            percentage = ms/duration;
            move_object_to(object, start_x*(1-percentage) + end_x*percentage,
                                                               start_y*(1-percentage) + end_y*percentage)
                 }
    }
};

function circular_trajectory (center_x, center_y, radius, period, sign, aspect) {
   this.id = next_trajectory_id++;
   this.update = function(object, ms) {
        with (Math) {
           angle = 2*PI*ms/period;
           sine = sin(angle);
           if (sign=="positive") sine = abs(sine);
           if (sign=="negative") sine = -abs(sine);
           if (aspect) sine = aspect * sine;
           move_object_to(object, center_x + radius * cos(angle),
                                                             center_y + radius * sine)
    }}
};

function irregular_hop_trajectory (center_x, center_y, radius1, radius2, period, aspect) {
   this.id = next_trajectory_id++;
   this.update = function(object, ms) {
        with (Math) {
           angle = 2*PI*ms/period;
           offset = radius2 * cos(angle/19); // slower, repeating every 19 cycles
           if (!aspect) aspect = 1;
           move_object_to(object, center_x + (radius1 * cos(angle)) + offset,
                                                             center_y + radius1 * aspect*(-abs(sin(angle))))
    }}
};

function changing_size (start_w, start_h, end_w, end_h, duration) {  
   this.id = next_trajectory_id++;
   if (!duration) duration = 1000;
   this.update = function(object, ms) {
        if (ms > duration) {
                 stop_motion(object, this);
                 object.image.width = end_w;
                 object.image.height = end_h;
           }
         else {
            percentage = ms/duration;
            object.image.width = Math.round(start_w*(1-percentage) + end_w*percentage);
            object.image.height = Math.round(start_h*(1-percentage) + end_h*percentage);
                 }
    }
};

var ie_setInterval_functions = new Array();
var setInterval_function_pointer_okay = false; // true in NS4, NS6, WinIE 5+; false in MacIE

setTimeout(function () {setInterval_function_pointer_okay = true}, 1)
