#ifndef VISUAL_DEBUGGER_H
#define VISUAL_DEBUGGER_H

#include "modulehandle.h"

namespace VRUT {

	class VisualDebugger {

	public:
		smart_pointer_v2<Scene> scene;
		Module *mModule;
		int mMaterialId;
		int mGeometryId;
		wxString mMaterialName;

		VisualDebugger(smart_pointer_v2<Scene> &scene, Module *module) : scene(scene) {
			mModule = module;
			mMaterialId = 0;
			mGeometryId = 0;
			SetColor(Vector4(1,0,0,1));
		}

		void SetColor(const Vector4 &color) {

			mMaterialName = wxString::Format(wxT("debugger-mat-%d"), mMaterialId++);
			//prepare material
			Material * material = new Material(mMaterialName);
			//create new "default" material with adequate name
			material->diffuse = color;
			material->specular = Vector4(0.0, 0.0, 0.0, 1);
			material->flags = Material::DOUBLE_SIDED;
			mModule->PostToKernel(GET_EVT_SCENE_MATERIAL_ADD(scene->GetID(), material));

		}

		void AddLine(const Vector3 &a, const Vector3 &b, const float width) {
			Vector3 d = b - a;
			Vector3 u, v;
			d.RightHandedBase(u, v);
			u = u.Normalize();
			v = v.Normalize();
#if 1
			std::vector<Vector3> vertices;
			std::vector<int> indices;
#else
			Vector3 vv[8];
			vv[0] = a-width*u;
			vv[1] = a+width*u;
			vv[2] = b+width*u;
			vv[3] = b-width*u;

			vv[4] = a-width*v;
			vv[5] = a+width*v;
			vv[6] = b+width*v;
			vv[7] = b-width*v;

			const int indices[] {
				0, 1, 2,
					0, 2, 3,
					4, 5, 6,
					4, 6, 7 };
#endif
			const int segments = 8;
			Vector3 bb = a + 0.9f*(b-a);
			for (int i=0; i < segments; i++) {
				float alpha = i*2.0f*M_PI/segments;
				Vector3 d = width*(sin(alpha)*u + cos(alpha)*v);
				vertices.push_back(a+d);
				vertices.push_back(bb+d);
			}
			// vertices for arrow
			for (int i=0; i < segments; i++) {
				float alpha = i*2.0f*M_PI/segments;
				Vector3 d = 1.5f*width*(sin(alpha)*u + cos(alpha)*v);
				vertices.push_back(bb+d);
			}
			// arrow tip
			vertices.push_back(b);

			for (int i=0; i < segments; i++) {
				int offset = 2*i;
				int mm = 2*segments;
				indices.push_back(offset);
				indices.push_back((offset+2)%mm);
				indices.push_back((offset+3)%mm);
				indices.push_back(offset);
				indices.push_back((offset+3)%mm);
				indices.push_back((offset+1)%mm);
			}
			// arrow
			for (int i=0; i < segments; i++) {
				int offset = 2*segments;
				int mm = segments;
				indices.push_back(offset+i);
				indices.push_back(offset+(i+1)%mm);
				indices.push_back(vertices.size()-1);
			}

			wxString nodeName = wxString::Format(wxT("debugger-geom-%d"), mGeometryId++);

			GeometryNode * node = new GeometryNode(nodeName);
			NODE_ID nodeId = scene->GetNewNodeID();
			node->SetID(nodeId);
			mModule->PostToKernel(GET_EVT_SCENE_NODE_INSERT(scene->GetID(), node, 0));
			mModule->PostToKernel(GET_EVT_SCENE_NODE_MATERIAL_SET(scene->GetID(), nodeId, mMaterialName));

			GeometryTriangles *geoTri = new GeometryTriangles(scene->GetNewGeometryID());
			for (size_t i=0; i < vertices.size(); i++)
				geoTri->vertices.push_back(vertices[i]);

			for (size_t i=0; i < indices.size(); i++)
				geoTri->indices.push_back(indices[i]);

			geoTri->triDescList.push_back(std::pair<GeometryTriangles::Index, GeometryTriangles::PRIMITIVE_TYPE>(0, GeometryTriangles::TRI_LIST));
			///Assign mesh
			GEOMETRY_ID gid=geoTri->GetID();
			geoTri->UnifyVertices();
			mModule->PostToKernel(GET_EVT_SCENE_GEOMETRY_ADD(scene->GetID(), geoTri));
			mModule->PostToKernel(GET_EVT_SCENE_NODE_GEOMETRY_SET(scene->GetID(), nodeId, gid));
		}
	};
}

#endif
