package JAKJ . RedstoneInMotion ;

public class MotiveSpectreEntity extends TileEntity
{
	public Directions MotionDirection ;

	public BlockPosition RenderCacheKey ;

	public net . minecraft . nbt . NBTTagList PendingBlockUpdates ;

	public BlockRecord DriveRecord ;

	public boolean DriveIsAnchored ;

	public BlockRecordSet Body ;

	public int TicksExisted ;

	public static int MotionDuration = 20 ;

	public static double Velocity = 1 / ( ( double ) MotionDuration ) ;

	public void ShiftBlockPosition ( BlockRecord Record )
	{
		Record . Shift ( MotionDirection ) ;
	}

	public void ShiftPipeItemPosition ( Object Position ) throws Throwable
	{
		ModInteraction . BC_Position_x . set ( Position , ( ( Double ) ModInteraction . BC_Position_x . get ( Position ) ) + MotionDirection . DeltaX ) ;
		ModInteraction . BC_Position_y . set ( Position , ( ( Double ) ModInteraction . BC_Position_y . get ( Position ) ) + MotionDirection . DeltaY ) ;
		ModInteraction . BC_Position_z . set ( Position , ( ( Double ) ModInteraction . BC_Position_z . get ( Position ) ) + MotionDirection . DeltaZ ) ;
	}

	public void ScheduleShiftedBlockUpdate ( net . minecraft . nbt . NBTTagCompound PendingBlockUpdateRecord )
	{
		worldObj . scheduleBlockUpdateFromLoad
		(
			PendingBlockUpdateRecord . getInteger ( "X" ) + MotionDirection . DeltaX ,
			PendingBlockUpdateRecord . getInteger ( "Y" ) + MotionDirection . DeltaY ,
			PendingBlockUpdateRecord . getInteger ( "Z" ) + MotionDirection . DeltaZ ,

			PendingBlockUpdateRecord . getInteger ( "Id" ) ,

			PendingBlockUpdateRecord . getInteger ( "Delay" ) ,

			PendingBlockUpdateRecord . getInteger ( "Priority" )
		) ;
	}

	@Override
	public void updateEntity ( )
	{
		TicksExisted ++ ;

		for ( CapturedEntity Entity : CapturedEntities )
		{
			Entity . Update ( ) ;
		}

		if ( worldObj . isRemote )
		{
			return ;
		}

		if ( TicksExisted < MotionDuration )
		{
			return ;
		}

		Release ( ) ;
	}

	public void Release ( )
	{
		for ( BlockRecord Record : Body )
		{
			ShiftBlockPosition ( Record ) ;

			WorldUtil . SneakySetBlock ( worldObj , Record . X , Record . Y , Record . Z , Record . Id , Record . Meta ) ;
		}

		BlockRecordSet PipesToInitialize = new BlockRecordSet ( ) ;

		for ( BlockRecord Record : Body )
		{
			if ( Record . EntityRecord != null )
			{
				Record . Entity = net . minecraft . tileentity . TileEntity . createAndLoadEntity ( Record . EntityRecord ) ;

				worldObj . setBlockTileEntity ( Record . X , Record . Y , Record . Z , Record . Entity ) ;

				if ( ModInteraction . BC_TileGenericPipe != null )
				{
					if ( ModInteraction . BC_TileGenericPipe . isInstance ( Record . Entity ) )
					{
						PipesToInitialize . add ( Record ) ;
					}
				}
			}
		}

		for ( BlockRecord Record : PipesToInitialize )
		{
			try
			{
				Object Pipe = ModInteraction . BC_TileGenericPipe_pipe . get ( Record . Entity ) ;

				ModInteraction . BC_TileGenericPipe_initialize . invoke ( Record . Entity , Pipe ) ;

				Object Transport = ModInteraction . BC_Pipe_transport . get ( Pipe ) ;

				if ( ! ModInteraction . BC_PipeTransportItems . isInstance ( Transport ) )
				{
					continue ;
				}

				ModInteraction . BC_PipeTransportItems_delay . set ( Transport , -1 ) ;

				java . util . List DelayedEntities = ( java . util . List ) ModInteraction . BC_PipeTransportItems_delayedEntitiesToLoad . get ( Transport ) ;

				java . util . Map EntityMap = ( java . util . Map ) ModInteraction . BC_PipeTransportItems_travelingEntities . get ( Transport ) ;

				for ( Object Entity : DelayedEntities )
				{
					Object Item = ModInteraction . BC_EntityData_item . get ( Entity ) ;

					ModInteraction . BC_EntityPassiveItem_setWorld . invoke ( Item , worldObj ) ;

					int Id = ( Integer ) ModInteraction . BC_EntityPassiveItem_getEntityId . invoke ( Item ) ;

					EntityMap . put ( Id , Entity ) ;

					Object ItemPosition = ModInteraction . BC_EntityPassiveItem_position . get ( Item ) ;

					ShiftPipeItemPosition ( ItemPosition ) ;
				}

				DelayedEntities . clear ( ) ;
			}
			catch ( Throwable Throwable )
			{
				Throwable . printStackTrace ( ) ;
			}
		}

		try
		{
			CarriageDriveEntity Drive = ( CarriageDriveEntity ) worldObj . getBlockTileEntity ( DriveRecord . X , DriveRecord . Y , DriveRecord . Z ) ;

			if ( ! DriveIsAnchored )
			{
				Drive . Active = true ;
			}

			Drive . ToggleActivity ( ) ;
		}
		catch ( Throwable Throwable )
		{
			Throwable . printStackTrace ( ) ;
		}

		WorldUtil . RefreshBlock ( worldObj , xCoord , yCoord , zCoord , Blocks . Spectre . blockID , 0 ) ;

		for ( BlockRecord Record : Body )
		{
			WorldUtil . RefreshBlock ( worldObj , Record . X , Record . Y , Record . Z , 0 , Record . Id ) ;
		}

		int PendingBlockUpdateCount = PendingBlockUpdates . tagCount ( ) ;

		for ( int Index = 0 ; Index < PendingBlockUpdateCount ; Index ++ )
		{
			ScheduleShiftedBlockUpdate ( ( net . minecraft . nbt . NBTTagCompound ) PendingBlockUpdates . tagAt ( Index ) ) ;
		}
	}

