package net.minecraft.world.entity;

import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.SpawnEggItem;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.nbt.CompoundTag;
import javax.annotation.Nullable;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.Level;
import net.minecraft.network.syncher.EntityDataAccessor;

public abstract class AgableMob extends PathfinderMob {
    private static final EntityDataAccessor<Boolean> DATA_BABY_ID;
    protected int age;
    protected int forcedAge;
    protected int forcedAgeTimer;
    
    protected AgableMob(final EntityType<? extends AgableMob> aku, final Level bjw) {
        super(aku, bjw);
    }
    
    @Override
    public SpawnGroupData finalizeSpawn(final LevelAccessor bjx, final DifficultyInstance ajj, final MobSpawnType alc, @Nullable SpawnGroupData alm, @Nullable final CompoundTag jt) {
        if (alm == null) {
            alm = new AgableMobGroupData();
        }
        final AgableMobGroupData a7 = (AgableMobGroupData)alm;
        if (a7.isShouldSpawnBaby() && a7.getGroupSize() > 0 && this.random.nextFloat() <= a7.getBabySpawnChance()) {
            this.setAge(-24000);
        }
        a7.increaseGroupSizeByOne();
        return super.finalizeSpawn(bjx, ajj, alc, alm, jt);
    }
    
    @Nullable
    public abstract AgableMob getBreedOffspring(final AgableMob ako);
    
    protected void onOffspringSpawnedFromEgg(final Player ayj, final AgableMob ako) {
    }
    
    public boolean mobInteract(final Player ayj, final InteractionHand ajk) {
        final ItemStack ben4 = ayj.getItemInHand(ajk);
        final Item bei5 = ben4.getItem();
        if (bei5 instanceof SpawnEggItem && ((SpawnEggItem)bei5).spawnsEntity(ben4.getTag(), this.getType())) {
            if (!this.level.isClientSide) {
                final AgableMob ako6 = this.getBreedOffspring(this);
                if (ako6 != null) {
                    ako6.setAge(-24000);
                    ako6.moveTo(this.getX(), this.getY(), this.getZ(), 0.0f, 0.0f);
                    this.level.addFreshEntity(ako6);
                    if (ben4.hasCustomHoverName()) {
                        ako6.setCustomName(ben4.getHoverName());
                    }
                    this.onOffspringSpawnedFromEgg(ayj, ako6);
                    if (!ayj.abilities.instabuild) {
                        ben4.shrink(1);
                    }
                }
            }
            return true;
        }
        return false;
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.<Boolean>define(AgableMob.DATA_BABY_ID, false);
    }
    
    public int getAge() {
        if (this.level.isClientSide) {
            return this.entityData.<Boolean>get(AgableMob.DATA_BABY_ID) ? -1 : 1;
        }
        return this.age;
    }
    
    public void ageUp(final int integer, final boolean boolean2) {
        final int integer3;
        int integer2 = integer3 = this.getAge();
        integer2 += integer * 20;
        if (integer2 > 0) {
            integer2 = 0;
        }
        final int integer4 = integer2 - integer3;
        this.setAge(integer2);
        if (boolean2) {
            this.forcedAge += integer4;
            if (this.forcedAgeTimer == 0) {
                this.forcedAgeTimer = 40;
            }
        }
        if (this.getAge() == 0) {
            this.setAge(this.forcedAge);
        }
    }
    
    public void ageUp(final int integer) {
        this.ageUp(integer, false);
    }
    
    public void setAge(final int integer) {
        final int integer2 = this.age;
        this.age = integer;
        if ((integer2 < 0 && integer >= 0) || (integer2 >= 0 && integer < 0)) {
            this.entityData.<Boolean>set(AgableMob.DATA_BABY_ID, integer < 0);
            this.ageBoundaryReached();
        }
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag jt) {
        super.addAdditionalSaveData(jt);
        jt.putInt("Age", this.getAge());
        jt.putInt("ForcedAge", this.forcedAge);
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag jt) {
        super.readAdditionalSaveData(jt);
        this.setAge(jt.getInt("Age"));
        this.forcedAge = jt.getInt("ForcedAge");
    }
    
    @Override
    public void onSyncedDataUpdated(final EntityDataAccessor<?> sb) {
        if (AgableMob.DATA_BABY_ID.equals(sb)) {
            this.refreshDimensions();
        }
        super.onSyncedDataUpdated(sb);
    }
    
    @Override
    public void aiStep() {
        super.aiStep();
        if (this.level.isClientSide) {
            if (this.forcedAgeTimer > 0) {
                if (this.forcedAgeTimer % 4 == 0) {
                    this.level.addParticle(ParticleTypes.HAPPY_VILLAGER, this.getRandomX(1.0), this.getRandomY() + 0.5, this.getRandomZ(1.0), 0.0, 0.0, 0.0);
                }
                --this.forcedAgeTimer;
            }
        }
        else if (this.isAlive()) {
            int integer2 = this.getAge();
            if (integer2 < 0) {
                ++integer2;
                this.setAge(integer2);
            }
            else if (integer2 > 0) {
                --integer2;
                this.setAge(integer2);
            }
        }
    }
    
    protected void ageBoundaryReached() {
    }
    
    @Override
    public boolean isBaby() {
        return this.getAge() < 0;
    }
    
    static {
        DATA_BABY_ID = SynchedEntityData.<Boolean>defineId(AgableMob.class, EntityDataSerializers.BOOLEAN);
    }
    
    public static class AgableMobGroupData implements SpawnGroupData {
        private int groupSize;
        private boolean shouldSpawnBaby;
        private float babySpawnChance;
        
        public AgableMobGroupData() {
            this.shouldSpawnBaby = true;
            this.babySpawnChance = 0.05f;
        }
        
        public int getGroupSize() {
            return this.groupSize;
        }
        
        public void increaseGroupSizeByOne() {
            ++this.groupSize;
        }
        
        public boolean isShouldSpawnBaby() {
            return this.shouldSpawnBaby;
        }
        
        public void setShouldSpawnBaby(final boolean boolean1) {
            this.shouldSpawnBaby = boolean1;
        }
        
        public float getBabySpawnChance() {
            return this.babySpawnChance;
        }
        
        public void setBabySpawnChance(final float float1) {
            this.babySpawnChance = float1;
        }
    }
}
