/*
 * $Id: bodies.h $
 *
 * Description  :
 * Author       : Radek Bien <mail: radek.bien@seznam.cz>  <ICQ: 201-963-660>
 *
 * Purpose      :
 */

#ifndef _EVTSTRUCTS_H__
#define _EVTSTRUCTS_H__

//#include <vector>
//#include "common.h"
//#include "moddefs.h"
#include "textparser.h"
#include "scene.h"
//#include "scenenode.h"

namespace VRUT
{
	///Tracked device data structure
	struct DeviceData
	{
		struct Finger
		{
			/// Transformation matrix
			Matrix matrix;

			/// The lengths of the phalanges.
			/// Phalanges lengths are in order from outermost (length[0]) to innermost (length[2])
			float lengths[3];

			/// Angles between phalanges.
			/// angle[0] - between outermost and middle and angle[1] between middle and innermost
			float angles[2];

			/// Radius of the tip of the finger.
			float radius;
		};

		// button states used for car simulation
		enum {
			BUTTON_TEMPO_OFF=1,
			BUTTON_TEMPO_ON=2,
			BUTTON_TEMPO_CANCEL=4,
			BUTTON_TEMPO_SET=8,
			BUTTON_TEMPO_RESUME=16,
			BUTTON_TEMPO_FASTER=32,
			BUTTON_TEMPO_SLOWER=64,
			BUTTON_TEMPO_RELEASE=128,
			BUTTON_LEFT_BLINKER=256,
			BUTTON_RIGHT_BLINKER=512,
			BUTTON_VPROF0=1024,
			BUTTON_VPROF1=2048,
			BUTTON_VPROF2=4096
		};
		
		enum DEVICE_TYPE {
			DEVICE_Unknown = 0,//it is the first value for cycles and it can be also used as "all types"
			DEVICE_FlyStick2,
			DEVICE_FingerTracking,
			DEVICE_6DoF,
			DEVICE_Measurement,
			DEVICE_3DoF,
			DEVICE_Last
		};

		/// Unique device identifier
		int id;
		/// Device type (should be only informative)
		DEVICE_TYPE type;
		/// Quality of transformation
		float quality;
		/// Transformation matrix
		Matrix matrix;
		/// actually pressed buttons on device
		int buttons;
		/// Actual values of controls
		std::vector<float> controls;
		/// Left or right hand
		int hand;//0 - left, 1 - right
		/// Hand fingers (first is thumb)
		std::vector<Finger> fingers;

		DeviceData(int _id=0, DEVICE_TYPE _type=DEVICE_Unknown, int _buttons=0) : id (_id), type(_type), quality(0), buttons(_buttons), hand(0) {}

		DeviceData(int _id, DEVICE_TYPE _type, Matrix _matrix, int _buttons, std::vector<float> _controls) : id (_id), type(_type), quality(0), matrix(_matrix), buttons(_buttons), hand(0)
		{
			controls.assign(_controls.begin(), _controls.end());
		}

		/// Get human readable name for given type
		/// Can be used for ComboBoxes etc.
		static wxString GetTypeName(DEVICE_TYPE type)
		{
			switch (type)
			{
			case DEVICE_Unknown:
				return wxT("0 - Unknown");
			case DEVICE_FlyStick2:
				return wxT("1 - FlyStick2");
			case DEVICE_FingerTracking:
				return wxT("2 - FingerTracking");
			case DEVICE_6DoF:
				return wxT("3 - 6DoF device");
			case DEVICE_Measurement:
				return wxT("4 - Measurement");
			case DEVICE_3DoF:
				return wxT("5 - 3DoF device");
			default:
				return wxT("Wrong value");
			}
		}

		/// Get type from name - opposite to GetTypeName
		static DeviceData::DEVICE_TYPE GetTypeByName(wxString &name)
		{
			long tmp=0;
			TextParser(name.utf8_str()).ParseLong(&tmp);
			return (DeviceData::DEVICE_TYPE)tmp;
		}

		/// Get string with DeviceDatra properties
		wxString ToString() const
		{
			wxString res;
			res += wxString::Format(wxT("\nDevice id: %i \n"), id);
			res += wxT("Type: ") + GetTypeName(type);
			res += wxString::Format(wxT("\nQuality: %f \n"), quality);
			res += wxString::Format(wxT("Pressed buttons: %i \n"), buttons);

			res += wxT("Transformation matrix: \n")+matrix.ToString()+wxT("\n");

			if (type==DEVICE_FingerTracking)
			{
				res += wxString::Format(wxT("Hand: %i \n"), hand);

				for (size_t i = 0; i < fingers.size(); i++)
				{
					res += wxString::Format(wxT("Finger: %lu \n"), (unsigned long)i);
					res += wxT("Finger transformation matrix: \n")+fingers[i].matrix.ToString()+wxT("\n");

					for (int j = 0; j < 3; j++)
					{
						res += wxString::Format(wxT("Length %i: %f \n"), j, fingers[i].lengths[j]);
						if (j != 2)
							res += wxString::Format(wxT("Angle %i: %f \n"), j, fingers[i].angles[j]);
					}
				}
			}
			return res;
		}
	};