	@Override
	public void Finalize ( )
	{
		if ( worldObj . isRemote )
		{
			CarriageRenderCache . Release ( RenderCacheKey ) ;
		}
	}

	@Override
	public void WriteCommonRecord ( net . minecraft . nbt . NBTTagCompound TagCompound )
	{
		TagCompound . setInteger ( "Motion" , MotionDirection . ordinal ( ) ) ;

		TagCompound . setInteger ( "RenderCacheKeyX" , RenderCacheKey . X ) ;
		TagCompound . setInteger ( "RenderCacheKeyY" , RenderCacheKey . Y ) ;
		TagCompound . setInteger ( "RenderCacheKeyZ" , RenderCacheKey . Z ) ;

		TagCompound . setInteger ( "RenderCacheKeyD" , RenderCacheKey . Dimension ) ;
	}

	@Override
	public void ReadCommonRecord ( net . minecraft . nbt . NBTTagCompound TagCompound )
	{
		MotionDirection = Directions . values ( ) [ TagCompound . getInteger ( "Motion" ) ] ;

		RenderCacheKey = new BlockPosition ( TagCompound . getInteger ( "RenderCacheKeyX" ) , TagCompound . getInteger ( "RenderCacheKeyY" ) , TagCompound . getInteger ( "RenderCacheKeyZ" ) ,
			TagCompound . getInteger ( "RenderCacheKeyD" ) , null ) ;
	}

	@Override
	public void WriteServerRecord ( net . minecraft . nbt . NBTTagCompound TagCompound )
	{
		TagCompound . setInteger ( "DriveX" , DriveRecord . X ) ;
		TagCompound . setInteger ( "DriveY" , DriveRecord . Y ) ;
		TagCompound . setInteger ( "DriveZ" , DriveRecord . Z ) ;

		TagCompound . setBoolean ( "DriveIsAnchored" , DriveIsAnchored ) ;

		TagCompound . setTag ( "PendingBlockUpdates" , PendingBlockUpdates ) ;

		{
			net . minecraft . nbt . NBTTagList BodyRecord = new net . minecraft . nbt . NBTTagList ( ) ;

			for ( BlockRecord Record : Body )
			{
				net . minecraft . nbt . NBTTagCompound BodyBlockRecord = new net . minecraft . nbt . NBTTagCompound ( ) ;

				BodyBlockRecord . setInteger ( "X" , Record . X ) ;
				BodyBlockRecord . setInteger ( "Y" , Record . Y ) ;
				BodyBlockRecord . setInteger ( "Z" , Record . Z ) ;

				BodyBlockRecord . setInteger ( "Id" , Record . Id ) ;

				BodyBlockRecord . setInteger ( "Meta" , Record . Meta ) ;

				if ( Record . EntityRecord != null )
				{
					BodyBlockRecord . setCompoundTag ( "EntityRecord" , Record . EntityRecord ) ;
				}

				BodyRecord . appendTag ( BodyBlockRecord ) ;
			}

			TagCompound . setTag ( "Body" , BodyRecord ) ;
		}
	}

