# py/pyext - python script objects for PD and MaxMSP
#
# Copyright (c) 2002-2005 Thomas Grill (gr@grrrr.org)
# For information on usage and redistribution, and for a DISCLAIMER OF ALL
# WARRANTIES, see the file, "license.txt," in this distribution.  
#

"""

pyext Usage:
- Import pyext

- Inherit your class from pyext._class

- Specfiy the number of inlets and outlets:
    Use the class members (variables) _inlets and _outlets
    If not given they default to 1
    You can also use class methods with the same names to return the respective number

- Constructors/Destructors
    You can specify an __init__ constructor and/or an __del__ destructor.
    The constructor will be called with the object's arguments

    e.g. if your PD or MaxMSP object looks like
    [pyext script class arg1 arg2 arg3]

    then the __init__(self,*args) function will be called with a tuple argument
    args = (arg1,arg2,arg3) 
    With this syntax, you will have to give at least one argument.
    By defining the constructor as __init__(self,*args) you can also initialize 
    the class without arguments.

- Methods called by pyext
    The general format is 'tag_inlet(self,arg)' resp. 'tag_inlet(self,*args)':
        tag is the PD or MaxMSP message header.. either bang, float, list etc.
        inlet is the inlet (starting from 1) from which messages are received.
        args is a tuple which corresponds to the content of the message. args can be omitted.

    The inlet index can be omitted. The method name then has the format 'tag_(self,inlet,args)'.
    Here, the inlet index is a additional parameter to the method

    You can also set up methods which react on any message. These have the special forms
        _anything_inlet(self,*args)
    or
        _anything_(self,inlet,*args) 

    Please see below for examples.

    Any return values are ignored - use _outlet (see below).

    Generally, you should avoid method_, method_xx forms for your non-pyext class methods.
    Identifiers (variables and functions) with leading underscores are reserved for pyext.

- Send messages to outlets:
    Use the inherited _outlet method.
    You can either use the form
        self._outlet(outlet,arg1,arg2,arg3,arg4) ... where all args are atoms (no sequence types!)
    or
        self._outlet(outlet,arg) ... where arg is a sequence containing only atoms

- Use pyext functions and methods: 
    See the __doc__ strings of the pyext module and the pyext._class base class.

"""

try:
    import pyext
except:
    print "ERROR: This script must be loaded by the PD/Max pyext external"

from mass3d import Mass3D
from link3d import Link3D

class InteractionMassCreator(pyext._class):
    """This class creates a number of fixed masses which can be moved around by some kind of input device."""

    # number of inlets and outlets
    _inlets=1
    _outlets=1

    mass_messages = []
    
    # Create a number of fixed masses
    # Float inlet sets number of fixed masses to create.
    # Each mass id is prefixed with a number.  First mass is number 1, second is 2, etc...
    def float_1(self, *args):
    
        mass_messages = []
        link_messages = []
        for i in range(1, args[0] + 1, 1):
            # Set up fixed mass
            fixed_mass = Mass3D()
            fixed_mass.id = str(i) + "-interactor-fixed-mass"
            fixed_mass.fixed = True
            fixed_mass.position = (0, 0, 0)
            mass_messages.append(fixed_mass.get_msd_setup_message())
            
            
            # Set up collision links so that mouse masses will collide with floating masses
            collision_link = Link3D()
            collision_link.id = "interactor-collision-link"
            collision_link.mass1_id = fixed_mass.id 
            collision_link.mass2_id = "floating-mass"
            collision_link.rigidity = 0.4
            collision_link.damping = 0.4
            collision_link.distance_exponent = 1
            collision_link.min_length = 0.0
            collision_link.max_length = 0.2
            
            link_messages.append(collision_link.get_msd_setup_message())
           
        # Send msd setup messages out the outlet
        for message in mass_messages:
          self._outlet(1, message)
          
        # Send msd link messages out too
        for message in link_messages:
            self._outlet(1, message)