
#include <vector>

class Projekt : public Test
{
public:
	struct Ragdoll
	{
		b2Body* create_head(float skala, const b2Vec2 szyja[])
		{
			b2BodyDef h;
			h.position = szyja[1];
			h.type = b2_dynamicBody;

			h.angle = -90.0f * b2_pi / 180;
			b2Body* body_head = world->CreateBody(&h);

			b2CircleShape cs; 
			cs.m_radius = 0.30f*skala;

			body_head->CreateFixture(&cs, 1.0f);
			lista_body.push_back(body_head);

			return body_head;
		}


		void make(b2World* world, const b2Vec2& wsp, float skala)
		{
			this->world = world;

			b2Vec2 noga_L_B[] = { wsp + skala*b2Vec2(-0.25f, 0.0f), wsp + skala*b2Vec2(-0.25f, 0.5f) };
			b2Vec2 noga_R_B[] = { wsp + skala*b2Vec2(0.25f, 0.0f), wsp + skala*b2Vec2(0.25f, 0.5f) };
			b2Vec2 noga_L_T[] = { wsp + skala*b2Vec2(-0.25f, 0.5f), wsp + skala*b2Vec2(-0.25f, 1.0f) };
			b2Vec2 noga_T_T[] = { wsp + skala*b2Vec2(0.25f, 0.5f), wsp + skala*b2Vec2(0.25f, 1.0f) };
			b2Vec2 brzuch[] = { wsp + skala*b2Vec2(0.0f, 1.0f), wsp + skala*b2Vec2(0.0f, 1.6f) };
			b2Vec2 klatka[] = { wsp + skala*b2Vec2(0.0f, 1.6f), wsp + skala*b2Vec2(0.0f, 2.0f) };
			b2Vec2 reka_L_T[] = { wsp + skala*b2Vec2(-0.375f, 2.0f), wsp + skala*b2Vec2(-1.0f, 2.0f), };
			b2Vec2 reka_R_T[] = { wsp + skala*b2Vec2(0.375f, 2.0f), wsp + skala*b2Vec2(1.0f, 2.0f), };
			b2Vec2 reka_L_B[] = { wsp + skala*b2Vec2(-1.0f, 2.0f), wsp + skala*b2Vec2(-1.625f, 2.0f), };
			b2Vec2 reka_R_B[] = { wsp + skala*b2Vec2(1.0f, 2.0f), wsp + skala*b2Vec2(1.625f, 2.0f), };
			b2Vec2 szyja[] = { wsp + skala*b2Vec2(0.0f, 2.0f), wsp + skala*b2Vec2(0.0f, 2.4f) };


			b2Body* b_noga_L_B = make_part(noga_L_B, 0.25f*skala);
			b2Body* b_noga_R_B = make_part(noga_R_B, 0.25f*skala);
			b2Body* b_noga_L_T = make_part(noga_L_T, 0.3f*skala);
			b2Body* b_noga_R_T = make_part(noga_T_T, 0.3f*skala);

			b2Body* b_brzuch = make_part(brzuch, 0.75f*skala);
			
			b2Body* b_klatka = make_part(klatka, 0.8f*skala);
			
			
			b2Body* b_reka_L_T = make_part(reka_L_T, 0.25f*skala);
			b2Body* b_reka_R_T = make_part(reka_R_T, 0.25f*skala);
			b2Body* b_reka_L_B = make_part(reka_L_B, 0.22f*skala);
			b2Body* b_reka_R_B = make_part(reka_R_B, 0.22f*skala);

			b2Body* b_szyja = make_part(szyja, 0.2f*skala);
			
			b2Body* body_head = create_head(skala, szyja);

			
			b2RevoluteJoint* j_noga_L_B = make_joint(noga_L_B[1], b_noga_L_B, b_noga_L_T, -45.0f, 45.0f);
			b2RevoluteJoint* j_noga_R_B = make_joint(noga_R_B[1], b_noga_R_B, b_noga_R_T, -45.0f, 45.0f);

			b2RevoluteJoint* j_noga_L_T = make_joint(noga_L_T[1], b_noga_L_T, b_brzuch, -40.0f, 40.0f);
			b2RevoluteJoint* j_noga_R_T = make_joint(noga_T_T[1], b_noga_R_T, b_brzuch, -40.0f, 40.0f);
			
			b2RevoluteJoint* j_reka_L_T = make_joint(reka_L_T[0], b_reka_L_T, b_klatka, -80.0f, 80.0f);
			b2RevoluteJoint* j_reka_R_T = make_joint(reka_R_T[0], b_reka_R_T, b_klatka, -80.0f, 80.0f);
			
			b2RevoluteJoint* j_tors = make_joint(klatka[0], b_brzuch, b_klatka, -15.0f, 15.0f);
			
			b2RevoluteJoint* j_reka_L_B = make_joint(reka_L_B[0], b_reka_L_T, b_reka_L_B, -130.0f, 130.0f);
			b2RevoluteJoint* j_reka_R_B = make_joint(reka_R_B[0], b_reka_R_T, b_reka_R_B, -130.0f, 130.0f);
			
			b2RevoluteJoint* j_szyja = make_joint(szyja[0], b_szyja, b_klatka, -15.0f, 15.0f);
			
			b2RevoluteJoint* j_glowa = make_joint(szyja[1], body_head, b_szyja, -5.0f, 5.0f);
		}
		
