#ifndef __WEAPON_H__
#define __WEAPON_H__

#include "Brainstem.h" 

using namespace Brainstem;

class Weapon
{
public:
	virtual void Update(ICamera* camera) = 0;
	virtual void Fire() = 0;

	bool IsActive;
	bool IsSwitching;

protected:

	IKernel* Kernel;
	IDirector* Director;
	IScene* Scene;

	float YawRotation, PitchRotation;
	float RecoilFactor;
	float RecoilMax;
	float SwingPower;
	float SmoothingPower;
	float BreathingFactor;

	Vector3<float> HolsterOffset;
	Vector3<float> HolsterPosition;

	bool BlockFiring;
	bool IsFiring;
	bool IsHolstered;

	Matrix4<float> GetWorldTransform(Matrix4<float> lookTransform, 
		Vector3<float> position, Vector3<float> rotation,
		Vector3<float> scale)
	{
		position.X -= RecoilFactor;
		position.Y += BreathingFactor;

		Matrix4<float> nodeOffset;
		nodeOffset.SetTranslation(position) * nodeOffset.SetRotationRadians(rotation);

		Matrix4<float> nodeScale;
		nodeScale.SetScale(scale);

		return lookTransform * nodeOffset * nodeScale;
	}

	Matrix4<float> GetLookTransform(ICamera* camera)
	{
		float switchSpeed = 0.06f;

		IsSwitching = false;

		if (IsActive && IsHolstered)
		{
			if (HolsterOffset.X < 0.0f)
				HolsterOffset.X += switchSpeed;
			else
				HolsterOffset.X = 0.0f;

			if (HolsterOffset.Y < 0.0f)
				HolsterOffset.Y += switchSpeed;
			else
				HolsterOffset.Y = 0.0f;

			if (HolsterOffset.Z < 0.0f)
				HolsterOffset.Z += switchSpeed;
			else
				HolsterOffset.Z = 0.0f;

			if (HolsterOffset.X == 0.0f && HolsterOffset.Y == 0.0f && HolsterOffset.Z == 0.0f)
				IsHolstered = false;
			else
				IsSwitching = true;
		}

		if (!IsActive && !IsHolstered)
		{
			if (HolsterOffset.X > HolsterPosition.X)
				HolsterOffset.X -= switchSpeed;
			else
				HolsterOffset.X = HolsterPosition.X;

			if (HolsterOffset.Y > HolsterPosition.Y)
				HolsterOffset.Y -= switchSpeed;
			else
				HolsterOffset.Y = HolsterPosition.Y;

			if (HolsterOffset.Z > HolsterPosition.Z)
				HolsterOffset.Z -= switchSpeed;
			else
				HolsterOffset.Z = HolsterPosition.Z;

			if (HolsterOffset == HolsterPosition)
				IsHolstered = true;
			else
				IsSwitching = true;
		}

		Matrix4<float> cameraTranslation;
		cameraTranslation.SetTranslation(camera->Position);

		Matrix4<float> holsterTranslation;
		holsterTranslation.SetTranslation(HolsterOffset) * 
			holsterTranslation.SetRotationRadians(Vector3<float>(0.0f, HolsterOffset.X, HolsterOffset.X / 3.0f));

		Matrix4<float> pitchTransform;
		pitchTransform.SetTranslation(Vector3<float>(cosf(camera->Pitch), -cosf(camera->Pitch), 0.0f)) *
			pitchTransform.SetRotationRadians(Vector3<float>(0.0f, 0.0f, camera->Pitch));
		
		Matrix4<float> yawTransform;
		yawTransform.SetTranslation(Vector3<float>(cosf(camera->Yaw), 0.0f, -sinf(camera->Yaw))) *
			yawTransform.SetRotationRadians(Vector3<float>(0.0f, camera->Yaw + BSTM_PI_OVER_2, 0.0f));

		return cameraTranslation * yawTransform * pitchTransform * holsterTranslation;
	}
};

class HandOfGod : public Weapon
{
public:
	HandOfGod(IKernel* kernel, IDirector* director, IScene* scene);
	~HandOfGod();

	void Update(ICamera* camera);
	void Fire();

private:

	ISceneNode* Hand;
	ISceneNode* FlashPrimary;
	ISceneNode* FlashHori;
	ISceneNode* FlashVert;

	float FlashRotationOffset;

	PointLight* Flash;
};

class AK47U : public Weapon
{
public:
	AK47U(IKernel* kernel, IDirector* director, IScene* scene);
	~AK47U();

	void Update(ICamera* camera);
	void Fire();

private:

	ISceneNode* Gun;

	ISceneNode* FlashPrimary;
	ISceneNode* FlashHori;
	ISceneNode* FlashVert;

	ISceneNode* LeftArm;
	ISceneNode* RightArm;

	float FlashRotationOffset;

	PointLight* Flash;
};

#endif