	@Override
	public void ReadServerRecord ( net . minecraft . nbt . NBTTagCompound TagCompound )
	{
		DriveRecord = new BlockRecord ( TagCompound . getInteger ( "DriveX" ) , TagCompound . getInteger ( "DriveY" ) , TagCompound . getInteger ( "DriveZ" ) ) ;

		DriveIsAnchored = TagCompound . getBoolean ( "DriveIsAnchored" ) ;

		PendingBlockUpdates = TagCompound . getTagList ( "PendingBlockUpdates" ) ;

		Body = new BlockRecordSet ( ) ;

		{
			net . minecraft . nbt . NBTTagList BodyRecord = TagCompound . getTagList ( "Body" ) ;

			int BodyBlockCount = BodyRecord . tagCount ( ) ;

			for ( int Index = 0 ; Index < BodyBlockCount ; Index ++ )
			{
				net . minecraft . nbt . NBTTagCompound BodyBlockRecord = ( net . minecraft . nbt . NBTTagCompound ) BodyRecord . tagAt ( Index ) ;

				BlockRecord Record = new BlockRecord ( BodyBlockRecord . getInteger ( "X" ) , BodyBlockRecord . getInteger ( "Y" ) , BodyBlockRecord . getInteger ( "Z" ) ) ;

				Record . Id = BodyBlockRecord . getInteger ( "Id" ) ;

				Record . Meta = BodyBlockRecord . getInteger ( "Meta" ) ;

				if ( BodyBlockRecord . hasKey ( "EntityRecord" ) )
				{
					Record . EntityRecord = BodyBlockRecord . getCompoundTag ( "EntityRecord" ) ;
				}

				Body . add ( Record ) ;
			}
		}
	}

	@Override
	public void WriteClientRecord ( net . minecraft . nbt . NBTTagCompound TagCompound )
	{
		net . minecraft . nbt . NBTTagList CapturedEntityRecords = new net . minecraft . nbt . NBTTagList ( ) ;

		for ( CapturedEntity Entity : CapturedEntities )
		{
			net . minecraft . nbt . NBTTagCompound CapturedEntityRecord = new net . minecraft . nbt . NBTTagCompound ( ) ;

			CapturedEntityRecord . setInteger ( "Id" , Entity . Entity . entityId ) ;

			CapturedEntityRecord . setDouble ( "InitialX" , Entity . InitialX ) ;
			CapturedEntityRecord . setDouble ( "InitialY" , Entity . InitialY ) ;
			CapturedEntityRecord . setDouble ( "InitialZ" , Entity . InitialZ ) ;

			CapturedEntityRecords . appendTag ( CapturedEntityRecord ) ;
		}

		TagCompound . setTag ( "CapturedEntities" , CapturedEntityRecords ) ;
	}

	@Override
	public void ReadClientRecord ( net . minecraft . nbt . NBTTagCompound TagCompound )
	{
		net . minecraft . nbt . NBTTagList CapturedEntityRecords = TagCompound . getTagList ( "CapturedEntities" ) ;

		CapturedEntities . clear ( ) ;

		int CapturedEntityCount = CapturedEntityRecords . tagCount ( ) ;

		for ( int Index = 0 ; Index < CapturedEntityCount ; Index ++ )
		{
			net . minecraft . nbt . NBTTagCompound EntityRecord = ( net . minecraft . nbt . NBTTagCompound ) CapturedEntityRecords . tagAt ( Index ) ;

			net . minecraft . entity . Entity Entity = worldObj . getEntityByID ( EntityRecord . getInteger ( "Id" ) ) ;

			if ( Entity == null )
			{
				continue ;
			}

			CapturedEntities . add ( new CapturedEntity ( Entity , EntityRecord . getDouble ( "InitialX" ) , EntityRecord . getDouble ( "InitialY" ) , EntityRecord . getDouble ( "InitialZ" ) ) ) ;
		}
	}

	public class CapturedEntity
	{
		public net . minecraft . entity . Entity Entity ;

		public double InitialX ;
		public double InitialY ;
		public double InitialZ ;

		boolean WasOnGround ;

		boolean WasAirBorne ;

		public CapturedEntity ( net . minecraft . entity . Entity Entity )
		{
			this ( Entity , Entity . posX , Entity . posY , Entity . posZ ) ;
		}

		public CapturedEntity ( net . minecraft . entity . Entity Entity , double InitialX , double InitialY , double InitialZ )
		{
			this . Entity = Entity ;

			this . InitialX = InitialX ;
			this . InitialY = InitialY ;
			this . InitialZ = InitialZ ;

			WasOnGround = Entity . onGround ;

			WasAirBorne = Entity . isAirBorne ;

			Update ( ) ;
		}

