
    var dirs = new Array();
    function get_directions_cached(startpoint, endpoint, donecallback, parent) {
      var hash = "" +startpoint+":"+endpoint;
      if (dirs[hash] == null) {
        var dirn = new GDirections(null, document.getElementById("dummy"));
        dirn.parent = parent;      
        GEvent.addListener(dirn,"load", donecallback);
        dirn.loadFromWaypoints([startpoint,endpoint],{getPolyline:true,getSteps:true,travelMode:G_TRAVEL_MODE_WALKING});
        dirs[hash] = dirn;
      } else {
        dirs[hash].parent = parent;
        donecallback.call(dirs[hash]);              
      }
    }
    
    
      function update_participant_point(p,step) {
        p.d += step;
        p.d_at_v += step
        while (p.d_at_v > p.d_to_next_v && p.v+2  < p.poly.getVertexCount()) {
            p.v++;
            if (p.v >= p.poly.getVertexCount()) {
              alert("bla");
            }
            p.d_at_v -= p.d_to_next_v;
            p.d_to_next_v = p.poly.getVertex(p.v).distanceFrom(p.poly.getVertex(p.v+1));
        }
        var movedPart = p.d_at_v / p.d_to_next_v;
        if (isNaN(movedPart)) {
          alert("NAN d to next:"+p.d_to_next_v+" numvertices:"+p.poly.getVertexCount()+" vertex no:"+p.v+" vertex1:"+p.poly.getVertex(p.v-1)+" vertex2:"+p.poly.getVertex(p.v));         
        }
        var newlat = (1.0 - movedPart) * p.poly.getVertex(p.v).lat() + movedPart * p.poly.getVertex(p.v+1).lat();
        var newlng = (1.0 - movedPart) * p.poly.getVertex(p.v).lng() + movedPart * p.poly.getVertex(p.v+1).lng();
          if (p.v+1 >= p.poly.getVertexCount()) {
            alert("bla2");
          }

        p.point = new GLatLng(newlat, newlng);
//        var shouldbe = p.poly.GetPointAtDistance(p.d);
//        console.log("is:"+p.point+" should:"+shouldbe);
      }
    


    var VoodooParticipant = Class.create({
    
    initialize: function(icon,startPoint, name, map) {
      log_it("new participant"+participantCount);
      this.id = participantCount++;
      this.voodooname = name;
      this.icon = icon;
      this.startPoint = startPoint;
      this.endPoint = null;
      this.parentMap = map;
      this.map = map;

      this.step = Math.random()*2+2; // metres

      this.poly;
      this.eol;
      this.d = 0;
      this.d_at_v = 0;
      this.d_to_next_v = 100;
      this.v = 0;

      this.isDancing = false;      
      this.starting = true;
      
      this.canMove = false;

     },
      loadCallback: function() {
        // haaaacckyyy
        this.parent.dirn = this;
        log_it("pid:"+this.parent.voodooname+" directions loaded callback");
        this.parent.poly=this.parent.dirn.getPolyline();
        this.parent.eol=this.parent.poly.Distance();
        this.parent.d = 0;
        this.parent.d_at_v = 0;
        this.parent.d_to_next_v = this.parent.poly.getVertex(0).distanceFrom(this.parent.poly.getVertex(1));
        this.parent.v = 0;
        update_participant_point(this.parent,0);
        log_it("name distance:"+this.parent.voodooname+" "+this.parent.eol);
//        map.addOverlay(new GMarker(poly.getVertex(0),G_START_ICON));
//        map.addOverlay(new GMarker(poly.getVertex(poly.getVertexCount()-1),G_END_ICON));
        if (this.parent.starting) {
//          this.map = this.parent.map;
          
          var marker = new GMarkerEx(this.parent.poly.getVertex(0),{icon: this.parent.icon, title:'<span style="position:relative; font-size:8pt; color: white; background-color: black; font-family: Arial,Helvetica,Garuda,sans-serif; text-align: left; align: left; filter: alpha(opacity=50); -moz-opacity: .5; -khtml-opacity: .5; opacity: .5;">'+this.parent.voodooname+'</span>',draggable:true});
//          marker.map_ = this.parent.map;
         
          this.parent.marker = marker;
          this.parent.parentMap.addOverlay(marker);
          marker.showPopup();

          this.parent.starting = false;
//          log_it("pid:"+this.id+" added marker to map");          
        }
//        else {
//          this.parent.marker.setPoint(this.parent.poly.getVertex(0));
//        }
//        this.parent.pauseFor = 500;
        this.parent.canMove = true;        
        document.getElementById("dummy").style.display = "none";
      },


      
       newEndPoint: function() {
         //do {
         var choice = Math.random();
         if (choice < 0.1/3.0) 
           this.endPoint = ecleticos;
         else
         if (choice < 0.2/3.0) 
           this.endPoint = paim;
         else
         if (choice < 2.8/3.0) 
           this.endPoint = trackers;
         else
         if (choice < 3.0/3.0) 
           this.endPoint = neto;
         //}; while (this.endPoint == this.startPoint);
       },
       
       startMoving: function() {
        this.canMove = false;
        this.isDancing = false;
        if (this.marker != null) {
          this.marker.setImage(normal_voodoo_image);
          this.marker.showPopup();
        }          
        log_it("pid:"+this.id+" startMoving() called");
        this.newEndPoint();
        if (this.endPoint == this.startPoint) {
//          log_it("PROBLEM!!!!");
            this.startDancing();
            return;
        }
        log_it("pid:"+this.id+" first endPoint calculated: "+this.endPoint);        
        get_directions_cached(this.startPoint, this.endPoint, this.loadCallback, this);            
       },

       dance: function() {
         var dancePoint = new GLatLng(this.endPoint.lat()+Math.random()*0.00006-0.00003, this.endPoint.lng()+Math.random()*0.00006-0.00003);
         this.marker.setPoint(dancePoint);
       },
       
       startDancing: function(doneDancingCall) {
         if (this.isDancing)
           return;
         this.canMove = false;
         this.isDancing = true;
         this.dance();
         this.marker.setImage(dancing_voodoo_image+"?a="+Math.random());
         this.marker.hidePopup();
         setTimeout(doneDancingCall, (((this.endPoint == ecleticos || this.endPoint == paim || this.endPoint == neto) ? 500: 240000)*Math.random()));
       },
       
    });
