// ----------------------------------------------------------------------------
//
void SceneMovementAnimatorTask::generateProgram( AnimationDefinition* definition )
{
    SceneMovementAnimator* config = dynamic_cast< SceneMovementAnimator *>( definition );

    MovementAnimation& movement = config->movement();

    ParticipantArray participants;
    Head head;

    // Determine which actors will be participating
	for ( SceneActor& actor : getActors() ) {
        Fixture* pf = getActorRepresentative( actor.getActorUID() );
        if ( !pf || !pf->canMove() )
            continue;

        if ( movement.m_head_number == 0 ) { // All heads on fixture(s)
            for ( UINT head_number=1; head_number <= pf->getNumHeads(); head_number++ ) {
                if ( pf->getHead( head_number, head ) )
                    participants.emplace_back( actor.getActorUID(), head );                    
            }
        }
        else {                                 // Single head on fixture(s)
            if ( pf->getHead( movement.m_head_number, head ) )
                participants.emplace_back( actor.getActorUID(), head ); 
        }
    }

    STUDIO_ASSERT( movement.m_group_size >= 1, "Movement group size must be >= 1" );
    STUDIO_ASSERT( movement.m_home_wait_periods > 0 && movement.m_home_wait_periods < MAX_WAIT_PERIODS, 
        "Home wait periods must be between 1 and %d", MAX_WAIT_PERIODS );
    STUDIO_ASSERT( movement.m_dest_wait_periods > 0 && movement.m_dest_wait_periods < MAX_WAIT_PERIODS, 
        "Destination wait periods must be between 1 and %d", MAX_WAIT_PERIODS );

    // TODO: At some point, pre-compute the channel arrays once rather on each scene load as
    // that will be a problem for many fixtures/animations in a single scene.

    switch ( movement.m_movement_type ) {
        case MOVEMENT_RANDOM:							// Move to random locations
            genRandomMovement( movement, participants );
            break;

        case MOVEMENT_FAN:								// Fan beams
            genFanMovement( movement, participants );
            break;

        case MOVEMENT_ROTATE:							// Simple rotate at tilt angle
            genRotateMovement( movement, participants );
            break;

        case MOVEMENT_NOD:								// Simple up and down
            genNodMovement( movement, participants );
            break;

        case MOVEMENT_XCROSS:							// Cross fixture beams
            genXcrossMovement( movement, participants );
            break;

        case MOVEMENT_MOONFLOWER:						// Moonflower effect
            genMoonflowerMovement( movement, participants );
            break;

        case MOVEMENT_COORDINATES:						// Absolute coordinates effect
            genCoordinatesMovement( movement, participants );
            break;

        case MOVEMENT_SINEWAVE:						    // Sinewave movement
            genSineMovement( movement, participants );
            break;
    }
}