#pragma once

#include "ofxBox2dUtils.h"
#include "ofxBox2dBaseShape.h"

#include "ofxBox2dCircle.h"
#include "ofxBox2dLoop.h"

#include "ofxBox2dRender.h"

#include "ofMain.h"

class ofxBox2d: public b2ContactListener, public b2DestructionListener {
private:
	b2Vec2 m_bounds[4];

    float fps;
public:
    b2Vec2 gravity;
    bool doSleep;
	int velocityIterations;
	int positionIterations;

    bool pause;
    bool singleStep;

    bool drawStats;
    bool drawShapes;
    bool drawJoints;
    bool drawAABBs;
    bool drawPairs;
    bool drawCOMs;

    bool enableWarmStarting;
    bool enableContinuous;

	ofxBox2d();
	~ofxBox2d();

    void setup();
	void update();
	void draw();

	void setBounds(float x, float y, float w, float h, bool softEdges = true);
    void setFrameRate(int targetRate);

	void registerGrabbing();
	void unregisterGrabbing();
    void MouseDown(ofMouseEventArgs &e);
    void MouseUp(ofMouseEventArgs &e);
    void MouseMove(ofMouseEventArgs &e);

// Function in header due to inlining.
	inline b2World* getWorld() { return m_world; };

// b2ContactListener
	void BeginContact(b2Contact* contact);
	void EndContact(b2Contact* contact);
	void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
	void PostSolve(const b2Contact* contact, const b2ContactImpulse* impulse);

// b2DestructionListener
	void SayGoodbye(b2Fixture* fixture);
	void SayGoodbye(b2Joint* joint);
protected:
	friend class ofxBox2dDestructionListener;

	b2Body* m_groundBody;
	b2Body* m_body;
	b2World* m_world;
	int32 m_textLine;
    ofxBox2dDebugDraw m_debugDraw;
	b2MouseJoint* m_mouseJoint;
	b2Vec2 m_mouseWorld;
};

class QueryCallback: public b2QueryCallback {
public:
	QueryCallback(const b2Vec2& point);
	bool ReportFixture(b2Fixture* fixture);

	b2Vec2 m_point;
	b2Fixture* m_fixture;
};
