"""
The U{SimTK core<https://simtk.org/home/simtkcore>} 
multibody mechanics biosimulation tool kit.

The C{simtk} package provides python bindings for the 
U{SimTK<https://simtk.org/home/simtkcore>} biosimulation tool kit.

X{SimTK} brings together in a robust, convenient, open source form the 
collection of highly-specialized technologies necessary to building 
successful physics-based simulations of biological structures. These 
include: strict adherence to an important set of abstractions and 
guiding principles, robust, high-performance numerical methods, 
support for developing and sharing physics-based models, and careful 
software engineering.

B{Citation:}

Any work that uses SimTK Core (including Simbody) should cite the following paper: 
I{Jeanette P. Schmidt, Scott L. Delp, Michael A. Sherman, Charles A. Taylor,
Vijay S. Pande, Russ B. Altman, 
"The Simbios National Center: SystemsBiology in Motion", Proceedings of the IEEE,
special issue on Computational System Biology. Volume 96, Issue 8:1266 - 1280. 
(2008)}

Publications that make use of this software should also acknowledge
the NIH Center for Physics-Based Simulation of Biological Structures 
(Simbios) with NIH Roadmap U54 GM072970.
"""
__docformat__ = "epytext en"

__author__ = "Christopher M. Bruns"
__copyright__ = "Copyright 2010, Stanford University and Christopher M. Bruns"
__credits__ = []
__license__ = "MIT"
__maintainer__ = "Christopher M. Bruns"
__email__ = "cmbruns@stanford.edu"

import simbios.std as std
from _vecs import *
from _common import *
from _math import *
from _simbody import *
from _molmodel import *

def _vec3_repr(self):
    return "Vec3(%s, %s, %s)" % ( repr(self[0]), repr(self[1]), repr(self[2]) )
Vec3.__repr__ = _vec3_repr

# Reimplement PeriodicPdbWriter, since the C++ wrapper is not working
class PeriodicPdbWriter2(PeriodicEventReporter):
    def __init__(self, system, pyfile, interval):
        super(PeriodicPdbWriter2, self).__init__(interval)
        self.system = system
        self.pyfile = pyfile
        self.buf = streambuf(pyfile)
        self.ostream = adaptbx_ostream(self.buf)
        self.modelNumber = 1

    def handleEvent(self, state):
        # The following realize statement causes runtime error:
        #  AttributeError: 'VerletIntegrator' object has no attribute 'getNextEventTime'
        # self.system.realize(Stage.Position)
        nextAtomSerialNumber = 1
        print >>self.pyfile, "MODEL     %4d" % self.modelNumber
        # for c in range(self.system.getNumCompounds()):
            # compound = self.system.getCompound(c) # same runtime error
            # TODO
            # pass
        print >>self.pyfile, "ENDMDL"
        self.pyfile.flush()
        self.modelNumber += 1

class _CppContainerType(object):
    """
    _Container is used to create a unified syntax for simtk containers.

    For example simtk.Array[int]
    """
    def __init__(self):
        self.types = dict()

    def __getitem__(self, elementType):
        try:
            return self.types[elementType]
        except IndexError:
            raise IndexError(
                "Sorry, no C++ container %s of %s defined." +
                " Try using a python container." % 
                    (self, elementType))

    def __setitem__(self, elementType, containerType):
        self.types[elementType] = containerType

# Create semantic sugar for accessing particular Array types
# These are manually enumerated here
Array = _CppContainerType()
Array[int] = Array_int
Array[Array[int]] = Array_Array_int
Array[float] = Array_double
Array[Array[float]] = Array_Array_double
Array[Vec3] = Array_Vec3
Array[Array[Vec3]] = Array_Array_Vec3
# Array[Attribute] = Array_Attribute
# TODO - the rest

# Create semantic sugar for accessing particular Vector types
# These are manually enumerated here
Vector_ = _CppContainerType()
Vector_[float] = Vector_double
Vector = Vector_[float] # Like the C++ typedef (no-underscore version)
Vector_[Vec3] = Vector_Vec3
Vector_[SpatialMat] = Vector_SpatialMat
Vector_[SpatialVec] = Vector_SpatialVec

SplineFitter = _CppContainerType()
SplineFitter[float] = SplineFitter_Real

