package JAKJ . RedstoneInMotion ;

public abstract class CarriageDriveEntity extends TileEntity
{
	public boolean Continuous ;

	public boolean Active ;

	public boolean Signalled ;

	@Override
	public IconHolder GetIcon ( int Side , int Meta )
	{
		if ( Continuous )
		{
			if ( Active )
			{
				return ( CarriageDrive . Types . values ( ) [ Meta ] . ContinuousActiveIcon ) ;
			}

			return ( CarriageDrive . Types . values ( ) [ Meta ] . ContinuousIcon ) ;
		}

		if ( Active )
		{
			return ( CarriageDrive . Types . values ( ) [ Meta ] . NormalActiveIcon ) ;
		}

		return ( CarriageDrive . Types . values ( ) [ Meta ] . NormalIcon ) ;
	}

	public void ToggleContinuity ( )
	{
		Continuous = ! Continuous ;

		Propagate ( ) ;
	}

	public void ToggleActivity ( )
	{
		if ( Active && Continuous )
		{
			CooldownRemaining = ContinuousCooldown ;
		}

		Active = ! Active ;

		Propagate ( ) ;
	}

	public Directions CarriageDirection ;

	public Directions SignalDirection ;

	public void HandleNeighbourBlockChange ( )
	{
		CarriageDirection = null ;

		boolean CarriageDirectionValid = true ;

		SignalDirection = null ;

		boolean SignalDirectionValid = true ;

		for ( Directions Direction : Directions . values ( ) )
		{
			int X = xCoord + Direction . DeltaX ;
			int Y = yCoord + Direction . DeltaY ;
			int Z = zCoord + Direction . DeltaZ ;

			if ( worldObj . isAirBlock ( X , Y , Z ) )
			{
				continue ;
			}

			int Id = worldObj . getBlockId ( X , Y , Z ) ;

			if ( Id == Blocks . Carriage . GetId ( ) )
			{
				if ( CarriageDirection != null )
				{
					CarriageDirectionValid = false ;
				}
				else
				{
					CarriageDirection = Direction ;
				}
			}
			else if ( Block . Get ( Id ) . isProvidingWeakPower ( worldObj , X , Y , Z , Direction . ordinal ( ) ) > 0 )
			{
				if ( SignalDirection != null )
				{
					SignalDirectionValid = false ;
				}
				else
				{
					SignalDirection = Direction ;
				}
			}
		}

		if ( ! CarriageDirectionValid )
		{
			CarriageDirection = null ;
		}

		if ( ! SignalDirectionValid )
		{
			SignalDirection = null ;
		}
	}

	public static int ContinuousCooldown = 0 ;

	public int CooldownRemaining ;

	@Override
	public void ReadFromNbt ( NbtCompound TagCompound , boolean FromServer )
	{
		Active = TagCompound . getBoolean ( "Active" ) ;

		Continuous = TagCompound . getBoolean ( "Continuous" ) ;

		Signalled = TagCompound . getBoolean ( "Signalled" ) ;

		CooldownRemaining = TagCompound . getInteger ( "CooldownRemaining" ) ;
	}

	@Override
	public void WriteToNbt ( NbtCompound TagCompound , boolean ToClient )
	{
		TagCompound . setBoolean ( "Active" , Active ) ;

		TagCompound . setBoolean ( "Continuous" , Continuous ) ;

		TagCompound . setBoolean ( "Signalled" , Signalled ) ;

		TagCompound . setInteger ( "CooldownRemaining" , CooldownRemaining ) ;
	}

	boolean ContextStale = true ;

	@Override
	public void updateEntity ( )
	{
		if ( worldObj . isRemote )
		{
			return ;
		}

		if ( ContextStale )
		{
			HandleNeighbourBlockChange ( ) ;

			ContextStale = false ;
		}

		if ( CooldownRemaining > 0 )
		{
			CooldownRemaining -- ;

			return ;
		}

		if ( Active )
		{
			return ;
		}

		if ( SignalDirection == null )
		{
			Signalled = false ;

			return ;
		}

		if ( CarriageDirection == null )
		{
			return ;
		}

		if ( Signalled )
		{
			if ( ! Continuous )
			{
				return ;
			}
		}

		Signalled = true ;

		try
		{
			BeginMotion ( SignalDirection . Opposite ( ) , false ) ;
		}
		catch ( CarriageMotionException Exception )
		{
		}
	}

	public void BeginMotion ( Directions MotionDirection , boolean Simulate ) throws CarriageMotionException
	{
		CarriageEntity Carriage = ( CarriageEntity ) worldObj . getBlockTileEntity ( xCoord + CarriageDirection . DeltaX , yCoord + CarriageDirection . DeltaY , zCoord + CarriageDirection . DeltaZ ) ;

		CarriagePackage Package = GeneratePackage ( Carriage , CarriageDirection , MotionDirection ) ;

		if ( Simulate )
		{
			return ;
		}

		ToggleActivity ( ) ;

		BlockRecordSet NewPositions = new BlockRecordSet ( ) ;

		for ( BlockRecord Record : Package . Blocks )
		{
			Record . Pull ( this ) ;

			NewPositions . add ( Record . NextInDirection ( MotionDirection ) ) ;
		}

		for ( BlockRecord Record : Package . Blocks )
		{
			if ( NewPositions . contains ( Record ) )
			{
				WorldUtil . SneakySetBlock ( worldObj , Record . X , Record . Y , Record . Z , Blocks . MotiveSpectre . GetId ( ) , MotiveSpectre . Types . Supportive . ordinal ( ) , null ) ;
			}
			else
			{
				WorldUtil . SneakySetBlock ( worldObj , Record . X , Record . Y , Record . Z , 0 , 0 , null ) ;
			}
		}

		WorldUtil . SneakySetBlock
		(
			worldObj , Carriage . xCoord , Carriage . yCoord , Carriage . zCoord , Blocks . MotiveSpectre . GetId ( ) , MotiveSpectre . Types . Motive . ordinal ( ) , new MotiveSpectreEntity ( Package )
		) ;

		for ( BlockRecord Record : Package . Blocks )
		{
			WorldUtil . NotifyBlocks ( worldObj , Record . X , Record . Y , Record . Z , Record . Id , 0 ) ;
		}

		WorldUtil . NotifyBlocks ( worldObj , Carriage . xCoord , Carriage . yCoord , Carriage . zCoord , 0 , Blocks . MotiveSpectre . GetId ( ) ) ;
	}

	public abstract CarriagePackage GeneratePackage ( CarriageEntity Carriage , Directions CarriageDirection , Directions MotionDirection ) throws CarriageMotionException ;

	public abstract boolean Anchored ( ) ;
}