		public void SetPosition ( double OffsetX , double OffsetY , double OffsetZ )
		{
			Entity . setPosition ( InitialX + OffsetX , InitialY + OffsetY + Entity . yOffset , InitialZ + OffsetZ ) ;
		}

		public void Update ( )
		{
			Entity . fallDistance = 0 ;

			if ( TicksExisted == MotionDuration )
			{
				Entity . motionX = 0 ;
				Entity . motionY = 0 ;
				Entity . motionZ = 0 ;

				SetPosition ( MotionDirection . DeltaX , MotionDirection . DeltaY , MotionDirection . DeltaZ ) ;

				Entity . prevPosX = Entity . posX ;
				Entity . prevPosY = Entity . posY ;
				Entity . prevPosZ = Entity . posZ ;

				Entity . onGround = WasOnGround ;

				Entity . isAirBorne = WasAirBorne ;

				return ;
			}

			Entity . onGround = false ;

			Entity . isAirBorne = true ;

			Entity . motionX = Velocity * MotionDirection . DeltaX ;
			Entity . motionY = Velocity * MotionDirection . DeltaY ;
			Entity . motionZ = Velocity * MotionDirection . DeltaZ ;

			SetPosition ( Entity . motionX * TicksExisted , Entity . motionY * TicksExisted , Entity . motionZ * TicksExisted ) ;

			Entity . prevPosX = Entity . posX - Entity . motionX ;
			Entity . prevPosY = Entity . posY - Entity . motionY ;
			Entity . prevPosZ = Entity . posZ - Entity . motionZ ;
		}
	}

	public java . util . ArrayList < CapturedEntity > CapturedEntities = new java . util . ArrayList < CapturedEntity > ( ) ;

	public void Absorb ( CarriagePackage Package )
	{
		MotionDirection = Package . MotionDirection ;

		Body = Package . Blocks ;

		RenderCacheKey = Package . RenderCacheKey ;

		PendingBlockUpdates = Package . PendingBlockUpdates ;

		DriveRecord = new BlockRecord ( Package . DriveRecord ) ;

		if ( ! Package . DriveIsAnchored )
		{
			DriveRecord . Shift ( Package . MotionDirection ) ;
		}

		{
			net . minecraft . util . AxisAlignedBB EntityCaptureBox = net . minecraft . util . AxisAlignedBB . getBoundingBox
			(
				Package . MinX - 5 , Package . MinY - 5 , Package . MinZ - 5 , Package . MaxX + 5 , Package . MaxY + 5 , Package . MaxZ + 5
			) ;

			java . util . List EntitiesFound = Package . World . getEntitiesWithinAABB ( net . minecraft . entity . Entity . class , EntityCaptureBox ) ;

			for ( Object EntityObject : EntitiesFound )
			{
				net . minecraft . entity . Entity Entity = ( net . minecraft . entity . Entity ) EntityObject ;

				BlockRecord PositionCheck = new BlockRecord ( ( int ) Math . floor ( Entity . posX ) , ( int ) Math . floor ( Entity . posY ) , ( int ) Math . floor ( Entity . posZ ) ) ;

				if ( ! Body . contains ( PositionCheck ) )
				{
					PositionCheck . Y -- ;

					if ( ! Body . contains ( PositionCheck ) )
					{
						PositionCheck . Y -- ;

						if ( ! Body . contains ( PositionCheck ) )
						{
							Entity = null ;
						}
					}
				}

				if ( Entity == null )
				{
					continue ;
				}

				if ( Entity instanceof net . minecraft . entity . player . EntityPlayer )
				{
					if ( ! Configuration . CarriageMotion . CapturePlayerEntities )
					{
						continue ;
					}
				}
				else if ( Entity instanceof net . minecraft . entity . EntityLiving )
				{
					if ( ! Configuration . CarriageMotion . CaptureOtherLivingEntities )
					{
						continue ;
					}
				}
				else if ( Entity instanceof net . minecraft . entity . item . EntityItem )
				{
					if ( ! Configuration . CarriageMotion . CaptureItemEntities )
					{
						continue ;
					}
				}
				else if ( ! Configuration . CarriageMotion . CaptureOtherEntities )
				{
					continue ;
				}

				CapturedEntities . add ( new CapturedEntity ( ( net . minecraft . entity . Entity ) Entity ) ) ;
			}
		}
	}

	@Override
	public net . minecraft . util . AxisAlignedBB getRenderBoundingBox ( )
	{
		return ( INFINITE_EXTENT_AABB ) ;
	}
}
