package common.ai;

import common.entity.types.EntityLiving;
import common.entity.types.IEntityOwnable;
import common.pathfinding.PathEntity;
import common.pathfinding.PathPoint;
import common.util.BlockPos;
import common.util.ExtMath;
import common.vars.Vars;

public abstract class EntityAITarget extends EntityAIBase
{
    /** The entity that this task belongs to */
    protected final EntityLiving taskOwner;

    /**
     * If true, EntityAI targets must be able to be seen (cannot be blocked by walls) to be suitable targets.
     */
    protected boolean shouldCheckSight;

    /**
     * When true, only entities that can be reached with minimal effort will be targetted.
     */
    private boolean nearbyOnly;

    /**
     * When nearbyOnly is true: 0 -> No target, but OK to search; 1 -> Nearby target found; 2 -> Target too far.
     */
    private int targetSearchStatus;

    /**
     * When nearbyOnly is true, this throttles target searching to avoid excessive pathfinding.
     */
    private int targetSearchDelay;

    /**
     * If  @shouldCheckSight is true, the number of ticks before the interuption of this AITastk when the entity does't
     * see the target
     */
    private int targetUnseenTicks;

    public EntityAITarget(EntityLiving creature, boolean checkSight)
    {
        this(creature, checkSight, false);
    }

    public EntityAITarget(EntityLiving creature, boolean checkSight, boolean onlyNearby)
    {
        this.taskOwner = creature;
        this.shouldCheckSight = checkSight;
        this.nearbyOnly = onlyNearby;
    }

    /**
     * Returns whether an in-progress EntityAIBase should continue executing
     */
    public boolean continueExecuting()
    {
        EntityLiving entitylivingbase = this.taskOwner.getAttackTarget();

        if (entitylivingbase == null)
        {
            return false;
        }
        else if (!entitylivingbase.isEntityAlive())
        {
            return false;
        }
        else
        {
//            Team team = this.taskOwner.getTeam();
//            Team team1 = entitylivingbase.getTeam();
//
//            if (team != null && team1 == team)
//            {
//                return false;
//            }
//            else
//            {
                double d0 = this.getTargetDistance();

                if (this.taskOwner.getDistanceSqToEntity(entitylivingbase) > d0 * d0)
                {
                    return false;
                }
                else
                {
                    if (this.shouldCheckSight)
                    {
                        if (this.taskOwner.getEntitySenses().canSee(entitylivingbase))
                        {
                            this.targetUnseenTicks = 0;
                        }
                        else if (++this.targetUnseenTicks > 60)
                        {
                            return false;
                        }
                    }

                    return Vars.mobAttacks;
                }
//            }
        }
    }

    protected double getTargetDistance()
    {
    	return (double)this.taskOwner.getPathingRange();
    }

    /**
     * Execute a one shot task or start executing a continuous task
     */
    public void startExecuting()
    {
        this.targetSearchStatus = 0;
        this.targetSearchDelay = 0;
        this.targetUnseenTicks = 0;
    }

    /**
     * Resets the task
     */
    public void resetTask()
    {
        this.taskOwner.setAttackTarget((EntityLiving)null);
    }

    /**
     * A static method used to see if an entity is a suitable target through a number of checks.
     */
    public static boolean isSuitableTarget(EntityLiving attacker, EntityLiving target, boolean checkSight)
    {
        if (target == null)
        {
            return false;
        }
        else if (target == attacker)
        {
            return false;
        }
        else if (!target.isEntityAlive())
        {
            return false;
        }
        else if (!Vars.infight && target.getClass() == attacker.getClass())
        {
            return false;
        }
        else
        {
//            Team team = attacker.getTeam();
//            Team team1 = target.getTeam();
//
//            if (team != null && team1 == team)
//            {
//                return false;
//            }
//            else
//            {
                if (attacker instanceof IEntityOwnable // ) // && ((IEntityOwnable)attacker).getOwnerId() != null && !((IEntityOwnable)attacker).getOwnerId().isEmpty())
//                {
//                    if (target instanceof IEntityOwnable && ((IEntityOwnable)attacker).getOwnerId().equalsIgnoreCase(((IEntityOwnable)target).getOwnerId()))
//                    {
//                        return false;
//                    }

//                    if (
                    		&& target == ((IEntityOwnable)attacker).getOwner())
                    {
                        return false;
//                    }
                }
                else if (!Vars.mobAttacks)
                {
                    return false;
                }

                return !checkSight || attacker.getEntitySenses().canSee(target);
//            }
        }
    }

    /**
     * A method used to see if an entity is a suitable target through a number of checks. Args : entity,
     * canTargetInvinciblePlayer
     */
    protected boolean isSuitableTarget(EntityLiving target)
    {
        if (!isSuitableTarget(this.taskOwner, target, this.shouldCheckSight))
        {
            return false;
        }
        else if (!this.taskOwner.isWithinHomeDistanceFromPosition(new BlockPos(target)))
        {
            return false;
        }
        else
        {
            if (this.nearbyOnly)
            {
                if (--this.targetSearchDelay <= 0)
                {
                    this.targetSearchStatus = 0;
                }

                if (this.targetSearchStatus == 0)
                {
                    this.targetSearchStatus = this.canEasilyReach(target) ? 1 : 2;
                }

                if (this.targetSearchStatus == 2)
                {
                    return false;
                }
            }

            return true;
        }
    }

    /**
     * Checks to see if this entity can find a short path to the given target.
     *  
     * @param target the entity to find a path to
     */
    private boolean canEasilyReach(EntityLiving target)
    {
        this.targetSearchDelay = 10 + this.taskOwner.getRNG().zrange(5);
        PathEntity pathentity = this.taskOwner.getNavigator().getPathToEntityLiving(target);

        if (pathentity == null)
        {
            return false;
        }
        else
        {
            PathPoint pathpoint = pathentity.getFinalPathPoint();

            if (pathpoint == null)
            {
                return false;
            }
            else
            {
                int i = pathpoint.xCoord - ExtMath.floord(target.posX);
                int j = pathpoint.zCoord - ExtMath.floord(target.posZ);
                return (double)(i * i + j * j) <= 2.25D;
            }
        }
    }
}
