// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.npc.movement;

import com.hypixel.hytale.server.core.modules.physics.component.Velocity;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.server.npc.util.NPCPhysicsMath;
import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.math.vector.Vector3d;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.ComponentType;

public class GroupSteeringAccumulator
{
    @Nonnull
    private static final ComponentType<EntityStore, TransformComponent> TRANSFORM_COMPONENT_TYPE;
    private final Vector3d sumOfVelocities;
    private final Vector3d sumOfDistances;
    private final Vector3d sumOfPositions;
    private final Vector3d temp;
    private int count;
    private double x;
    private double y;
    private double z;
    private double xViewDirection;
    private double yViewDirection;
    private double zViewDirection;
    private Vector3d componentSelector;
    private double maxRangeSquared;
    private double maxDistance;
    private float collisionViewHalfAngleCosine;
    
    public GroupSteeringAccumulator() {
        this.sumOfVelocities = new Vector3d();
        this.sumOfDistances = new Vector3d();
        this.sumOfPositions = new Vector3d();
        this.temp = new Vector3d();
        this.componentSelector = Vector3d.ALL_ONES;
        this.maxRangeSquared = Double.MAX_VALUE;
        this.maxDistance = Double.MAX_VALUE;
        this.collisionViewHalfAngleCosine = 1.0f;
    }
    
    public void begin(final double x, final double y, final double z, final double xViewDirection, final double yViewDirection, final double zViewDirection) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.xViewDirection = xViewDirection;
        this.yViewDirection = yViewDirection;
        this.zViewDirection = zViewDirection;
        this.sumOfDistances.assign(0.0);
        this.sumOfPositions.assign(0.0);
        this.sumOfVelocities.assign(0.0);
        this.count = 0;
    }
    
    public void begin(@Nonnull final Ref<EntityStore> ref, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        final HeadRotation headRotationComponent = componentAccessor.getComponent(ref, HeadRotation.getComponentType());
        assert headRotationComponent != null;
        final Vector3f headRotation = headRotationComponent.getRotation();
        NPCPhysicsMath.getViewDirection(headRotation, this.temp);
        this.temp.normalize();
        final TransformComponent transformComponent = componentAccessor.getComponent(ref, GroupSteeringAccumulator.TRANSFORM_COMPONENT_TYPE);
        assert transformComponent != null;
        final Vector3d position = transformComponent.getPosition();
        this.begin(position.getX(), position.getY(), position.getZ(), this.temp.x, this.temp.y, this.temp.z);
    }
    
    public void processEntity(@Nonnull final Ref<EntityStore> ref, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        final Velocity velocityComponent = componentAccessor.getComponent(ref, Velocity.getComponentType());
        assert velocityComponent != null;
        final Vector3d velocity = velocityComponent.getVelocity();
        final TransformComponent transformComponent = componentAccessor.getComponent(ref, GroupSteeringAccumulator.TRANSFORM_COMPONENT_TYPE);
        assert transformComponent != null;
        final Vector3d position = transformComponent.getPosition();
        final double xPosition = position.getX();
        final double yPosition = position.getY();
        final double zPosition = position.getZ();
        final double dx = xPosition - this.x;
        final double dy = yPosition - this.y;
        final double dz = zPosition - this.z;
        if (NPCPhysicsMath.dotProduct(dx, dy, dz, this.componentSelector) < this.maxRangeSquared && NPCPhysicsMath.isInViewCone(this.xViewDirection, this.yViewDirection, this.zViewDirection, this.collisionViewHalfAngleCosine, dx, dy, dz)) {
            this.sumOfDistances.add(dx, dy, dz);
            this.sumOfPositions.add(xPosition, yPosition, zPosition);
            this.sumOfVelocities.add(velocity);
            ++this.count;
        }
    }
    
    public void processEntity(@Nonnull final Ref<EntityStore> ref, final double distanceWeight, final double positionWeight, final double velocityWeight, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        final TransformComponent transformComponent = componentAccessor.getComponent(ref, GroupSteeringAccumulator.TRANSFORM_COMPONENT_TYPE);
        assert transformComponent != null;
        final Vector3d position = transformComponent.getPosition();
        final Velocity velocityComponent = componentAccessor.getComponent(ref, Velocity.getComponentType());
        assert velocityComponent != null;
        final Vector3d velocity = velocityComponent.getVelocity();
        final double dx = position.getX() - this.x;
        final double dy = position.getY() - this.y;
        final double dz = position.getZ() - this.z;
        double d = NPCPhysicsMath.dotProduct(dx, dy, dz, this.componentSelector);
        if (d < this.maxRangeSquared && NPCPhysicsMath.isInViewCone(this.xViewDirection, this.yViewDirection, this.zViewDirection, this.collisionViewHalfAngleCosine, dx, dy, dz)) {
            d = 1.0 - Math.sqrt(d) / this.maxDistance;
            double w = Math.pow(d, distanceWeight);
            this.sumOfDistances.add(dx * w, dy * w, dz * w);
            w = Math.pow(d, positionWeight);
            this.sumOfPositions.addScaled(position, w);
            w = Math.pow(d, velocityWeight);
            this.sumOfVelocities.addScaled(velocity, w);
            ++this.count;
        }
    }
    
    public void end() {
        if (this.count > 0) {
            final double scale = 1.0 / this.count;
            this.sumOfDistances.scale(scale).scale(this.componentSelector);
            this.sumOfPositions.scale(scale).scale(this.componentSelector);
            this.sumOfVelocities.scale(scale).scale(this.componentSelector);
        }
    }
    
    public void setComponentSelector(final Vector3d componentSelector) {
        this.componentSelector = componentSelector;
    }
    
    public void setMaxRange(final double maxRange) {
        this.maxRangeSquared = maxRange * maxRange;
        this.maxDistance = maxRange;
    }
    
    public void setViewConeHalfAngleCosine(final float collisionViewHalfAngleCosine) {
        this.collisionViewHalfAngleCosine = collisionViewHalfAngleCosine;
    }
    
    @Nonnull
    public Vector3d getSumOfVelocities() {
        return this.sumOfVelocities;
    }
    
    @Nonnull
    public Vector3d getSumOfDistances() {
        return this.sumOfDistances;
    }
    
    @Nonnull
    public Vector3d getSumOfPositions() {
        return this.sumOfPositions;
    }
    
    public int getCount() {
        return this.count;
    }
    
    static {
        TRANSFORM_COMPONENT_TYPE = TransformComponent.getComponentType();
    }
}
