//===========================================================================//
// File:   segment.hh                                                        //
// Project: MUNGA           Brick: Model Manager                             //
// Contents: Skeleton Heirachical element							                 //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 10/11/95  JM  Initial coding.                                             //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc.                     //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//
#if !defined(SEGMENT_HPP)
#	define SEGMENT_HPP

#	if !defined(TABLE_HPP)
#		include <table.hpp>
#	endif

#	if !defined(LINMTRX_HPP)
#		include <linmtrx.hpp>
#	endif

#	if !defined(CSTR_HPP)
#		include <cstr.hpp>
#	endif

#	if !defined(VCHAIN_HPP)
#		include <vchain.hpp>
#	endif

	class DamageZone;
	class Joint;
	class JointedMover;

//##########################################################################
//##################### Segment::VideoObjectNames ##########################
//##########################################################################

	class EntitySegment__VideoObjectNames :
		public Plug
	{
	public:
		CString*
			GetVideoObjectName(Enumeration damage_graphic_state);

		void
			AddVideoObjectName(
				const CString &new_name,
				Enumeration damage_graphic_state
			);


		EntitySegment__VideoObjectNames();
		~EntitySegment__VideoObjectNames();

	protected:

		typedef PlugOf<CString> CStringPlug;

		typedef VChainOf<CStringPlug*, Enumeration>
			VideoObjectNamesSocket;

		VideoObjectNamesSocket videoObjectNames;
	};

//##########################################################################
//##########################    Segment      ###############################
//##########################################################################

	class EntitySegment :
		public Plug
	{
		friend class JointedMover;

	public:
		typedef EntitySegment__VideoObjectNames		VideoObjectNames;
		typedef TableOf<EntitySegment*, int>				SegmentTable;
		typedef TableIteratorOf<EntitySegment*, int>	SegmentTableIterator;
		typedef PlugOf<int>									IntegerPlug;
		typedef TableOf<IntegerPlug*, int>				IntegerTable;
		typedef TableIteratorOf<IntegerPlug*, int>		IntegerTableIterator;

		enum SkeletonType {
			SkeletonType_N,		// Exterior
			SkeletonType_S,		// Interior
			SkeletonType_T,
			SkeletonType_O,
			SkeletonType_A,
			SkeletonType_B,
			SkeletonType_C,
			SkeletonType_D,
			SkeletonTypeCount
		};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Segment Data
	//
	protected:
		Logical
			segmentModified,
			siteSegment;

		LinearMatrix
			segmentToParent,
			segmentToEntity,
			baseOffset;

		typedef PlugOf<CString>												CStringPlug;
		typedef TableOf<VideoObjectNames*, Enumeration>				VideoObjectTable;
		typedef TableIteratorOf<VideoObjectNames*, Enumeration>	VideoTableIterator;

		VideoObjectTable
			videoObjectTable;

		Joint
			*jointPointer;
		int
			jointIndex;
		EntitySegment
			*parentSegment;
		int
			parentIndex;
		int
			thisIndex;

		IntegerTable
			damageZoneTable,
			childIndexTable;
		int
			primaryDamageZone;

		SegmentTable
			childPointerTable;

		CString
			segmentName;

		const LinearMatrix&
			GetSegmentToParent();

		void
			SetSegmentToEntity(LinearMatrix& new_matrix)
				{Check(this); segmentToEntity = new_matrix;}
		void
			SetSegmentToParent(LinearMatrix& new_matrix)
				{Check(this); segmentToParent = new_matrix;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Accessors
	//
	public:
		void
			ModifySegment(Logical modified = True)
				{Check(this); segmentModified = modified;}

		const LinearMatrix&
			GetBaseOffset() const
				{Check(this); return baseOffset;}

		const LinearMatrix&
			GetSegmentToEntity();

		int
			GetPrimaryDamageZone() const
				{Check(this); return primaryDamageZone;}
		int
			GetParentIndex() const
				{Check(this); return parentIndex;}

		const EntitySegment*
			GetParent() const
				{Check(this); return parentSegment;}

		int
			GetIndex() const
				{Check(this); return thisIndex;}

		int
			IsSiteSegment()
				{Check(this); return siteSegment;}

		CString
			GetName() const
				{Check(this); return segmentName;}

		int
			GetJointIndex() const
				{Check(this); return jointIndex;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Children of Segments Support
	//
	public:
		CString*
			GetVideoObjectName(
				SkeletonType skl_type = SkeletonType_N,
				Enumeration damage_graphic_state = 0
			);

		void
			AddChildIndex(int  child_index, int index);

		void
			AddChildPointer(EntitySegment *child_pointer, int index);

		void
			AddDamageZone(int damage_index, int index);

		void
			AddVideoObjectName(
				CString video_object_name,
				Enumeration skl_type,
				Enumeration damage_graphic_state = 0
			);

		IntegerTableIterator*
			MakeChildIndexTable()
				{
					Check(this);
					Check_Pointer(&childIndexTable);
					IntegerTableIterator *iterator = new
						IntegerTableIterator(&childIndexTable);
					return iterator;
				}

		IntegerTableIterator*
			MakeDamageZoneIndexTable()
				{
					Check(this);
					Check_Pointer(&damageZoneTable);
					IntegerTableIterator *iterator = new
						IntegerTableIterator(&damageZoneTable);
					return iterator;
				}

		EntitySegment(
			CString			segment_name,
			int				this_index,
			int				parent_index,
			int 				joint_index,
			Joint 			*joint_ptr,
			LinearMatrix 	&lin_matrix,
			EntitySegment	*parent_segment,
			Logical			is_site,
			int				primary_damage_zone

		);
		~EntitySegment();
	};

	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream* stream,
			EntitySegment::SkeletonType *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}
	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const EntitySegment::SkeletonType *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}

#endif
