//===========================================================================//
// File:        jmover.hh                                                            //
// Project: MUNGA           Brick: Model Manager                             //
// Contents: Interface specification for moving entity class                 //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 01/21/95  JMA  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc.                     //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//
#if !defined(JMOVER_HPP)
#	define JMOVER_HPP

#	if !defined(MOVER_HPP)
#		include <mover.hpp>
#	endif

#	if !defined(JOINT_HPP)
#		include <joint.hpp>
#	endif

#	if !defined(SLOT_HPP)
#		include <slot.hpp>
#	endif

#	if !defined(SEGMENT_HPP)
#		include <segment.hpp>
#	endif

//##############################################################################
//########################    JointedMover    ##################################
//##############################################################################

	class JointedMover:
		public Mover
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Shared Data support
	//
	public:
		static Derivation ClassDerivations;

		static SharedData DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Message Support
	//
	#if 0
	private:
		static const HandlerEntry MessageHandlerEntries[];

	protected:
		static MessageHandlerSet MessageHandlers;
	#endif

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Attribute Support
	//
	public:
		enum{
			SegmentCountAttributeID = Mover::NextAttributeID,
			SegmentTableAttributeID,
			JointSubsystemAttributeID,
			NextAttributeID
		};

	private:
		static const IndexEntry AttributePointers[];

	protected:
		static AttributeIndexSet        AttributeIndex;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Segment Support
	//
	public:

		EntitySegment::SegmentTable
			segmentTable;

		int
			segmentCount;

		EntitySegment*
			GetSegmentFromDamageZone(CString damage_zone);

		EntitySegment*
			GetSegment(CString segment_name);

		EntitySegment*
			GetSegment(int segment_index)
				{
					Check(this);
					EntitySegment::SegmentTableIterator iterator(segmentTable);
					return iterator.GetNth(segment_index);
				}

		SlotOf<JointSubsystem*>
			jointSubsystem;

		JointSubsystem*
			GetJointSubsystem()
			{
				Check(this); return jointSubsystem.GetCurrent();
			}

		void
			GetSegmentToWorld(
				EntitySegment &my_segment,
				LinearMatrix *transform
			);

	 protected:
		void
			InitializeChildPointers(EntitySegment *current_segment);

		void
			CalcSegmentTransforms(EntitySegment *final_segment);


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//       Animation Support
	//
	public:

	typedef
			Scalar (JointedMover::*AnimationCallback)(
				ResourceDescription::ResourceID animation_number,
				Scalar carryover,
            Logical animate_joints
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Model Support
	//
	public:
		typedef void
			(JointedMover::*Performance)(Scalar time_slice);

		void
			SetPerformance(Performance performance)
				{
					Check(this);
					activePerformance = (Simulation::Performance)performance;
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction and Destruction
	//
	public:

		static JointedMover*
			Make(MakeMessage *creation_message);

		static int
			CreateDamageZoneStream (
				ResourceFile *resource_file,
				const char *model_name,
				NotationFile *model_file,
				const ResourceDirectories *directories
			);

		static ResourceDescription::ResourceID
			CreateSkeletonStream(
				ResourceFile 							*resource_file,
				const char              			*model_name,
				NotationFile   						*model_file,
				const ResourceDirectories        *directories
			);

		static Logical
			InitDestroyedVideoObjectNames(
				MemoryStream *segment_stream,
				NotationFile *model_file,
				CString		page_name,
				const ResourceDirectories *directories
			);


		static Logical
			InitVideoObjectNames(
				MemoryStream *segment_stream,
				NotationFile *model_file,
				CString		page_name,
            const ResourceDirectories *directories
			);
		static int
			GetSegmentIndex(
				CString segment_name,
				NotationFile *skl_file
			);

		static int
			GetDamageZoneIndex(
				CString 	damage_zone_name,
				NotationFile	*skl_file
			);

		JointedMover(
			MakeMessage *creation_message,
			SharedData &virtual_data
		);
		~JointedMover();

		Logical
      	TestInstance() const;
	};

//##########################################################################
//##########################    Animation    ###############################
//##########################################################################

	class AnimationInstance:
		public Plug
	{
	private:
		Logical lerpToZero;
		Scalar  deltaTime;
	public:
		AnimationInstance(JointedMover *jointed_mover);
		~AnimationInstance();

		Scalar Animate(Scalar time_slice, Logical move_joints = True);

		Logical
			LerpToPose(Scalar time_slice, Scalar time_to_lerp, Logical move_joints = True);

		Logical LerpToRest(Scalar time_slice, Scalar time_to_lerp, Logical move_joints = True);

		void SnapToRest(Logical move_joints = True);

		void
			SetAnimation(
				ResourceDescription::ResourceID animation_number,
				JointedMover::AnimationCallback finished_callback
			);

		int
			frameCount,
			jointCount,
			*jointIndices;
		float
			*footStepThreshold;
		Scalar
			*frameStart;

		void
			*keyFrames;

		void
			*currentFrameTo;

		Vector3D
			*keyJointPos,
			*rootTranslations;

		JointSubsystem
			*jointSubToAnimate;

	protected:
		int currentFrame;
		JointedMover *moverToAnimate;
		ResourceDescription *animationResource;
		JointedMover::AnimationCallback finishedCallback;
		Scalar currentTime;
	};

#endif
