/* Author     : Josh Grant

*/

#include <Xm/Xm.h>
#include <Xm/Form.h>

#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/sensors/SoTimerSensor.h>

#include <Interface.h>
#include <Scatter.h>
#include <iostream.h>
#include <math.h>

int   pnum    = 50;
float cradius = 4.0;
float dradius = 0.25;
float pradius = 0.05;
float speed   = 0.05;
float dmass   = 500.0;
float pmass   = 1.0;

// checkArgs() checks the command line arguments and assigns all variables
// not listed on command to zero.
int checkArgs(int myargc, char **myargv) {
  int i;
  
  for (i = 1; i < myargc; i += 2) {
    if (i + 1 == myargc) return 0;
 
    if (!strcmp(myargv[i], "-num"))
       pnum = atoi(myargv[i + 1]);
    else if (!strcmp(myargv[i], "-catch"))
       cradius = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "-dradius"))
       dradius = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "-dmass"))
       dmass = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "-pradius"))
       pradius = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "-pmass"))
       pmass = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "-speed"))
       speed = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "-h"))
      return 0;
    else if (!strcmp(myargv[i], "-help"))
      return 0;
    else
      return 0;
  }
  return 1;
}

void printUsage() {
  cout << "Usage - scatter" << endl;

  cout << "     -num int   : Total number of particles to be scattered, \n"
       << "                  default = 50\n"
       << "   -catch float : Distance from center of scene where particles\n"
       << "                  will be caught and have velocities set to 0,\n"
       << "                  default = 4.0\n"
       << " -dradius float : Radius of deflector to be injected into\n"
       << "                  particle volume. default = 0.25\n"
       << " -pradius float : Radius of each particle in volume,\n"
       << "                  default = 0.05\n"
       << "   -dmass float : Mass of deflector to be injected into particle\n"
       << "                  volume. default = 500.0\n"
       << "   -pmass float : Mass of each particle in volume,\n"
       << "                  default = 1.0\n"
       << "   -speed float : Rate at which the scene is updated,\n"
       << "                : default = 0.05\n"
       << "    -help       : this message\n"
       << endl;
}

void updateCB (void *data, SoSensor *) {
  Scatter *scatter = (Scatter *)data;
  scatter->update();
}


////////////////////////////////////////////////////////////
//
// The main program gets a window from X, 
// puts an interactive 3D examinerViewer in it, 
// attaches the scene graph to the viewer,
// renders the scene graph,
// and hands control over to the Inventor main loop.
void main(int argc, char **argv) {
  Interface *gui;
  Scatter scatter;
  SoTimerSensor *sensor;
  SoSeparator *root;

  srand48(getpid());
  
  if (!checkArgs(argc, argv)){
    printUsage();
    exit(1);
  }

  scatter.deflector->setRadius(dradius);
  scatter.deflector->mass  = dmass;
  scatter.catchRadius      = cradius;
  scatter.pset.radius      = pradius;
  scatter.pset.mass        = pmass;
  scatter.pset.particleNum = pnum;
  scatter.pset.updateSet();

  sensor = new SoTimerSensor(updateCB, &scatter);
  sensor->setInterval(SbTime(speed));

  gui = new Interface(&scatter, sensor);

  // Initialize Inventor and Xt
  Widget myWindow = SoXt::init("Scatter");
  Widget myForm   = XtCreateWidget("Form", xmFormWidgetClass, myWindow,
				     NULL, 0);

  SoXtExaminerViewer *myViewer = new SoXtExaminerViewer(myForm);

  // Lay out the components within the form
  Arg args[8];
  XtSetArg(args[0], XmNtopAttachment, XmATTACH_FORM);
  XtSetArg(args[1], XmNbottomAttachment, XmATTACH_FORM);
  XtSetArg(args[2], XmNleftAttachment, XmATTACH_POSITION);
  XtSetArg(args[3], XmNrightAttachment, XmATTACH_POSITION);
  XtSetArg(args[4], XmNrightPosition, 80);
  XtSetValues(myViewer->getWidget(), args, 5);

  gui->setInitial(dradius, dmass, pradius, pmass, pnum);
  Widget myControls = gui->makeGUI(myForm);

  root = scatter.makeScene();
  scatter.clear();

  myViewer->setSceneGraph(root);
  myViewer->show();

  SoXt::show(myControls);
  SoXt::show(myForm);
  SoXt::show(myWindow);
  SoXt::mainLoop();
}
