package cn.mcmod.tofucraft.entity;

import cn.mcmod.tofucraft.entity.ai.*;
import cn.mcmod.tofucraft.item.ItemLoader;
import cn.mcmod.tofucraft.sound.TofuSounds;
import cn.mcmod.tofucraft.util.WorldUtils;
import cn.mcmod.tofucraft.world.village.TofuVillage;
import cn.mcmod.tofucraft.world.village.TofuVillageCollection;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.*;
import net.minecraft.entity.ai.*;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.item.EntityXPOrb;
import net.minecraft.entity.monster.AbstractIllager;
import net.minecraft.entity.monster.EntityVex;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.entity.monster.IMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.init.MobEffects;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.inventory.InventoryBasic;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.pathfinding.PathNavigateGround;
import net.minecraft.potion.PotionEffect;
import net.minecraft.stats.StatList;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.village.MerchantRecipe;
import net.minecraft.village.MerchantRecipeList;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

import javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class EntityTofunian extends EntityAgeable implements INpc, IMerchant {
    private static final DataParameter<Integer> TOFUPROFESSION = EntityDataManager.createKey(EntityTofunian.class, DataSerializers.VARINT);
    private int randomTickDivider;

    private boolean isMating;
    TofuVillage village;
    private int tofunianCareerLevel;
    private int tofunianTimeUntilReset;
    private boolean isWillingToMate;
    private boolean needsInitilization;
    private int wealth;
    private java.util.UUID lastBuyingPlayer;
    @Nullable
    private EntityPlayer buyingPlayer;
    @Nullable
    private MerchantRecipeList buyingList;
    private boolean isLookingForHome;
    private final InventoryBasic villagerInventory;
    private boolean isAleadyUpdate;

    public EntityTofunian(World worldIn) {
        super(worldIn);
        this.villagerInventory = new InventoryBasic("Items", false, 8);
        this.setSize(0.45F, 1.4F);
        ((PathNavigateGround) this.getNavigator()).setBreakDoors(true);
        this.setCanPickUpLoot(true);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
    protected void initEntityAI() {
        this.tasks.addTask(0, new EntityAISwimming(this));
        this.tasks.addTask(2, new EntityAITofunianTradePlayer(this));
        this.tasks.addTask(2, new EntityAITofunianLookAtTradePlayer(this));
        this.tasks.addTask(3, new EntityAIMoveIndoors(this));
        this.tasks.addTask(4, new EntityAIRestrictOpenDoor(this));
        this.tasks.addTask(5, new EntityAIOpenDoor(this, true));
        this.tasks.addTask(6, new EntityAIMoveTowardsRestriction(this, 0.6D));
        this.tasks.addTask(7, new EntityAITofunianMate(this));
        this.tasks.addTask(8, new EntityAIUseItemOnLeftHand(this, new ItemStack(ItemLoader.tofu_food, 1, 3), SoundEvents.ENTITY_GENERIC_EAT, (p_213736_1_) -> {
            return this.getHealth() < this.getMaxHealth() && this.world.rand.nextInt(100) == 0;
        }) {

            @Override
            public boolean shouldExecute() {
                if (super.shouldExecute() && hasEnoughCraftedItem(0, 1)) {
                    for (int i = 0; i < getVillagerInventory().getSizeInventory(); ++i) {
                        ItemStack itemstack = getVillagerInventory().getStackInSlot(i);
                        if (itemstack.getItem() == ItemLoader.tofu_food) {
                            itemstack.shrink(1);
                            return true;
                        }
                    }
                    return false;

                } else {
                    return false;
                }
            }

            @Override
            public void resetTask() {
                super.resetTask();
                heal(2.0F);
            }
        });
        this.tasks.addTask(9, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F));
        this.tasks.addTask(9, new EntityAITofunianInteract(this));
        this.tasks.addTask(9, new EntityAIWanderAvoidWater(this, 0.6D));
        this.tasks.addTask(10, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F));
        this.targetTasks.addTask(0, new EntityAIHurtByTarget(this, true));
    }

    protected void applyEntityAttributes() {
        super.applyEntityAttributes();

        this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.5D);
        this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(2.0D);
    }

    @SideOnly(Side.CLIENT)
    public void handleStatusUpdate(byte id) {
        if (id == 12) {
            this.spawnParticles(EnumParticleTypes.HEART);
        } else if (id == 13) {
            this.spawnParticles(EnumParticleTypes.VILLAGER_ANGRY);
        } else if (id == 14) {
            this.spawnParticles(EnumParticleTypes.VILLAGER_HAPPY);
        } else {
            super.handleStatusUpdate(id);
        }
    }

    @SideOnly(Side.CLIENT)
    private void spawnParticles(EnumParticleTypes particleType) {
        for (int i = 0; i < 5; ++i) {
            double d0 = this.rand.nextGaussian() * 0.02D;
            double d1 = this.rand.nextGaussian() * 0.02D;
            double d2 = this.rand.nextGaussian() * 0.02D;
            this.world.spawnParticle(particleType, this.posX + (double) (this.rand.nextFloat() * this.width * 2.0F) - (double) this.width, this.posY + 1.0D + (double) (this.rand.nextFloat() * this.height), this.posZ + (double) (this.rand.nextFloat() * this.width * 2.0F) - (double) this.width, d0, d1, d2);
        }
    }

    public boolean canBeLeashedTo(EntityPlayer player) {
        return false;
    }

    @Override
    protected void updateAITasks() {
        if (--this.randomTickDivider <= 0) {
            BlockPos blockpos = new BlockPos(this);

            String s = TofuVillageCollection.fileNameForProvider(this.world.provider);

            ((TofuVillageCollection) Objects.requireNonNull(this.world.getPerWorldStorage().getOrLoadData(TofuVillageCollection.class, s))).addToVillagerPositionList(blockpos);
            this.randomTickDivider = 70 + this.rand.nextInt(50);

            this.village = ((TofuVillageCollection) Objects.requireNonNull(this.world.getPerWorldStorage().getOrLoadData(TofuVillageCollection.class, s))).getNearestVillage(blockpos, 32);

            if (this.village == null) {
                this.detachHome();
            } else {
                BlockPos blockpos1 = this.village.getCenter();
                this.setHomePosAndDistance(blockpos1, this.village.getTofuVillageRadius());

                if (this.isLookingForHome) {
                    this.isLookingForHome = false;
                    this.village.setDefaultPlayerReputation(5);
                }
            }
        }

        if (!this.isTrading() && this.tofunianTimeUntilReset > 0) {
            --this.tofunianTimeUntilReset;

            if (this.tofunianTimeUntilReset <= 0) {
                if (this.needsInitilization) {
                    for (MerchantRecipe merchantrecipe : this.buyingList) {
                        if (merchantrecipe.isRecipeDisabled()) {
                            merchantrecipe.increaseMaxTradeUses(this.rand.nextInt(6) + this.rand.nextInt(6) + 2);
                        }
                    }

                    this.initTrades();
                    this.needsInitilization = false;

                    if (this.lastBuyingPlayer != null) {
                        this.world.setEntityState(this, (byte) 14);

                    }
                }

                this.addPotionEffect(new PotionEffect(MobEffects.REGENERATION, 200, 0));
            }
        }

        super.updateAITasks();
    }

    public void setLookingForHome() {
        this.isLookingForHome = true;
    }

    public boolean isMating() {
        return this.isMating;
    }

    public void setMating(boolean mating) {
        this.isMating = mating;
    }

    public void setCustomer(@Nullable EntityPlayer player) {
        this.buyingPlayer = player;
    }

    @Nullable
    public EntityPlayer getCustomer() {
        return this.buyingPlayer;
    }

    public boolean isTrading() {
        return this.buyingPlayer != null;
    }

    @Override
    public void useRecipe(MerchantRecipe recipe) {

        recipe.incrementToolUses();
        this.livingSoundTime = -this.getTalkInterval();
        this.playSound(TofuSounds.TOFUNIAN_YES, this.getSoundVolume(), this.getSoundPitch());
        int i = 3 + this.rand.nextInt(4);

        if (recipe.getToolUses() == 1 || this.rand.nextInt(5) == 0) {
            this.tofunianTimeUntilReset = 40;
            this.needsInitilization = true;
            this.isWillingToMate = true;

            //update TofunianTrade
            if (this.tofunianCareerLevel != 0) {

                ++this.tofunianCareerLevel;

            } else {

                this.tofunianCareerLevel = 2;

            }


            if (this.buyingPlayer != null) {
                this.lastBuyingPlayer = this.buyingPlayer.getUniqueID();
            } else {
                this.lastBuyingPlayer = null;
            }

            i += 5;
        }

        if (recipe.getItemToBuy().getItem() == ItemLoader.zundaruby) {
            this.wealth += recipe.getItemToBuy().getCount();
        }

        if (recipe.getRewardsExp()) {
            this.world.spawnEntity(new EntityXPOrb(this.world, this.posX, this.posY + 0.5D, this.posZ, i));
        }

    }

    public void onLivingUpdate() {
        this.updateArmSwingProgress();

        super.onLivingUpdate();

        if (!this.world.isRemote) {
            if (this.rand.nextInt(600) == 0 && this.deathTime == 0) {
                this.heal(1.0F);
            }
        }
    }

    public boolean processInteract(EntityPlayer player, EnumHand hand) {
        ItemStack itemstack = player.getHeldItem(hand);
        boolean flag = itemstack.getItem() == Items.NAME_TAG;

        if (flag) {
            itemstack.interactWithEntity(player, this, hand);
            return true;
        } else if (!this.holdingSpawnEggOfClass(itemstack, this.getClass()) && this.isEntityAlive() && !this.isTrading() && !this.isChild() && !player.isSneaking()) {
            if (this.buyingList == null) {
                this.initTrades();
            }

            if (hand == EnumHand.MAIN_HAND) {
                player.addStat(StatList.TALKED_TO_VILLAGER);
            }

            if (!this.world.isRemote && !this.buyingList.isEmpty()) {
                this.setCustomer(player);
                player.displayVillagerTradeGui(this);
            } else if (this.buyingList.isEmpty()) {
                return super.processInteract(player, hand);
            }

            return true;
        } else {
            return super.processInteract(player, hand);
        }
    }

    @Override
    protected void entityInit() {

        super.entityInit();

        this.getDataManager().register(TOFUPROFESSION, Integer.valueOf(0));
    }

    @Override
    public void writeEntityToNBT(NBTTagCompound compound) {

        super.writeEntityToNBT(compound);
        compound.setInteger("tofu_profession", this.getDataManager().get(TOFUPROFESSION));
        compound.setInteger("CareerLevel", this.tofunianCareerLevel);
        compound.setInteger("Riches", this.wealth);

        if (this.buyingList != null) {
            compound.setTag("Offers", this.buyingList.getRecipiesAsTags());
        }

        compound.setBoolean("Willing", this.isWillingToMate);

        NBTTagList nbttaglist = new NBTTagList();

        for (int i = 0; i < this.villagerInventory.getSizeInventory(); ++i) {
            ItemStack itemstack = this.villagerInventory.getStackInSlot(i);

            if (!itemstack.isEmpty()) {
                nbttaglist.appendTag(itemstack.writeToNBT(new NBTTagCompound()));
            }
        }

        compound.setTag("Inventory", nbttaglist);
    }

    public void readEntityFromNBT(NBTTagCompound compound) {
        super.readEntityFromNBT(compound);
        this.getDataManager().set(TOFUPROFESSION, compound.getInteger("tofu_profession"));
        //Load villager's CarrierLevel and make it usable as tofunian CareerLevel
        this.tofunianCareerLevel = compound.getInteger("CareerLevel");

        this.wealth = compound.getInteger("Riches");

        if (compound.hasKey("Offers", 10)) {
            NBTTagCompound nbttagcompound = compound.getCompoundTag("Offers");
            this.buyingList = new MerchantRecipeList(nbttagcompound);
        }

        this.isWillingToMate = compound.getBoolean("Willing");

        NBTTagList nbttaglist = compound.getTagList("Inventory", 10);

        for (int i = 0; i < nbttaglist.tagCount(); ++i) {
            ItemStack itemstack = new ItemStack(nbttaglist.getCompoundTagAt(i));

            if (!itemstack.isEmpty()) {
                this.villagerInventory.addItem(itemstack);
            }
        }

        this.setCanPickUpLoot(true);
        this.updateEntityAI();
    }

    @Override
    protected SoundEvent getAmbientSound() {

        return TofuSounds.TOFUNIAN_AMBIENT;
    }


    @Override
    protected SoundEvent getDeathSound() {

        return null;
    }

    @Override
    protected SoundEvent getHurtSound(DamageSource damageSource) {

        return null;
    }

    protected boolean canDespawn() {
        return false;
    }


    public TofuProfession getTofuProfession() {

        return TofuProfession.get(this.getDataManager().get(TOFUPROFESSION));
    }

    public void initTofuProfession() {
        int randValRole = rand.nextInt(TofuProfession.values().length);

        if (randValRole == TofuProfession.FISHERMAN.ordinal()) {

            this.setFisher();

        } else if (randValRole == TofuProfession.GUARD.ordinal()) {

            this.setGuard();

        } else if (randValRole == TofuProfession.TOFUCOOK.ordinal()) {

            this.setTofuCook();

        } else if (randValRole == TofuProfession.TOFUSMITH.ordinal()) {

            this.setTofuSmith();

        }
    }

    public void setTofuProfession(int profession) {
        if (profession == TofuProfession.FISHERMAN.ordinal()) {

            this.setFisher();

        } else if (profession == TofuProfession.GUARD.ordinal()) {

            this.setGuard();

        } else if (profession == TofuProfession.TOFUCOOK.ordinal()) {

            this.setTofuCook();

        } else if (profession == TofuProfession.TOFUSMITH.ordinal()) {

            this.setTofuSmith();

        }
    }

    @Nullable
    @Override
    public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata) {

        IEntityLivingData data = super.onInitialSpawn(difficulty, livingdata);

        initTofuProfession();

        updateEntityAI();

        initTrades();

        return data;

    }

    public void updateEntityAI() {

        if (!this.isAleadyUpdate) {
            if (canGuard()) {
                this.tasks.addTask(1, new EntityAIAttackMelee(this, 0.65F, true));
                this.targetTasks.addTask(1, new EntityAINearestAttackableTarget<>(this, EntityTofuChinger.class, false));
                this.targetTasks.addTask(1, new EntityAINearestAttackableTarget<>(this, EntityZombie.class, false));
                this.targetTasks.addTask(1, new EntityAINearestAttackableTarget<>(this, AbstractIllager.class, false));
                this.targetTasks.addTask(1, new EntityAINearestAttackableTarget<>(this, EntityVex.class, false));
                this.targetTasks.addTask(1, new EntityAINearestAttackableTarget<>(this, EntityTofuGandlem.class, false));

                if (!this.isChild()) {
                    this.tasks.addTask(6, new EntityAIUseItemOnLeftHand<>(this, new ItemStack(ItemLoader.bugle), TofuSounds.TOFUBUGLE, (p_213736_1_) -> {
                        return WorldUtils.isMorning(this.world) && this.world.rand.nextInt(350) == 0;
                    }));
                }
            } else {
                this.tasks.addTask(1, new EntityAITofunianAvoidEntity<>(this, EntityTofuChinger.class, 8.0F, 0.6D, 0.6D));
                this.tasks.addTask(1, new EntityAITofunianAvoidEntity<>(this, EntityZombie.class, 8.0F, 0.6D, 0.6D));
                this.tasks.addTask(1, new EntityAITofunianAvoidEntity<>(this, AbstractIllager.class, 8.0F, 0.8D, 0.8D));
                this.tasks.addTask(1, new EntityAITofunianAvoidEntity<>(this, EntityVex.class, 8.0F, 0.6D, 0.6D));
                this.tasks.addTask(1, new EntityAITofunianAvoidEntity<>(this, EntityTofuGandlem.class, 8.0F, 0.8D, 0.8D));

                this.tasks.addTask(2, new EntityAIPanic(this, 0.75F));
            }


            if (canFarm() && !this.isChild()) {
                this.tasks.addTask(8, new EntityAIHarvestTofuFarmland(this, 0.6D));
            }

            if ((canFarm() || canFish()) && !this.isChild()) {
                this.tasks.addTask(8, new EntityAIMakingFood(this, 0.6D));
            }
            this.isAleadyUpdate = true;
        }
    }

    protected void onGrowingAdult() {

        if (this.getTofuProfession() == TofuProfession.TOFUCOOK) {
            this.tasks.addTask(8, new EntityAIHarvestTofuFarmland(this, 0.6D));
        }

        if (canFarm() || canFish()) {
            this.tasks.addTask(8, new EntityAIMakingFood(this, 0.6D));
        }

        if (canGuard()) {
            if (!this.isChild()) {
                this.tasks.addTask(6, new EntityAIUseItemOnLeftHand<>(this, new ItemStack(ItemLoader.bugle), TofuSounds.TOFUBUGLE, (p_213736_1_) -> {
                    return WorldUtils.isMorning(this.world) && this.world.rand.nextInt(260) == 0;
                }));
            }
        }

        super.onGrowingAdult();
    }

    @Override
    public float getEyeHeight() {
        return this.isChild() ? 0.5F : 1.0f;
    }

    @Override
    public boolean attackEntityAsMob(Entity entityIn) {
        boolean flag = entityIn.attackEntityFrom(DamageSource.causeMobDamage(this), (float) ((int) this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getAttributeValue()));

        if (flag) {
            this.applyEnchantments(this, entityIn);
        }

        return flag;
    }

    @Override
    public EntityTofunian createChild(EntityAgeable ageable) {

        EntityTofunian entityvillager = new EntityTofunian(this.world);

        entityvillager.onInitialSpawn(this.world.getDifficultyForLocation(new BlockPos(entityvillager)), (IEntityLivingData) null);

        return entityvillager;

    }

    public boolean canFarm() {

        return this.getDataManager().get(TOFUPROFESSION) == TofuProfession.TOFUCOOK.ordinal();

    }

    public boolean canSmish() {

        return this.getDataManager().get(TOFUPROFESSION) == TofuProfession.TOFUSMITH.ordinal();

    }

    public boolean canFish() {

        return this.getDataManager().get(TOFUPROFESSION) == TofuProfession.FISHERMAN.ordinal();

    }

    public boolean canGuard() {

        return this.getDataManager().get(TOFUPROFESSION) == TofuProfession.GUARD.ordinal() && !isChild();

    }

    public void setTofuSmith() {

        this.getDataManager().set(TOFUPROFESSION, Integer.valueOf(TofuProfession.TOFUSMITH.ordinal()));
    }

    public void setTofuCook() {

        this.getDataManager().set(TOFUPROFESSION, Integer.valueOf(TofuProfession.TOFUCOOK.ordinal()));
    }

    public void setGuard() {

        this.getDataManager().set(TOFUPROFESSION, Integer.valueOf(TofuProfession.GUARD.ordinal()));

        this.setFightingItem();

    }

    public void setFisher() {

        this.getDataManager().set(TOFUPROFESSION, Integer.valueOf(TofuProfession.FISHERMAN.ordinal()));

        /*this.setFishingItem();*/

    }

    public void setFightingItem() {

        this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(ItemLoader.ishiTofuSword));


        if (this.rand.nextBoolean()) {
            this.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(ItemLoader.metalhelmet));
        } else {
            this.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(ItemLoader.solidhelmet));
        }
    }

    @SideOnly(Side.CLIENT)
    public void setRecipes(@Nullable MerchantRecipeList recipeList) {
    }

    public World getWorld() {
        return this.world;
    }

    public BlockPos getPos() {
        return new BlockPos(this);
    }


    @Nullable
    public MerchantRecipeList getRecipes(EntityPlayer player) {
        if (this.buyingList == null) {
            this.initTrades();
        }

        return net.minecraftforge.event.ForgeEventFactory.listTradeOffers(this, player, buyingList);
    }

    public void initTrades() {
        int j = this.tofunianCareerLevel;
        MerchantRecipeList trades = this.settingTrade(j);

        if (trades != null) {
            if (this.buyingList == null) {
                this.buyingList = trades;
            } else {
                this.buyingList = trades;
            }
        }
    }

    private MerchantRecipeList settingTrade(int level) {
        MerchantRecipeList list = new MerchantRecipeList();

        if (getTofuProfession() == TofuProfession.FISHERMAN) {


            addTradeRubyForItem(list, new ItemStack(ItemLoader.tofu_food), 22 + rand.nextInt(6));

            addTradeForSingleRuby(list, new ItemStack(ItemLoader.foodset, 8 + rand.nextInt(3)), 1);
            if (tofunianCareerLevel > 1) {
                addTradeForSingleRuby(list, new ItemStack(ItemLoader.soymilk_drink, 1, 1 + rand.nextInt(2)), 3 + rand.nextInt(2));
                addTradeForSingleRuby(list, new ItemStack(ItemLoader.soymilk_drink, 1, 5 + rand.nextInt(2)), 3 + rand.nextInt(2));
            }
        } else if (getTofuProfession() == TofuProfession.TOFUCOOK) {
            addTradeRubyForItem(list, new ItemStack(ItemLoader.tofu_food), 24 + rand.nextInt(6));
            addTradeRubyForItem(list, new ItemStack(ItemLoader.soybeans), 24 + rand.nextInt(6));

            if (tofunianCareerLevel > 1) {
                addTradeRubyForItem(list, new ItemStack(ItemLoader.rice), 16 + rand.nextInt(6));

                addTradeForSingleRuby(list, new ItemStack(ItemLoader.tofu_food, 6 + rand.nextInt(4), 6), 1);
                addTradeForSingleRuby(list, new ItemStack(ItemLoader.tofu_food, 6 + rand.nextInt(4), 5), 1);
            }
            if (tofunianCareerLevel > 2) {
                if (this.rand.nextInt(2) == 0) {
                    addTradeForSingleRuby(list, new ItemStack(ItemLoader.foodset, 5 + rand.nextInt(3), 15), 1);
                } else {
                    addTradeForSingleRuby(list, new ItemStack(ItemLoader.foodset, 6 + rand.nextInt(4), 14), 1);
                }
            }

            if (tofunianCareerLevel > 3) {
                addTradeForSingleRuby(list, new ItemStack(ItemLoader.tofuhoe, 1), 4);
                addTradeForSingleRuby(list, new ItemStack(ItemLoader.zundaMochi, 4 + rand.nextInt(4)), 1);

                addTradeForSingleRuby(list, new ItemStack(ItemLoader.material, 2 + rand.nextInt(2), 17), 4);
            }

            if (tofunianCareerLevel > 4) {
                if (this.rand.nextInt(2) == 0) {
                    addTradeForSingleRuby(list, new ItemStack(ItemLoader.material, 1 + rand.nextInt(2), 9), 5);
                }
            }
        } else if (getTofuProfession() == TofuProfession.TOFUSMITH) {
            addTradeRubyForItem(list, new ItemStack(ItemLoader.tofu_food, 1, 2), 22 + rand.nextInt(6));

            addTradeForSingleRuby(list, new ItemStack(ItemLoader.metalTofuSword, 1), 4 + rand.nextInt(3));
            addTradeForSingleRuby(list, new ItemStack(ItemLoader.metalTofuShovel, 1), 5 + rand.nextInt(3));
            if (tofunianCareerLevel > 1) {
                addTradeRubyForItem(list, new ItemStack(ItemLoader.tofu_material, 1), 5 + rand.nextInt(4));
                addTradeForSingleRuby(list, new ItemStack(ItemLoader.metalhelmet, 1), 4 + rand.nextInt(3));
                addEnchantTradeForSingleRuby(list, new ItemStack(ItemLoader.metalTofuPickaxe, 1), 6 + rand.nextInt(6));
            }

            if (tofunianCareerLevel > 2) {
                addEnchantTradeForSingleRuby(list, new ItemStack(ItemLoader.metalleggins, 1), 6 + rand.nextInt(4));
                addEnchantTradeForSingleRuby(list, new ItemStack(ItemLoader.metalchestplate, 1), 7 + rand.nextInt(4));
            }

            if (tofunianCareerLevel > 3) {
                addEnchantTradeForSingleRuby(list, new ItemStack(ItemLoader.zundaBow, 1), 2 + rand.nextInt(2));
                addEnchantTradeForSingleRuby(list, new ItemStack(ItemLoader.zundaArrow, 8 + rand.nextInt(4)), 1 + rand.nextInt(1));
            }

            addTradeForSingleRuby(list, new ItemStack(ItemLoader.tofustick, 2), 1 + rand.nextInt(2));
        }

        return list;
    }

    public void addTradeRubyForItem(MerchantRecipeList list, ItemStack buy, int cost) {

        ItemStack stack1 = buy.copy();

        stack1.setCount(cost);

        list.add(new MerchantRecipe(stack1, new ItemStack(ItemLoader.zundaruby, 1)));
    }

    public void addTradeForSingleRuby(MerchantRecipeList list, ItemStack sell, int cost) {

        ItemStack stack1 = sell.copy();

        list.add(new MerchantRecipe(new ItemStack(ItemLoader.zundaruby, cost), stack1));
    }

    public void addEnchantTradeForSingleRuby(MerchantRecipeList list, ItemStack sell, int cost) {

        ItemStack stack1 = sell.copy();

        ItemStack enchantStack = EnchantmentHelper.addRandomEnchantment(this.rand, new ItemStack(stack1.getItem(), 1, stack1.getMetadata()), 5 + this.rand.nextInt(15), false);

        list.add(new MerchantRecipe(new ItemStack(ItemLoader.zundaruby, cost), enchantStack));
    }

    @Override
    public ITextComponent getDisplayName() {

        String s1 = null;

        switch (this.getTofuProfession()) {
            case GUARD:
                s1 = "guard";
                break;
            case TOFUCOOK:
                s1 = "tofucrafter";
                break;
            case FISHERMAN:
                s1 = "fisherman";
                break;
            case TOFUSMITH:
                s1 = "tofusmith";
                break;
        }


        ITextComponent itextcomponent = new TextComponentTranslation("entity.Tofunian." + s1, new Object[0]);
        itextcomponent.getStyle().setHoverEvent(this.getHoverEvent());
        itextcomponent.getStyle().setInsertion(this.getCachedUniqueIdString());


        return itextcomponent;
    }

    public boolean getIsWillingToMate(boolean updateFirst) {
        if (!this.isWillingToMate && updateFirst && this.hasEnoughFoodToBreed()) {
            boolean flag = false;

            for (int i = 0; i < this.getVillagerInventory().getSizeInventory(); ++i) {
                ItemStack itemstack = this.getVillagerInventory().getStackInSlot(i);

                if (!itemstack.isEmpty()) {
                    if (itemstack.getItem() == Items.BREAD && itemstack.getCount() >= 3) {
                        flag = true;
                        this.getVillagerInventory().decrStackSize(i, 3);
                    } else if ((itemstack.getItem() == ItemLoader.soybeans || itemstack.getItem() == ItemLoader.tofu_food || itemstack.getItem() == ItemLoader.foodset || itemstack.getItem() == Items.POTATO || itemstack.getItem() == Items.CARROT) && itemstack.getCount() >= 12) {
                        flag = true;
                        this.getVillagerInventory().decrStackSize(i, 12);
                    }
                }

                if (flag) {
                    this.world.setEntityState(this, (byte) 18);
                    this.isWillingToMate = true;
                    break;
                }
            }
        }

        return this.isWillingToMate;
    }

    public boolean hasEnoughFoodToBreed() {
        return this.hasEnoughItems(1);
    }

    /**
     * Used by {@link net.minecraft.entity.ai.EntityAIVillagerInteract EntityAIVillagerInteract} to check if the
     * villager can give some items from an inventory to another villager.
     */
    public boolean canAbondonItems() {
        return this.hasEnoughItems(2);
    }

    public boolean wantsMoreFood() {
        boolean flag = this.getTofuProfession() == TofuProfession.TOFUCOOK;

        if (flag) {
            return !this.hasEnoughItems(5);
        } else {
            return !this.hasEnoughItems(1);
        }
    }

    public void setIsWillingToMate(boolean isWillingToMate) {
        this.isWillingToMate = isWillingToMate;
    }

    private boolean hasEnoughItems(int multiplier) {
        boolean flag = this.getTofuProfession() == TofuProfession.TOFUCOOK;

        for (int i = 0; i < this.getVillagerInventory().getSizeInventory(); ++i) {
            ItemStack itemstack = this.getVillagerInventory().getStackInSlot(i);

            if (!itemstack.isEmpty()) {
                if (itemstack.getItem() == Items.BREAD && itemstack.getCount() >= 3 * multiplier || itemstack.getItem() == Items.POTATO && itemstack.getCount() >= 12 * multiplier || itemstack.getItem() == Items.CARROT && itemstack.getCount() >= 12 * multiplier || itemstack.getItem() == Items.BEETROOT && itemstack.getCount() >= 12 * multiplier || itemstack.getItem() == ItemLoader.foodset && itemstack.getCount() >= 12 * multiplier || itemstack.getItem() == ItemLoader.soybeans && itemstack.getCount() >= 12 * multiplier) {
                    return true;
                }

                if (itemstack.getItem() == ItemLoader.tofu_food && itemstack.getCount() >= 14 * multiplier) {
                    return true;
                }

                if (flag && itemstack.getItem() == Items.WHEAT && itemstack.getCount() >= 9 * multiplier || flag && itemstack.getItem() == ItemLoader.rice && itemstack.getCount() >= 9 * multiplier) {
                    return true;
                }
            }
        }

        return false;
    }

    public boolean hasEnoughCraftedItem(int multiplier, int needCost) {
        for (int i = 0; i < this.getVillagerInventory().getSizeInventory(); ++i) {
            ItemStack itemstack = this.getVillagerInventory().getStackInSlot(i);

            if (!itemstack.isEmpty()) {
                if (itemstack.getItem() == ItemLoader.tofu_food && itemstack.getCount() >= 12 * multiplier + needCost) {
                    return true;
                }
            }
        }

        return false;
    }

    protected void updateEquipmentIfNeeded(EntityItem itemEntity) {
        ItemStack itemstack = itemEntity.getItem();

        if (this.canTofunianPickupItem(itemstack)) {
            ItemStack itemstack1 = this.getVillagerInventory().addItem(itemstack);

            if (itemstack1.isEmpty()) {
                itemEntity.setDead();
            } else {
                itemstack.setCount(itemstack1.getCount());
            }
        }
    }

    public InventoryBasic getVillagerInventory() {
        return villagerInventory;
    }

    private boolean canTofunianPickupItem(ItemStack itemStack) {
        Item item = itemStack.getItem();
        return item == ItemLoader.soybeans || item == ItemLoader.rice || item == ItemLoader.tofu_food && itemStack.getMetadata() == 3;
    }

    public boolean isFarmItemInInventory() {
        for (int i = 0; i < this.getVillagerInventory().getSizeInventory(); ++i) {
            ItemStack itemstack = this.getVillagerInventory().getStackInSlot(i);

            if (!itemstack.isEmpty() && (itemstack.getItem() == Items.WHEAT_SEEDS || itemstack.getItem() == Items.POTATO || itemstack.getItem() == Items.CARROT || itemstack.getItem() == Items.BEETROOT_SEEDS || itemstack.getItem() == ItemLoader.soybeans)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public boolean isOnSameTeam(Entity entityIn) {
        if (super.isOnSameTeam(entityIn)) {
            return true;
        } else if (entityIn instanceof EntityLivingBase && ((EntityLivingBase) entityIn).getCreatureAttribute() == TofuEntityRegister.tofunian) {
            return this.getTeam() == null && entityIn.getTeam() == null;
        } else {
            return false;
        }
    }

    public void verifySellingItem(ItemStack stack) {
        if (!this.world.isRemote && this.livingSoundTime > -this.getTalkInterval() + 20) {
            this.livingSoundTime = -this.getTalkInterval();
            if (!stack.isEmpty()) {
                this.playSound(TofuSounds.TOFUNIAN_YES, this.getSoundVolume(), this.getSoundPitch());
            }
        }
    }

    public void onDeath(DamageSource cause) {
        if (this.village != null) {
            Entity entity = cause.getTrueSource();

            if (entity != null) {
                if (entity instanceof EntityPlayer) {
                    this.village.modifyPlayerReputation(entity.getUniqueID(), -2);
                } else if (entity instanceof IMob) {
                    this.village.endMatingSeason();
                }
            } else {
                EntityPlayer entityplayer = this.world.getClosestPlayerToEntity(this, 16.0D);

                if (entityplayer != null) {
                    this.village.endMatingSeason();
                }
            }
        }

        super.onDeath(cause);
    }

    @Override
    public EnumCreatureAttribute getCreatureAttribute() {
        return TofuEntityRegister.tofunian;
    }

    public enum TofuProfession {

        GUARD,
        FISHERMAN,
        TOFUCOOK,
        TOFUSMITH;


        private static final Map<Integer, TofuProfession> lookup = new HashMap<>();

        static {
            for (TofuProfession e : EnumSet.allOf(TofuProfession.class)) {
                lookup.put(e.ordinal(), e);
            }
        }

        public static TofuProfession get(int intValue) {
            return lookup.get(intValue);
        }

    }
}