	///Structure carrying collision data
	struct CollisionReport
	{
		SCENE_ID sceneID;

		/// NODE_IDs of colliding subtrees (scene nodes)
		NODE_ID collidingMovableTreeID;
		NODE_ID collidingBarrierTreeID;

		/// NODE_IDs of colliding geometry nodes
		NODE_ID collidingMovableGeometryID;
		NODE_ID collidingBarrierGeometryID;

		/// Indicates whether details (center, depth and normal) are calculated
		bool hasDetails;

		/// Center of colliding area
		Vector3 collisionCenter;

		/// Normal vector of colliding area
		Vector3 collisionNormal;

		/// Depth of which movable object is in barrier object
		float depthOfPenetration;

		CollisionReport():
			sceneID(SCENE_ID_NONE), collidingMovableTreeID(NODE_ID_NONE), collidingBarrierTreeID(NODE_ID_NONE), collidingMovableGeometryID(NODE_ID_NONE), collidingBarrierGeometryID(NODE_ID_NONE),
			hasDetails(false), collisionCenter(0.0f, 0.0f, 0.0f), collisionNormal(0.0f, 0.0f, 0.0f), depthOfPenetration(0.0f) {}

		CollisionReport(const CollisionReport& r):
			sceneID(r.sceneID), collidingMovableTreeID(r.collidingMovableTreeID), collidingBarrierTreeID(r.collidingBarrierTreeID), collidingMovableGeometryID(r.collidingMovableGeometryID), collidingBarrierGeometryID(r.collidingBarrierGeometryID),
			hasDetails(r.hasDetails), collisionCenter(r.collisionCenter), collisionNormal(r.collisionNormal), depthOfPenetration(r.depthOfPenetration) {}

		CollisionReport(SCENE_ID _sceneID, NODE_ID _collidingMovableTreeID, NODE_ID _collidnigBarrierTreeID, NODE_ID _collidingMovableGeometryID, NODE_ID _collidingBarrierGeometryID):
			sceneID(_sceneID), collidingMovableTreeID(_collidingMovableTreeID), collidingBarrierTreeID(_collidnigBarrierTreeID), collidingMovableGeometryID(_collidingMovableGeometryID), collidingBarrierGeometryID(_collidingBarrierGeometryID),
			hasDetails(false), collisionCenter(0.0f, 0.0f, 0.0f), collisionNormal(0.0f, 0.0f, 0.0f), depthOfPenetration(0.0f) {}

		CollisionReport(SCENE_ID _sceneID, NODE_ID _collidingMovableTreeID, NODE_ID _collidnigBarrierTreeID, NODE_ID _collidingMovableGeometryID, NODE_ID _collidingBarrierGeometryID,
			Vector3 _collisionCenter, Vector3 _collisionNormal, float _depthOfPenetration):
			sceneID(_sceneID), collidingMovableTreeID(_collidingMovableTreeID), collidingBarrierTreeID(_collidnigBarrierTreeID), collidingMovableGeometryID(_collidingMovableGeometryID), collidingBarrierGeometryID(_collidingBarrierGeometryID),
			hasDetails(true), collisionCenter(_collisionCenter), collisionNormal(_collisionNormal), depthOfPenetration(_depthOfPenetration) {}
	};

	struct SceneNodeTransformPreData
	{
		Scene *scene;
		smart_pointer<SceneNode> sceneNode;
		Matrix *matrix;

		SceneNodeTransformPreData(Scene *scene, smart_pointer<SceneNode> sceneNode, Matrix *matrix) : scene(scene), sceneNode(sceneNode), matrix(matrix)
		{
		}
	};

	struct JSScriptingContext;
	typedef JSScriptingContext *JSScriptingContextPtr;
	struct JavascriptRunScriptData
	{
		JSScriptingContextPtr *ctx;

		const wxString &script;
		wxString &result;
		bool processed;

		JavascriptRunScriptData(JSScriptingContextPtr *ctx, const wxString &script, wxString &result)
			: ctx(ctx), script(script), result(result), processed(false) {}
	};
}

#endif