		b2World* world;

		std::vector<b2Body*> lista_body;
		std::vector<b2RevoluteJoint*> lista_joints;

		void  destroy()
		{
			for (size_t j = 0; j < lista_body.size(); ++j)
			{
				world->DestroyBody(lista_body[j]);
			}
			lista_body.clear();
			lista_joints.clear();
		}

		b2Body* make_part(const b2Vec2 v[], float width)
		{
			b2Vec2 a = v[1] - v[0];
			float  dist = a.Length();
			b2BodyDef b;
			b.type = b2_dynamicBody;
			b.position = 0.5f*(v[1] + v[0]);
			b.bullet = true;
			b.angle = atan2f(a.y, a.x);
			b2Body* body = world->CreateBody(&b);
			b2PolygonShape p;
			p.SetAsBox(dist / 2, width / 2);
			body->CreateFixture(&p, 1.0f)->SetFriction(1.0f);
			lista_body.push_back(body);

			return body;
		}

		b2RevoluteJoint* make_joint(const b2Vec2& wsp, b2Body* body1, b2Body* body2, float min_angle, float max_angle)
		{
			b2RevoluteJointDef j;
			j.Initialize(body1, body2, wsp);
			j.lowerAngle = min_angle * b2_pi / 180;
			j.upperAngle = max_angle * b2_pi / 180;
			j.enableLimit = true;
			lista_joints.push_back((b2RevoluteJoint*)world->CreateJoint(&j));

			return lista_joints.back();
		}
	};

	
	Ragdoll ragdoll;
	Ragdoll ragdoll2;
	b2Vec2  init_pos, init_pos2;
	
	Projekt()
	{
		b2BodyDef b;
		b2Body* body_ground = m_world->CreateBody(&b);
		b2ChainShape cs;
		b2Vec2 box[] = { b2Vec2(-50, 40), b2Vec2(-50, -0), b2Vec2(24.0, -0), b2Vec2(24, 40), b2Vec2(-50,40)};
		cs.CreateChain(box, 5);
		body_ground->CreateFixture(&cs, 1.0f);

		std::vector<b2Vec2> schody_l;
		std::vector<b2Vec2> schody_r;

		b2Vec2 vpoint(-50, 30);
		schody_l.push_back(vpoint);
		vpoint.x += 14;
		schody_l.push_back(vpoint);
		init_pos = vpoint - b2Vec2(0, 0);
		for (int i = 0; i < 12; ++i)//schody lewe
		{
			vpoint.y -= 2;
			schody_l.push_back(vpoint);
			vpoint.x += 1;
			schody_l.push_back(vpoint);
		}
		vpoint.y -= 6;
		schody_l.push_back(vpoint);

		b2ChainShape cs1;
		cs1.CreateChain(&schody_l[0], schody_l.size());
		body_ground->CreateFixture(&cs1, 1.0f)->SetFriction(2.0f);

		b2Vec2 vpoint2(-6, 0);
		schody_r.push_back(vpoint2);

		for (int i = 0; i < 12; ++i)//schody prawe
		{
			vpoint2.y += 2;
			schody_r.push_back(vpoint2);
			vpoint2.x += 2;
			schody_r.push_back(vpoint2);
		}

		vpoint2.x += 6;
		schody_r.push_back(vpoint2);
		b2ChainShape cs2;
		cs2.CreateChain(&schody_r[0], schody_r.size());
		body_ground->CreateFixture(&cs2, 1.0f)->SetFriction(2.0f);

		init_pos2 = vpoint2 - b2Vec2(4, 0); // pozycja init czyli wsp w create

		g_camera.m_center.Set(0, 18);

		set();

	}

	void set()
	{
		ragdoll.make(m_world, init_pos2, 2.5f);
		ragdoll2.make(m_world, init_pos, 2.4f);
	}

	void Step(Settings* settings)
	{
		Test::Step(settings);
	}

	void Keyboard(int key)
	{
		switch (key)
		{
		case GLFW_KEY_R:
		{
			ragdoll.destroy();
			ragdoll2.destroy();
			set();
			break;
		}
		}
	}

	static Test* Create()
	{
		return new Projekt();
	}
};