///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Copyright (C) 2006 by Intel Corporation and Carnegie Mellon University    //
// Contacts: casey.j.helfrich @ intel.com                                    //
//           bdr @ cs.cmu.edu                                                //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#ifndef __CATOMWORLD_HXX
#define __CATOMWORLD_HXX

#include <pthread.h>

#include <ext/hash_set>
#include "Catom.hxx"
#include <map>
#include <ext/hash_map>
#include "StateFile/BasicTypes.hxx"
#include "StateFile/StateFile.hxx"
#include "StateFile/Modules.hxx"
#include <ode/ode.h>

using namespace std;
using namespace __gnu_cxx;

class CatomSim;

namespace __gnu_cxx {
  template<> struct hash<const long unsigned int> {
    size_t operator()(const long unsigned int &x) const {
      return (size_t)x;
    }
  };
}

struct equl {
  bool operator()(const unsigned long ul1, const unsigned long ul2) const {
    return (ul1 == ul2);
  }
};


class object_color {
public:
  uint8 red;
  uint8 green;
  uint8 blue;
  uint8 alpha;
};


//WARNING: only reliable when hashing locations of
//catoms in the lattice!
//WARNING: assumes radius of catoms is 1.0
struct HashPoint3D { //used in loadPointHash
  size_t operator() (const Point3D&a) const {
    hash<char*> H;
    char stringVersion[100];
    int x = (int)(a.getX());
    int y = (int)(a.getY());
    int z = (int)(a.getZ());
    sprintf(stringVersion, "%d,%d,%d", x, y, z);
    return H(stringVersion);
  }
};

struct EqualPoint3D { //used in loadPointHash
  bool operator() (const Point3D&x, const Point3D&y) const {
    return x == y;
  }
};


// Takes the 'path' to a dpr or world file and fills up the 'targetMap' with points
// corresponding to the locations of catoms in the world
// return true on success, false otherwise
bool loadPointHash(string path, hash_set<Point3D, HashPoint3D, EqualPoint3D>& targetMap);



///////////////////////////////////////////////////////////////////////////////
// CatomWorld
//
// The Simulated CatomWorld contains universal constants and an rTree of 
// CatomSims. It has the ability to poulate and save the rTree state.

class CatomWorld {
public:
  
  // Physics stuff
  dWorldID dyn_world;   // world for dynamic simulation
  dSpaceID coll_space;  // space for doing collision detection
  dSpaceID neigh_space; // space for determining proximity and neighbors
  dSpaceID mag_space;   // space for determining proximity for magnets and contacts

  // non-catom objects in the world
  map<dGeomID,object_color*> other_objects;

  // Lines in the world
  vector<DPRLine> lines;
  void addLine(catomID, catomID);
  void addLine(catomID, catomID, unsigned int, unsigned int, unsigned int);
  void clearLine(catomID, catomID);
  
  void addLine(catomID, Point3D);
  void addLine(catomID, Point3D, unsigned int, unsigned int, unsigned int);
  void clearLine(catomID, Point3D);
  
  void listLines();
  void clearLines();
  void clearLines(catomID);

  
  // Persistent file and (_sim) module
  StateFile::File myFile;
  StateFile::Module *myModule;
  
  // Variables for commandline and experiment file options
  string worldFile;
  string experimentFile;
  int seed;
  bool pov_visualize;
  string res_x; 
  string res_y;
  string camera;
  string camera_look;
  bool save_pov;
  int save;
  int timesteps;
  bool use_physics;
  bool use_cylinder;
  bool use_faceted;
  double gravity;
  double bounce;
  double friction;
  double ground_friction;
  bool use_ground_friction;
  bool show_features;
  double phys_time_step;
  double sim_time_step;
  string modules_list;
  string featureMapType;
  unsigned int num_catoms;
  static unsigned int lattice_type;
  static unsigned int num_features;
  static unsigned int num_neighbors;
  
  long int current_time;

  // list of all GUIDs in "pseudorandom" order (volitile)
  vector< unsigned long > thread_schedule;
  
  vector< pair<string, string> > key_value_list;
  string search_key_value_list( string key );
  
  // hash of pointers to all CatomSim objects
  hash_map<const unsigned long, CatomSim *, hash<const unsigned long>, equl> catomHash;
  
  static pthread_mutex_t worldLock;
  static pthread_mutex_t logLock;
  
  // oracle()
  void oracle( void *vargp ) {};
  
  // World operations
  void createThreadSchedule();
  void lockWorld();
 
  //Worldbuilder uses these functions
  void clearCatoms();
  void deleteCatom(unsigned long int GUID);
  CatomSim* getCatom(unsigned long int GUID);
  bool addCatom(CatomSim* c, unsigned long int GUID); 
  unsigned long int catomAt(Point3D pos);
  void swap(unsigned long int GUID1, unsigned long int GUID2);
  
  // File operations
  bool loadExperiment( vector<string> &options );
  bool loadWorld();
  bool saveWorld();
  
  // Printing and logging functions
  void oStart( void ) { manageLock(&logLock,"StartLog",true); }
  void oEnd( void ) { manageLock(&logLock,"Endlog",false); }
  void manageLock( pthread_mutex_t*, const char*, bool ) const;
  
  // Graphics introspection
  void (*threadStart)();
  void (*getView)(float xyz[3], float hpr[3], void *rgb);
 
  // Constructor
  CatomWorld();
  
  // Destructor
  ~CatomWorld();
};

#endif  /* End __CATOMWORLD_H */
