#include <assert.h>
#include <ode-dbl/ode.h>
using namespace osg;
namespace lpzrobots {
  
  
  
  
  
  Nimm4::Nimm4(const OdeHandle& odeHandle, const OsgHandle& osgHandle,
               const std::string& name,
               double size, double force , double speed,
               bool sphereWheels )
    : 
      OdeRobot(odeHandle, osgHandle, name, "$Id$")
  {
    
    created=false;
    
    
    this->osgHandle.color = Color(2, 156/255.0, 0, 1.0f);
    
    max_force   = force*size*size;
    
    this->speed = speed;
    this->sphereWheels = sphereWheels;
    height=size;
    length=size/2.5; 
    width=size/2;  
    radius=size/6; 
    wheelthickness=size/20; 
    cmass=8*size;  
    wmass=size;    
    sensorno=4;    
    motorno=4;     
    segmentsno=5;  
    wheelsubstance.toRubber(50);
  };
  void Nimm4::setMotorsIntern(const double* motors, int motornumber){
    assert(created); 
    
    
    
    int len = (motornumber < motorno)? motornumber : motorno;
    
    
    for (int i=0; i<len; i++){
      joints[i]->setParam(dParamVel2, motors[i]*speed);
      joints[i]->setParam(dParamFMax2, max_force);
    }
  };
  int Nimm4::getSensorsIntern(
sensor* sensors, 
int sensornumber){
 
    assert(created); 
    
    
    
    int len = (sensornumber < sensorno)? sensornumber : sensorno;
    
    for (int i=0; i<len; i++){
      sensors[i]=dynamic_cast<Hinge2Joint*>(joints[i])->getPosition2Rate();
      sensors[i]/=speed;  
    }
    
    return len;
  };
    
    
    
    p2 = pose * Matrix::translate(
Vec3(0, 0, width*0.6));
    create(p2);
  };
  void Nimm4::update() {
    OdeRobot::update();
    assert(created); 
    for (int i=0; i<segmentsno; i++) { 
      objects[i]->update();
    }
    for (int i=0; i < 4; i++) { 
      joints[i]->update();
    }
  };
    if (created) {  
      destroy();
    }
    
    odeHandle.createNewSimpleSpace(parentspace, true);
    objects.resize(5);  
    joints.resize(4); 
    OdeHandle wheelHandle(odeHandle);
    
    wheelHandle.substance = wheelsubstance;
    
    
    
    
    
    Capsule* cap = new Capsule(width/2, length);
    cap->setTexture("Images/wood.rgb");
    cap->init(odeHandle, cmass, osgHandle);
    cap->setPose(Matrix::rotate(-M_PI/2, 0, 1, 0) * pose);
    objects[0]=cap;
    
    
    for (int i=1; i<5; i++) {
      
      
      
      
      
      Sphere* sph = new Sphere(radius);
      sph->setTexture("Images/wood.rgb");
      sph->init(wheelHandle, wmass, osgHandle.changeColor(Color(0.8,0.8,0.8)));
      Vec3 wpos = 
Vec3( ((i-1)/2==0?-1:1)*length/2.0,
 
                        ((i-1)%2==0?-1:1)*(width*0.5+wheelthickness),
                        -width*0.6+radius );
      sph->setPose(Matrix::rotate(M_PI/2, 0, 0, 1) * Matrix::translate(wpos) * pose);
      objects[i]=sph;
    }
    
    for (int i=0; i<4; i++) {
      Pos anchor(dBodyGetPosition (objects[i+1]->getBody()));
      joints[i] = new Hinge2Joint(objects[0], objects[i+1], anchor, Axis(0,0,1)*pose, Axis(0,1,0)*pose);
      joints[i]->init(odeHandle, osgHandle, true, 2.01 * radius);
    }
    for (int i=0; i<4; i++) {
      
      joints[i]->setParam(dParamLoStop, 0);
      joints[i]->setParam(dParamHiStop, 0);
    }
    created=true; 
  };
  void Nimm4::destroy(){
    if (created){
      cleanup();
      odeHandle.deleteSpace(); 
    }
    created=false; 
  }
}