package common.entity.npc;

import common.ai.EntityAIBase;
import common.ai.EntityMoveHelper;
import common.attributes.Attributes;
import common.block.Block;
import common.entity.types.EntityLiving;
import common.potion.Potion;
import common.rng.Random;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.ExtMath;
import common.world.World;

public abstract class EntityFlyingNPC extends EntityNPC
{
    public EntityFlyingNPC(World worldIn)
    {
        super(worldIn);
        this.moveHelper = new FlyMoveHelper(this);
        this.tasks.addTask(5, new AIRandomFly(this));
        this.tasks.addTask(7, new AILookAround(this));
    }

    protected void applyEntityAttributes()
    {
        super.applyEntityAttributes();
        this.getEntityAttribute(Attributes.FOLLOW_RANGE).setBaseValue(48.0D);
    }
    
    public float getArmRotation() {
    	return 0.0f;
    }
    
    public float getLegRotation() {
    	return 0.2f;
    }

    public void fall(float distance, float damageMultiplier)
    {
    }

    protected void updateFallState(double y, boolean onGroundIn, Block blockIn, BlockPos pos)
    {
    }
    
    public boolean isFlying() {
    	return true;
    }
    
//    public boolean canFlyFullSpeed() {
//    	return true;
//    }
    
//    public boolean canNaturallyFly() {
//    	return true;
//    }
    
    public void moveEntityWithHeading(float strafe, float forward)
    {
    	if(this.isPlayer()) {
    		super.moveEntityWithHeading(strafe, forward);
    		return;
    	}
        if (this.isInLiquid())
        {
            this.moveFlying(strafe, forward, 0.02F);
            this.moveEntity(this.motionX, this.motionY, this.motionZ);
            this.motionX *= 0.800000011920929D;
            this.motionY *= 0.800000011920929D;
            this.motionZ *= 0.800000011920929D;
        }
        else if (this.isInMolten())
        {
            this.moveFlying(strafe, forward, 0.02F);
            this.moveEntity(this.motionX, this.motionY, this.motionZ);
            this.motionX *= 0.5D;
            this.motionY *= 0.5D;
            this.motionZ *= 0.5D;
        }
        else
        {
            float f = 0.91F;

            if (this.onGround)
            {
                f = this.worldObj.getState(new BlockPos(ExtMath.floord(this.posX), ExtMath.floord(this.getEntityBoundingBox().minY) - 1, ExtMath.floord(this.posZ))).getBlock().slipperiness * 0.91F;
            }

            float f1 = 0.16277136F / (f * f * f);
            this.moveFlying(strafe, forward, this.onGround ? 0.1F * f1 : 0.02F);
            f = 0.91F;

            if (this.onGround)
            {
                f = this.worldObj.getState(new BlockPos(ExtMath.floord(this.posX), ExtMath.floord(this.getEntityBoundingBox().minY) - 1, ExtMath.floord(this.posZ))).getBlock().slipperiness * 0.91F;
            }

            this.moveEntity(this.motionX, this.motionY, this.motionZ);
            this.motionX *= (double)f;
            this.motionY *= (double)f;
            this.motionZ *= (double)f;
        }

        this.prevLswingAmount = this.lswingAmount;
        double d1 = this.posX - this.prevX;
        double d0 = this.posZ - this.prevZ;
        float f2 = ExtMath.sqrtd(d1 * d1 + d0 * d0) * 4.0F;

        if (f2 > 1.0F)
        {
            f2 = 1.0F;
        }

        this.lswingAmount += (f2 - this.lswingAmount) * 0.4F;
        this.limbSwing += this.lswingAmount;
    }
    
    public boolean isOnLadder()
    {
        return false;
    }

    public boolean isPotionApplicable(Potion potion)
    {
    	return potion != Potion.FLYING && super.isPotionApplicable(potion);
    }

    static class AILookAround extends EntityAIBase
    {
        private EntityFlyingNPC parentEntity;

        public AILookAround(EntityFlyingNPC entity)
        {
            this.parentEntity = entity;
            this.setMutexBits(2);
        }

        public boolean shouldExecute()
        {
            return true;
        }

