The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;
use Box2D;
use Test::More;



for my $listenerType ("normal","TestContactListener") {
    my $vec = Box2D::b2Vec2->new(10,-10);
    my $world = Box2D::b2World->new($vec, 1);

    my $body_def = Box2D::b2BodyDef->new();

    $body_def->position->Set(0.0, -10.0);

    my $groundBody = $world->CreateBody($body_def); 

    my $groundBox = Box2D::b2PolygonShape->new();

    $groundBox->SetAsBox(50.0, 10.0);

    $groundBody->CreateFixture( $groundBox, 0.0 ); 

    my $bodyDef = Box2D::b2BodyDef->new();
    $bodyDef->type(Box2D::b2_dynamicBody);
    is( $bodyDef->type(), 2, "returning enum" );
    $bodyDef->position->Set(0.0, 4.0);

    my $body = $world->CreateBody($bodyDef);
    
    pass( "Create body for world " );
    
    my $dynamicBox = Box2D::b2PolygonShape->new();
    $dynamicBox->SetAsBox( 1.0, 1.0 );
    
    pass( "Create box" );
    
    my $fixtureDef = Box2D::b2FixtureDef->new();
    $fixtureDef->shape( $dynamicBox );
    $fixtureDef->density(1.0);
    $fixtureDef->friction(0.3);
    
    
    $body->CreateFixtureDef($fixtureDef);
    
    pass( "Create fixture Def" );
    my $timeStep = 1.0/60.0;
    my $velocityIterations = 6;
    my $positionIterations = 2;
#$world->SetContactListener( undef );
    

    my $beginContact = 0;
    my $endContact = 0;
    my $preSolve = 0;
    my $postSolve = 0;
    my $listener;
    if ($listenerType eq "normal") {
        $listener = Box2D::PerlContactListener->new();
        # if this runs at least callback fixtures work as well!
        $listener->SetBeginContactSub(
            sub { 
                #warn "BeginContact!"; warn @_;
                $beginContact++;
                my ($contact) = @_;
                my $fixA = $contact->GetFixtureA();
                my $fixB = $contact->GetFixtureB();
                #warn "$fixA $fixB";
                my $posA = $fixA->GetBody()->GetPosition();
                my $posB = $fixB->GetBody()->GetPosition();
                #warn $posA->x() . " " . $posA->y(). " ".$fixA->GetDensity();
                #warn $posB->x() . " " . $posB->y(). " ".$fixB->GetDensity();
                
            } );
        $listener->SetEndContactSub(sub { #warn "EndContact!"; warn @_;
            $endContact++;  } );
        $listener->SetPreSolveSub(sub { #warn "PreSolve!"; warn @_; 
            $preSolve++;  } );
        $listener->SetPostSolveSub(sub {# warn "PostSolve!"; warn @_; 
            $postSolve++; });
        
        #warn "In Perl Code setting listener";
        $world->SetContactListener( $listener );
    } else {
        $listener = TestContactListener->new();
        ok(  UNIVERSAL::isa($listener,"Box2D::b2ContactListener"), "Not a contactlistener??");

        #warn "Setting listener!";
        $world->SetContactListener(  $listener );
    }

    foreach ( 0.. 20000 )
    {

	$world->Step( $timeStep, $velocityIterations, $positionIterations );
	$world->ClearForces();

	my $position = $body->GetPosition();
	my $angle = $body->GetAngle();
	#warn( "Position ". $position->x(). ", ". $position->y() ."\n" );
	#warn( "Angle ".$angle."\n");
    }

    if ($listenerType ne "normal") {
        $beginContact = $listener->{BeginContact};
        $endContact = $listener->{EndContact};
        $preSolve = $listener->{PreSolve};
        $postSolve = $listener->{PostSolve};

    }

    ok( $beginContact > 0, "beginContact doesn't work? $beginContact");
    ok( $endContact > 0, "endContact doesn't work?");
    ok( $preSolve > 0, "preSolve doesn't work?");
    # disabling postSolve test til I understand it more
    ok( $postSolve > 0, "postSolve doesn't work?");
    

    pass( "Run step and clear forces");

    pass("Made stuff and survived");

    $world->DestroyBody( $body );
    $body = undef;
    pass("Destroyed the body");

}

done_testing;

1;
package TestContactListener;
use Box2D;
#use Box2D::b2ContactListener;
use base qw(Box2D::b2ContactListener);

sub BeginContact {
    my ($self, $contact) = @_;
    #warn "TestContact BeginContact";
    $self->{BeginContact}++;
}
sub EndContact {
    my ($self, $contact) = @_;
    #warn "TestContact EndContact";
    $self->{EndContact}++;
}
sub PreSolve {
    my ($self) = @_;
    #warn "TestContact PreSolve";
    $self->{PreSolve}++;
}
sub PostSolve {
    my ($self) = @_;
    #warn "TestContact PostSolve";
    $self->{PostSolve}++;
}
        
1;