#include <ParticleSet.h>
#include <iostream.h>

ParticleSet::ParticleSet () {
  particleNum =   0;
  radius      = 0.1;
  mass        = 0.1;
  comp        = 0.2;

  nodeCreated = false;

  //makeNode();
}

ParticleSet::ParticleSet (int pnum, float rad, float ma) {
  particleNum = pnum;
  radius      = rad;
  mass        = ma;
  comp        = 0.2;
  nodeCreated = false;
  //makeNode();
};

ParticleSet::~ParticleSet () {
  int i, num;
  SoParticle *part;

  num = pset->getNumChildren();
  for (i = 0; i < num; i++) {
    part = (SoParticle *)pset->getChild(i);
    delete part;
  }
  pset->unref();
  material->unref();
  complexity->unref();
  root->unref();
}

SoSeparator* ParticleSet::getNewSet () {
  makeNode();

  nodeCreated = true;

  return root;
}

void ParticleSet::makeNode () {
  float r, g, b;
  int i;
  SoParticle *particle;
  
  root = new SoSeparator();

  complexity = new SoComplexity();
  complexity->value.setValue(comp);
  root->addChild(complexity);

  material = new SoMaterial();
  r = drand48();
  g = drand48();
  b = drand48();
  material->diffuseColor.setValue(SbColor(r, g, b));
  root->addChild(material);

  pset = new SoSeparator();
  for (i = 0; i < particleNum; i++) {
    particle = makeParticle();
    if (particle != NULL)
      pset->addChild(particle);
  }
  root->addChild(pset);
}

void ParticleSet::updateSet () {
  int currNum, i;
  SoParticle *particle;

  if (nodeCreated) {
  
    complexity->value.setValue(comp);

    currNum = pset->getNumChildren();
    if (currNum > particleNum) {
      for (i = currNum - 1; i >= particleNum; i--)
        pset->removeChild(i);
    } else if (currNum < particleNum) {
      for (i = currNum; i <= particleNum; i++) {
        particle = makeParticle();
        if (particle != NULL)
          pset->addChild(particle);
      }
    }

    currNum = pset->getNumChildren();
    for (i = 0; i < currNum; i++) {
      particle = (SoParticle *)(pset->getChild(i));
      particle->setRadius(radius);
      particle->mass = mass;
    }
  }
}

SoParticle* ParticleSet::makeParticle () {
  SoParticle *particle;
  SbVec3f pos;

  if (findPosition(pos)) {
    particle = new SoParticle();
    particle->setRadius(radius);
    particle->mass = mass;
    particle->setLocation(pos);

    return particle;
  } else
    return NULL;
}

int ParticleSet::findPosition (SbVec3f &pos) {
  int count = 0;
  float x, y, z, distance;

  while (count < MAX_TRIES) {
    x = drand48()*2.0 - 1.0;
    y = drand48()*2.0 - 1.0;
    z = drand48()*2.0 - 1.0;
    distance = x*x + y*y + z*z;
    if (distance < 1.0 && !overlap(SbVec3f(x, y, z))) {
      pos.setValue(x, y, z);
      return 1;
    }
    count++;
  }
  return 0;
}

int ParticleSet::overlap (SbVec3f pos) {
  int i, num;
  SoParticle *part;
  float rads, dist;

  num = pset->getNumChildren();
  for (i = 0; i < num; i++) {
    part = (SoParticle *)pset->getChild(i);
    
    dist = (part->getLocation() - pos).length();
    rads = radius * 2.0;

    if (dist <= rads)
      return 1;
  }
  return 0;
}