        public void updateTask()
        {
            if (this.parentEntity.getAttackTarget() == null)
            {
                this.parentEntity.yawOffset = this.parentEntity.rotYaw = -((float)ExtMath.atan2(this.parentEntity.motionX, this.parentEntity.motionZ)) * 180.0F / (float)Math.PI;
            }
            else
            {
                EntityLiving entitylivingbase = this.parentEntity.getAttackTarget();
                double d0 = 64.0D;

                if (entitylivingbase.getDistanceSqToEntity(this.parentEntity) < d0 * d0)
                {
                    double d1 = entitylivingbase.posX - this.parentEntity.posX;
                    double d2 = entitylivingbase.posZ - this.parentEntity.posZ;
                    this.parentEntity.yawOffset = this.parentEntity.rotYaw = -((float)ExtMath.atan2(d1, d2)) * 180.0F / (float)Math.PI;
                }
            }
        }
    }

    static class AIRandomFly extends EntityAIBase
    {
        private EntityFlyingNPC parentEntity;

        public AIRandomFly(EntityFlyingNPC entity)
        {
            this.parentEntity = entity;
            this.setMutexBits(1);
        }

        public boolean shouldExecute()
        {
            EntityMoveHelper entitymovehelper = this.parentEntity.getMoveHelper();

            if (!entitymovehelper.isUpdating())
            {
                return true;
            }
            else
            {
                double d0 = entitymovehelper.getX() - this.parentEntity.posX;
                double d1 = entitymovehelper.getY() - this.parentEntity.posY;
                double d2 = entitymovehelper.getZ() - this.parentEntity.posZ;
                double d3 = d0 * d0 + d1 * d1 + d2 * d2;
                return d3 < 1.0D || d3 > 3600.0D;
            }
        }

        public boolean continueExecuting()
        {
            return false;
        }

        public void startExecuting()
        {
            Random random = this.parentEntity.getRNG();
            double d0 = this.parentEntity.posX + (double)((random.floatv() * 2.0F - 1.0F) * 16.0F);
            double d1 = this.parentEntity.posY + (double)((random.floatv() * 2.0F - 1.0F) * 16.0F);
            double d2 = this.parentEntity.posZ + (double)((random.floatv() * 2.0F - 1.0F) * 16.0F);
            this.parentEntity.getMoveHelper().setMoveTo(d0, d1, d2, 1.0D);
        }
    }

    static class FlyMoveHelper extends EntityMoveHelper
    {
        private EntityFlyingNPC parentEntity;
        private int courseChangeCooldown;

        public FlyMoveHelper(EntityFlyingNPC entity)
        {
            super(entity);
            this.parentEntity = entity;
        }

        public void onUpdateMoveHelper()
        {
            if (this.update)
            {
                double d0 = this.posX - this.parentEntity.posX;
                double d1 = this.posY - this.parentEntity.posY;
                double d2 = this.posZ - this.parentEntity.posZ;
                double d3 = d0 * d0 + d1 * d1 + d2 * d2;

                if (this.courseChangeCooldown-- <= 0)
                {
                    this.courseChangeCooldown += this.parentEntity.getRNG().range(2, 6);
                    d3 = (double)ExtMath.sqrtd(d3);

                    if (this.isNotColliding(this.posX, this.posY, this.posZ, d3))
                    {
                        this.parentEntity.motionX += d0 / d3 * 0.1D;
                        this.parentEntity.motionY += d1 / d3 * 0.1D;
                        this.parentEntity.motionZ += d2 / d3 * 0.1D;
                    }
                    else
                    {
                        this.update = false;
                    }
                }
            }
        }

        private boolean isNotColliding(double x, double y, double z, double p_179926_7_)
        {
            double d0 = (x - this.parentEntity.posX) / p_179926_7_;
            double d1 = (y - this.parentEntity.posY) / p_179926_7_;
            double d2 = (z - this.parentEntity.posZ) / p_179926_7_;
            BoundingBox axisalignedbb = this.parentEntity.getEntityBoundingBox();

            for (int i = 1; (double)i < p_179926_7_; ++i)
            {
                axisalignedbb = axisalignedbb.offset(d0, d1, d2);

                if (!this.parentEntity.worldObj.getCollidingBoundingBoxes(this.parentEntity, axisalignedbb).isEmpty())
                {
                    return false;
                }
            }

            return true;
        }
    }
}
