///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Copyright (C) 2006 by Intel Corporation and Carnegie Mellon University    //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <errno.h>
#include <string.h>

#include "SandCast.hxx"
#include "CatomStick.hxx"
#include "CatomWorld.hxx"
#include "CatomSim.hxx"

CODE_MODULE_DECLARATION( SandCast, SandCast );

using namespace std;


static catomID simEndLeader = 0;

void SandCast::simulationStart() {
  CODE_MODULE(CatomStick)->set_mode(0);  // default all catoms to not stick
}


void SandCast::simulationEnd() {
  if (hostCatom==simEndLeader) {  // really a form of oracle end simulation
    string outfile;
    outfile = worldPtr->search_key_value_list( "SandCast_outfile" );
    if (outfile=="") return;
    fstream fs;
    fs.open( outfile.c_str(), fstream::out | fstream::trunc );
    hash_map<const unsigned long, CatomSim *, hash<const unsigned long>, equl>::iterator it;
    for (it = worldPtr->catomHash.begin(); it!=worldPtr->catomHash.end(); it++) {
      CatomSim* cs = it->second;
      Point3D p = cs->C.getLocation();
      fs << p.getX() << " " << p.getY() << " " << p.getZ() << "\n";
    }
    fs.close(); 
  }
}

static void touching( void *data, dGeomID o1, dGeomID o2 ) {
  CatomSim *c1 = (CatomSim*) dGeomGetData( o1 );
  CatomSim *c2 = (CatomSim*) dGeomGetData( o2 );
  if (c1) {
    REMOTE_CODE_MODULE(c1->C.getID(), CatomStick)->set_mode(1);
    c1->C.setColor( 0, 255, 0, 0 );
  }
  if (c2) {
    REMOTE_CODE_MODULE(c2->C.getID(), CatomStick)->set_mode(1);
    c2->C.setColor( 0, 255, 0, 0 );
  }
}

void SandCast::oracle() {
  // running concurrently with simulationStart
  oracleYield();
  // running with other oracles only
  hash_map<const unsigned long, CatomSim *, hash<const unsigned long>, equl>::iterator it;
  it = worldPtr->catomHash.begin();
  simEndLeader = it->second->C.getID();
  string infile;
  infile = worldPtr->search_key_value_list( "SandCast_infile" );
  if (infile=="") return;
  fstream fs;
  fs.open( infile.c_str(), fstream::in );
  dGeomID tmpobj = dCreateSphere( 0, CatomSim::catom_radius*0.1 );
  dGeomSetData( tmpobj, (void*) 0 );
  while (fs.good()) {
    double x,y,z;
    fs >> x >> y >> z;  // note: no error checking; should check for blank lines, partial lines, etc.
    // find all catoms that are close to x,y,z and make them stick
    dGeomSetPosition( tmpobj, x, y, z );
    dSpaceCollide2( tmpobj, (dxGeom*) (worldPtr->coll_space), 0, touching );
  }
  fs.close();
}
