/////////////////////////////////////////////////////////////
//                                                         //
// Copyright (c) 2007-2017 by The University of Queensland //
// Centre for Geoscience Computing                         //
// http://earth.uq.edu.au/centre-geoscience-computing      //
//                                                         //
// Primary Business: Brisbane, Queensland, Australia       //
// Licensed under the Open Software License version 3.0    //
// http://www.apache.org/licenses/LICENSE-2.0              //
//                                                         //
/////////////////////////////////////////////////////////////

#include <boost/version.hpp>
#include <iostream>
#include <fstream>
#include <sstream>
#include "MNTable2DPy.h"

using namespace std;

using namespace boost::python;

    using boost::python::arg;
    void exportMNTable2D()
    {
      // Disable autogeneration of C++ signatures (Boost 1.34.0 and higher)
      // for Epydoc which stumbles over indentation in the automatically generated strings.
      boost::python::docstring_options no_autogen(true,false);

      class_<MNTable2D>(
        "MNTable2D",
        "A multi-group neighbour table for constructing 2D particle assemblies",
        init<>()
      )
      .def(init<const MNTable2D &>())
      .def(
        init<Vector3&,Vector3&,double, unsigned int>(
          ( boost::python::arg("minPoint"), boost::python::arg("maxPoint"), boost::python::arg("gridSize"), boost::python::arg("numGroups")=1 ),
          "Constructs a neighbour table with specified bounds, cell size and initial number of particle groups.\n"
          "@type minPoint: L{Vector3}\n"
          "@kwarg minPoint: lower-left point of the particle region\n"
          "@type maxPoint: L{Vector3}\n"
          "@kwarg maxPoint: upper-right point of the particle region\n"
          "@type gridSize: double\n"
          "@kwarg gridSize: the cell size for neighbour searches\n"
          "@type numGroups: unsigned int\n"
          "@kwarg numGroups: the initial number of groups (default: 1)\n"
        )
      )
      .def(
        "tagParticlesAlongLine",
        &MNTable2D::tagParticlesAlongLine,
        ( boost::python::arg("line"), boost::python::arg("distance"), boost::python::arg("tag"), boost::python::arg("groupID")=0 ),
        "Assigns the specified tag to all particles from group C{groupID}\n"
        "that lie within the specified distance of the given line.\n"
        "@type line: L{Line2D}\n"
        "@kwarg line: the line along which to tag particles\n"
        "@type distance: double\n"
        "@kwarg distance: the maximum distance between tagged particles and the line\n"
        "@type tag: int\n"
        "@kwarg tag: the tag to assign particles\n"
        "@type groupID: unsigned int\n"
        "@kwarg groupID: the group ID of particles to tag (default: 0)\n"
        "@rtype: void\n"
      )
      .def(
        "tagParticlesAlongLineWithMask",
        &MNTable2D::tagParticlesAlongLineWithMask,
        ( boost::python::arg("line"), boost::python::arg("distance"), boost::python::arg("tag"), boost::python::arg("mask"), boost::python::arg("groupID")=0 ),
        "Assigns the specified tag to all particles from group C{groupID}\n"
        "that lie within the specified distance of the given line.\n"
        "@type line: L{Line2D}\n"
        "@kwarg line: the line along which to tag particles\n"
        "@type distance: double\n"
        "@kwarg distance: the maximum distance between tagged particles and the line\n"
        "@type tag: int\n"
        "@kwarg tag: the tag to assign particles\n"
        "@type mask: int\n"
        "@kwarg mask: the mask - determines which bits of the tag are influenced \n"
        "@type groupID: unsigned int\n"
        "@kwarg groupID: the group ID of particles to tag (default: 0)\n"
        "@rtype: void\n"
      )
      .def(
        "tagParticlesAlongLineSegment",
        &MNTable2D::tagParticlesAlongLineSegment,
        ( boost::python::arg("linesegment"), boost::python::arg("distance"), boost::python::arg("tag"), boost::python::arg("mask"), boost::python::arg("groupID")=0 ),
        "Assigns the specified tag to all particles from group C{groupID}\n"
        "that lie within the specified distance of the given line segment.\n"
        "@type line: L{Line2D}\n"
        "@kwarg line: the line along which to tag particles\n"
        "@type distance: double\n"
        "@kwarg distance: the maximum distance between tagged particles and the line\n"
        "@type tag: int\n"
        "@kwarg tag: the tag to assign particles\n"
        "@type mask: int\n"
        "@kwarg mask: the mask - determines which bits of the tag are influenced \n"
        "@type groupID: unsigned int\n"
        "@kwarg groupID: the group ID of particles to tag (default: 0)\n"
        "@rtype: void\n"
      )
      .def(
        "tagParticlesNear",
        &MNTable2D::tagParticlesNear,
        ( boost::python::arg("point"), boost::python::arg("distance"), boost::python::arg("tag"), boost::python::arg("groupID")=0 ),
        "Assigns the specified tag to all particles from group C{groupID}\n"
        "that lie within the specified distance of the given point.\n"
        "@type point: L{Vector3}\n"
        "@kwarg point: the point around which to tag particles\n"
        "@type distance: double\n"
        "@kwarg distance: the maximum distance between tagged particles and the specified point\n"
        "@type tag: int\n"
        "@kwarg tag: the tag to assign particles\n"
        "@type groupID: unsigned int\n"
        "@kwarg groupID: the group ID of particles to tag (default: 0)\n"
        "@rtype: void\n"
      )
      .def(
        "tagClosestParticle",
        &MNTable2D::tagClosestParticle,
        ( boost::python::arg("point"), boost::python::arg("tag"), boost::python::arg("groupID")=0 ),
        "Assigns the specified tag to the particle which is closest to the given point.\n"
        "@type point: L{Vector3}\n"
        "@kwarg point: the point closest to the particle to be tagged\n"
	"@type tag: int\n"
        "@kwarg tag: the tag to assign closest particle\n"
        "@type groupID: unsigned int\n"
        "@kwarg groupID: the group ID of particle to tag (default: 0)\n"
        "@rtype: void\n"
      )
      .def(
        "breakBondsAlongLineSegment",
        &MNTable2D::breakBondsAlongLineSegment,
        ( boost::python::arg("lineSegment"), boost::python::arg("distance"), boost::python::arg("tag"), boost::python::arg("groupID")=0 ),
        "Breaks bonds within the specified distance of the given line segment.\n"
        "Only bonds with the specified tag connecting particles in the\n"
        "specified group will be broken.\n"
        "@type lineSegment: L{LineSegment2D}\n"
        "@kwarg lineSegment: the line segment along which to break bonds\n"
        "@type distance: double\n"
        "@kwarg distance: the maximum distance between bonds and the line segment\n"
        "@type tag: int\n"
        "@kwarg tag: the bond tag of bonds to break\n"
        "@type groupID: unsigned int\n"
        "@kwarg groupID: the group ID of particles whose bonds are broken (default: 0)\n"
        "@rtype: void\n"
      )
      .def(
        "generateBonds",
        &MNTable2D::generateBonds,
        (boost::python::arg("groupID")=0, boost::python::arg("tolerance"), boost::python::arg("bondID") ),
        "Generates bonds between particle pairs separated by less than the specified tolerance\n"
        "@type groupID: int\n"
        "@kwarg groupID: the group ID of particles to bond together (default: 0)\n"
        "@type tolerance: double\n"
        "@kwarg tolerance: maximum distance separating bonded particles\n"
        "@type bondID: int\n"
        "@kwarg bondID: the bond ID to assign generated bonds\n"
        "@rtype: void\n"
      )
      .def(
        "generateBondsWithMask",
        &MNTable2D::generateBondsWithMask,
        (boost::python::arg("groupID")=0, boost::python::arg("tolerance"), boost::python::arg("bondID"), boost::python::arg("tag"), boost::python::arg("mask") ),
        "Generates bonds between particle pairs separated by less than the specified tolerance.\n"
        "A tag mask is used to select groups of particles to tag.\n"
        "@type groupID: int\n"
        "@kwarg groupID: the group ID of particles to bond together (default: 0)\n"
        "@type tolerance: double\n"
        "@kwarg tolerance: maximum distance separating bonded particles\n"
        "@type bondID: int\n"
        "@kwarg bondID: the bond ID to assign generated bonds\n"
        "@type tag: int\n"
        "@kwarg tag: the tag of particles to bond\n"
        "@type mask: int\n"
        "@kwarg mask: the bond mask\n"
        "@rtype: void\n"
      )
      .def(
        "generateBondsTaggedMasked",
        &MNTable2D::generateBondsTaggedMasked,
        (boost::python::arg("groupID")=0, boost::python::arg("tolerance"), boost::python::arg("bondID"), boost::python::arg("tag1"), boost::python::arg("mask1"), boost::python::arg("tag2"), boost::python::arg("mask2") ),
        "Generates bonds between particle pairs separated by less than the specified tolerance.\n"
        "A tag mask is used to select groups of particles to tag.\n"
        "@type groupID: int\n"
        "@kwarg groupID: the group ID of particles to bond together (default: 0)\n"
        "@type tolerance: double\n"
        "@kwarg tolerance: maximum distance separating bonded particles\n"
        "@type bondID: int\n"
        "@kwarg bondID: the bond ID to assign generated bonds\n"
        "@type tag1: int\n"
        "@kwarg tag1: the 1st particle tag\n"
        "@type mask1: int\n"
        "@kwarg mask1: the mask for the 1st particle tag\n"
        "@type tag2: int\n"
        "@kwarg tag2: the 2nd particle tag\n"
        "@type mask2: int\n"
        "@kwarg mask2: the mask for the 2nd particle tag\n"
        "@rtype: void\n"
      )
      .def(
        "generateRandomBonds",
        &MNTable2D::generateRandomBonds,
        (boost::python::arg("groupID"), boost::python::arg("tolerance"), boost::python::arg("probability"), boost::python::arg("bondID"), boost::python::arg("tag"), boost::python::arg("mask") ),
        "Generates bonds between particle pairs separated by less than the specified tolerance.\n"
        "Bonds are generated between particle pairs with the prescribed probability.\n"
        "@type groupID: int\n"
        "@kwarg groupID: the group ID of particles to bond together (default: 0)\n"
        "@type tolerance: double\n"
        "@kwarg tolerance: maximum distance separating bonded particles\n"
        "@type probability: double\n"
        "@kwarg probability: probability that a particle-pair is bonded (0.0 < probability < 1.0)\n"
        "@type bondID: int\n"
        "@kwarg bondID: the bond ID to assign generated bonds\n"
        "@type tag: int\n"
        "@kwarg tag: the tag of particles to bond\n"
        "@type mask: int\n"
        "@kwarg mask: the bond mask\n"
        "@rtype: void\n"
      ) 
      .def(
        "generateClusterBonds",
        &MNTable2D::generateClusterBonds,
        (boost::python::arg("groupID")=0, boost::python::arg("tolerance"), boost::python::arg("bondTag1"), boost::python::arg("bondTag2")),
        "Generates bonds between particle pairs separated by less than the specified tolerance.\n"
	"Bonds generated between particles having the same particle tag are given tag C{bondTag1}\n"
        "and bonds generated between particles of differing tags are given tag C{bondTag2}\n"
        "@type groupID: int\n"
        "@kwarg groupID: the group ID of particles to bond together (default: 0)\n"
        "@type tolerance: double\n"
        "@kwarg tolerance: maximum distance separating bonded particles\n"
        "@type bondTag1: int\n"
        "@kwarg bondTag1: the bond tag for bonds between particles with the same particle tag\n"
        "@type bondTag2: int\n"
        "@kwarg bondTag2: the bond tag for bonds between particles with differing particle tags\n"
	)
      .def(
        "getSumVolume",
        &MNTable2D::getSumVolume,
        ( boost::python::arg("groupID")=0 ),
        "Returns the sum of the particle areas in the specified group.\n"
        "@type groupID: int\n"
        "@kwarg groupID: the group ID of particles whose areas are summed (default: 0).\n"
        "@rtype: double\n"
      )
      .def(
        "getNumParticles",
        &MNTable2D::getNrParticles,
        ( boost::python::arg("groupID")=0 ),
        "Returns the number of the particles in the specified group.\n"
        "@type groupID: int\n"
        "@kwarg groupID: the group ID of the particles to count (default: 0).\n"
        "@rtype: int\n"
      )
      .def(
        "setOutputPrecision",
        &MNTable2D::SetOutputPrecision,
        ( boost::python::arg("precision")),
        "Set the number of significant digits for file output\n"
        "@type precision: int\n"
        "@kwarg precision: the number of significant digits (default: 10).\n"
      )
      .def(
        "write",
        &MNTable2D::write,
        ( boost::python::arg("fileName"), boost::python::arg("outputStyle") ),
        "Writes the particle assembly and bonding information to the specified\n"
        "file using the specified output style (0: debug; 1: geo; 2: vtk)\n"
        "@type fileName: string\n"
        "@kwarg fileName: the name of the file to write\n"
        "@type outputStyle: int\n"
        "@kwarg outputStyle: output style (0: debug; 1: geo; 2: vtk)\n"
        "@rtype: void\n"
      )
      .def(
	"tagParticlesToClosest",
	&MNTable2D::tagParticlesToClosest,
	( boost::python::arg("groupID1")=0, boost::python::arg("groupID2") ),
	"Tags particles in C{groupID1} closest to spheres in C{groupID2}\n"
        "@type groupID1: int\n"
        "@kwarg groupID1: the group ID of particles to tag (default: 0).\n"
        "@type groupID2: int\n"
        "@kwarg groupID2: the group ID of closest spheres.\n"
      )
      .def(
	"tagParticlesInVolume",
	&MNTable2D::tagParticlesInVolume,
	( boost::python::arg("volume"), boost::python::arg("tag"), boost::python::arg("groupID")=0 ),
        "Assigns the specified tag to all particles from group C{groupID}\n"
        "that lie within the specified volume.\n"
        "@type volume: L{AVolume}\n"
        "@kwarg volume: the volume within which to tag particles\n"
        "@type tag: int\n"
        "@kwarg tag: the tag to assign particles\n"
        "@type groupID: unsigned int\n"
        "@kwarg groupID: the group ID of particles to tag (default: 0)\n"
        "@rtype: void\n"
      )
      .def(
	"insert",
	&MNTable2D::insert,
	( boost::python::arg("sphere"), boost::python::arg("groupID")=0 ),
	"Inserts sphere\n"
        "@type sphere: L{Sphere}\n"
        "@kwarg sphere: the sphere to insert\n"
        "@type groupID: int\n"
        "@kwarg groupID: the group ID of the inserted sphere (default: 0).\n"
      )
      .def(
        "insertBond",
        &MNTable2D::insertBond,
        ( boost::python::arg("Id1"), boost::python::arg("Id2"), boost::python::arg("tag") ),
        "Inserts bond between particles with the specified particle IDs\n"
        "@type Id1: int\n"
        "@kwarg Id1: ID of first particle to bond\n"
        "@type Id2: int\n"
        "@kwarg Id2: ID of second particle to bond\n"
        "@type tag: int\n"
        "@kwarg tag: the bond tag to assign to the generated bond\n"
      ) 
      .def(
	   "removeTaggedParticles",
	   &MNTable2D::removeTagged,
	   (boost::python::arg("groupID")=0,boost::python::arg("tag"),boost::python::arg("mask")),
	   "Removes particles with given tag and mask\n"
           "@type groupID: int\n"
           "@kwarg groupID: the group ID of particles to remove (default: 0).\n"
           "@type tag: int\n"
           "@kwarg tag: the tag of particles to remove.\n"
           "@type mask: int\n"
           "@kwarg mask: the tag mask of particles to remove.\n"
      )
      .def(
        "GrowNGroups",
        &MNTable2D::GrowNGroups,
        ( boost::python::arg("numGroups") ),
        "Expands the neighbour table to permit the specified number of particle groups\n"
        "@type numGroups: int\n"
        "@kwarg numGroups: number of groups to create\n"
        "@rtype: void\n"
      )
      .def(
        "getSphereListFromGroup",
        &MNTable2D::getSphereListFromGroup,
        ( boost::python::arg("groupID")=0 ),
        "Returns a python list of L{Sphere} objects with the specified group ID\n"
        "@type groupID: int\n"
        "@kwarg groupID: the group ID of spheres to return as a list (default: 0)\n"
        "@rtype: boost::python::list\n"
      )
      .def(
        "getBondList",
        &MNTable2D::getBondList,
        ( boost::python::arg("groupID")=0 ),
        "Returns a python list of bonds with the specified group ID as int-int pairs \n"
        "@type groupID: int\n"
        "@kwarg groupID: the bond tag\n"
        "@rtype: boost::python::list\n"
      )
      .def(self_ns::str(self))
      ;
    }



