#include <iostream>
#include <iomanip>

#include <sstream>
#include <cstdlib> // für rand()

#include <vector>

using namespace std;

class Particle {
  double m_x, m_y, m_z;
public:
  Particle() {}
  Particle(double x, double y, double z) {
  }

  std::string toString() {
    std::ostringstream os;
    os << "Particle [" << std::setprecision(3) << m_x << "," << m_y << "," << m_z << "]";
    return os.str();
  }
};
    
class Atom : public Particle {
  std::string m_chemElement;
public:
  Atom() {}
  Atom(double x, double y, double z,
       const std::string &chemElement) {
  }
  std::string toString() {
    std::ostringstream os;
    os << "Atom " << m_chemElement;
    return os.str();
  }
};
    
class ChargedParticle : public Particle {
  double m_charge;
public:
  ChargedParticle() {}
  ChargedParticle(double x, double y, double z,
          double charge) {
  }
  std::string toString() {
    std::ostringstream os;
    os << "ChargedParticle (" << m_charge << " e)";
    return os.str();
  }
};
    
class Molecule : public Particle {
  vector<Atom> m_atoms;
public:
  Molecule() {}
  Molecule(double x, double y, double z, 
       vector<Atom> atoms) {
  }
  std::string toString() {
    std::ostringstream os;
    os << "Molecule (";
    for (int i = 0; i < m_atoms.size(); i++) {
      os << m_atoms[i].toString() << " ";
    }
    os << ")";
    return os.str();
  }
};
    
class ChargedMolecule : public ChargedParticle,
            public Molecule {
public:
  ChargedMolecule() {}
  ChargedMolecule(double x, double y, double z, 
          int charge, vector<Atom> atoms) {
  }
  std::string toString() {
    std::ostringstream os;
    os << "ChargedMolecule, composed of:";
    os << "  " << ChargedParticle::toString();
    os << "  " << Molecule::toString();
    return os.str();
  }
};


int main() {
  const int n_P = 12; // Anzahl der erzeugten und beobachteten Particles 

  vector < Particle *> vecp;


  srand(123456);

  // Zufällig Initialisierung
  for (int i = 0; i < n_P; i++) {
    Particle * p;

    double x = (double) rand() / RAND_MAX;
    double y = (double) rand() / RAND_MAX;
    double z = (double) rand() / RAND_MAX;

    if (z < 0.3) {
      p = new Particle(x,y,z);
    }
    else if (z < 0.6) { 
      p = new Atom(x,y,z, "H");
    } 
    else { 
      vector<Atom> atoms(3);
      atoms[0] = Atom(x,y,z, "H");
      atoms[1] = Atom(x,y,z, "H");
      atoms[2] = Atom(x,y,z, "O");
      p = new Molecule (x,y,z, atoms);
    }
    vecp.push_back( p );
  }

  
  /**** Schleife 1: ****/
  for (int i = 0; i < n_P; i++) {
    double x = (double) rand() / RAND_MAX;
    double y = (double) rand() / RAND_MAX;
    double z = (double) rand() / RAND_MAX;
    /*** Von der folgenden Zeile den Kommentar entfernen, um move zu testen! ***/
    //vecp[i]->move(x,y,z);
  }

  /***** Schleife 2: ****/
  for (int i = 0; i < n_P; i++) {
    cout << vecp[i]->toString() << "\n";
  }
}