#pragma once

#include "MAXProxies.hpp"

namespace MAXProxies {

	class MAXScene;
	class MAXGroup;

	//
	//#########################################################################
	//###########################    MAXLight    ###############################
	//#########################################################################
	//
	class MAXLight:
		public Proxies::LightProxy
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	public:
		static MAXLight*
			MakeProxy(
				MAXScene *scene,
				MAXGroup *parent,
				INode *light,
				int index
			)
				{return new MAXLight(scene, parent, light, index);}

		void
			Destroy();

		void*
			operator new(size_t)
				{return AllocatedMemory->New();}
		void
			operator delete(void *where)
				{AllocatedMemory->Delete(where);}

	protected:
		MAXLight(
			MAXScene *scene,
			MAXGroup *parent,
			INode *light,
			int index
		);
		~MAXLight();

		static Stuff::MemoryBlock
			*AllocatedMemory;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data Support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Testing
	//
	public:
		void
			TestInstance() const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Position management functions
	//
	public:
		//
		// Position traversal functions
		//
		MAXScene*
			GetSceneProxy()
				{Check_Object(this); return Cast_Pointer(MAXScene*, sceneProxy);}

		MAXGroup*
			GetParentGroupProxy()
				{
					Check_Object(this);
					return reinterpret_cast<MAXGroup*>(parentProxy);
				}
		void
			TransferAndAppendToParentGroup(Proxies::GroupProxy *parent);

		Proxies::ChildProxy*
			UseNextSiblingProxy();
		Proxies::ChildProxy*
			UsePreviousSiblingProxy();

	protected:

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Material functions
	//
	public:
		//
		// name functions
		//
		bool
			GetName(Stuff::MString *name);
		void
			SetName(const char* name);

		//
		// Position functions
		//
		bool
			GetLocalToParent(Stuff::LinearMatrix4D *matrix);
		void
			SetLocalToParent(const Stuff::LinearMatrix4D &matrix);

		//
		// Bounding functions
		//
		bool
			GetOBB(Stuff::OBB *obb);
		void
			SetOBB(const Stuff::OBB &obb);
		bool
			GetBoundingSphere(Stuff::Sphere *sphere);
		void
			SetBoundingSphere(const Stuff::Sphere &sphere);

		//
		// ambient color functions
		//
		void
			GetColor(Stuff::RGBColor *color);
		void
			SetColor(const Stuff::RGBColor &color);

		//
		// Ambience.  If the light is ambient (it isn't by default), then its
		// local to parent and local to world matrices are not valid
		//
		bool
			IsAmbient();
		void
			SetAmbient(bool ambient);

		//
		// light falloff (valid for points and spots)
		//
		bool
			GetFalloffDistance(
				Stuff::Scalar *n,
				Stuff::Scalar *f
			);
		void
			SetFalloffDistance(
				Stuff::Scalar n,
				Stuff::Scalar f
			);

		//
		// light falloff (for spots)
		//
		bool
			GetSpreadAngle(Stuff::Radian *angle);
		void
			SetSpreadAngle(const Stuff::Radian &radian);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// MAX helper functions
	//
	public:
		INode 
			*GetPreviousChild();
		INode 
			*GetNextChild();
		LightState *GetLightState() {return lightObject?&lightState:NULL;}
		INode *GetProxiedLight() {return proxiedLight;}
	protected:
		int 
			childIndex;

		INode
			*proxiedLight;

		LightObject
			*lightObject;

		LightState
			lightState;
	};
}
