package crazypants.enderio.item.darksteel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.command.IEntitySelector;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemShears;
import net.minecraft.item.ItemStack;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.common.IShearable;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerEvent;
import cofh.api.energy.IEnergyContainerItem;
import com.enderio.core.api.client.gui.IAdvancedTooltipProvider;
import com.enderio.core.common.util.BlockCoord;
import com.enderio.core.common.util.ItemUtil;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import crazypants.enderio.EnderIO;
import crazypants.enderio.EnderIOTab;
import crazypants.enderio.config.Config;
import crazypants.enderio.item.darksteel.upgrade.EnergyUpgrade;
import crazypants.enderio.machine.farm.farmers.HarvestResult;
public class ItemDarkSteelShears extends ItemShears implements IEnergyContainerItem, IAdvancedTooltipProvider, IDarkSteelItem {
public static boolean isEquipped(EntityPlayer player) {
if(player == null) {
return false;
}
ItemStack equipped = player.getCurrentEquippedItem();
if(equipped == null) {
return false;
}
return equipped.getItem() == DarkSteelItems.itemDarkSteelShears;
}
public static boolean isEquippedAndPowered(EntityPlayer player, int requiredPower) {
return getStoredPower(player) > requiredPower;
}
public static int getStoredPower(EntityPlayer player) {
if(!isEquipped(player)) {
return 0;
}
return EnergyUpgrade.getEnergyStored(player.getCurrentEquippedItem());
}
public static ItemDarkSteelShears create() {
ItemDarkSteelShears res = new ItemDarkSteelShears();
MinecraftForge.EVENT_BUS.register(res);
res.init();
return res;
}
private final MultiHarvestComparator harvestComparator = new MultiHarvestComparator();
private final EntityComparator entityComparator = new EntityComparator();
protected ItemDarkSteelShears() {
super();
this.setMaxDamage(this.getMaxDamage() * Config.darkSteelShearsDurabilityFactor);
setCreativeTab(EnderIOTab.tabEnderIO);
String str = "darkSteel_shears";
setUnlocalizedName(str);
setTextureName("enderIO:" + str);
}
@Override
public int getIngotsRequiredForFullRepair() {
return 2;
}
@Override
@SideOnly(Side.CLIENT)
public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List par3List) {
ItemStack is = new ItemStack(this);
par3List.add(is);
is = new ItemStack(this);
EnergyUpgrade.EMPOWERED_FOUR.writeToItem(is);
EnergyUpgrade.setPowerFull(is);
par3List.add(is);
}
@Override
public boolean isDamaged(ItemStack stack) {
return false;
}
@Override
public boolean onBlockStartBreak(ItemStack itemstack, int x, int y, int z, EntityPlayer player) {
if (player.worldObj.isRemote) {
return false;
}
int powerStored = getStoredPower(player);
if (powerStored < Config.darkSteelShearsPowerUsePerDamagePoint) {
return super.onBlockStartBreak(itemstack, x, y, z, player);
}
Block block = player.worldObj.getBlock(x, y, z);
if (block instanceof IShearable && ((IShearable)block).isShearable(itemstack, player.worldObj, x, y, z)) {
BlockCoord bc = new BlockCoord(x, y, z);
HarvestResult res = new HarvestResult(null, bc);
for (int dx = -Config.darkSteelShearsBlockAreaBoostWhenPowered; dx <= Config.darkSteelShearsBlockAreaBoostWhenPowered; dx++) {
for (int dy = -Config.darkSteelShearsBlockAreaBoostWhenPowered; dy <= Config.darkSteelShearsBlockAreaBoostWhenPowered; dy++) {
for (int dz = -Config.darkSteelShearsBlockAreaBoostWhenPowered; dz <= Config.darkSteelShearsBlockAreaBoostWhenPowered; dz++) {
Block block2 = player.worldObj.getBlock(x+dx, y+dy, z+dz);
if (block2 instanceof IShearable && ((IShearable)block2).isShearable(itemstack, player.worldObj, x+dx, y+dy, z+dz)) {
res.getHarvestedBlocks().add(new BlockCoord(x+dx, y+dy, z+dz));
}
}
}
}
List<BlockCoord> sortedTargets = new ArrayList<BlockCoord>(res.getHarvestedBlocks());
harvestComparator.refPoint = bc;
Collections.sort(sortedTargets, harvestComparator);
int maxBlocks = Math.min(sortedTargets.size(), powerStored / Config.darkSteelShearsPowerUsePerDamagePoint);
for (int i=0 ; i < maxBlocks ; i++) {
BlockCoord bc2 = sortedTargets.get(i);
super.onBlockStartBreak(itemstack, bc2.x, bc2.y, bc2.z, player);
if (bc2 != bc) {
player.worldObj.setBlockToAir(bc2.x, bc2.y, bc2.z);
}
}
}
return false;
}
IEntitySelector selectShearable = new IEntitySelector() {
@Override
public boolean isEntityApplicable(Entity entity) {
return entity instanceof IShearable && ((IShearable)entity).isShearable(null, entity.worldObj, (int)entity.posX, (int)entity.posY, (int)entity.posZ);
}
};
@Override
public boolean itemInteractionForEntity(ItemStack itemstack, EntityPlayer player, EntityLivingBase entity) {
if (entity.worldObj.isRemote) {
return false;
}
int powerStored = getStoredPower(player);
if (powerStored < Config.darkSteelShearsPowerUsePerDamagePoint) {
return super.itemInteractionForEntity(itemstack, player, entity);
}
if (entity instanceof IShearable) {
AxisAlignedBB bb = AxisAlignedBB.getBoundingBox(
entity.posX - Config.darkSteelShearsEntityAreaBoostWhenPowered, entity.posY - Config.darkSteelShearsEntityAreaBoostWhenPowered, entity.posZ - Config.darkSteelShearsEntityAreaBoostWhenPowered,
entity.posX + Config.darkSteelShearsEntityAreaBoostWhenPowered, entity.posY + Config.darkSteelShearsEntityAreaBoostWhenPowered, entity.posZ + Config.darkSteelShearsEntityAreaBoostWhenPowered);
List<Entity> sortedTargets = new ArrayList<Entity>(entity.worldObj.selectEntitiesWithinAABB(IShearable.class, bb, selectShearable));
entityComparator.refPoint = entity;
Collections.sort(sortedTargets, entityComparator);
boolean result = false;
int maxSheep = Math.min(sortedTargets.size(), powerStored / Config.darkSteelShearsPowerUsePerDamagePoint);
for (int i=0 ; i < maxSheep ; i++) {
Entity entity2 = sortedTargets.get(i);
if (entity2 instanceof EntityLivingBase && super.itemInteractionForEntity(itemstack, player, (EntityLivingBase) entity2)) {
result = true;
}
}
return result;
}
return false;
}
@SubscribeEvent
public void onBreakSpeedEvent(PlayerEvent.BreakSpeed evt) {
if(evt.originalSpeed > 2.0 && isEquippedAndPowered(evt.entityPlayer, Config.darkSteelShearsPowerUsePerDamagePoint)) {
evt.newSpeed = evt.originalSpeed * Config.darkSteelShearsEffeciencyBoostWhenPowered;
}
}
@Override
public void setDamage(ItemStack stack, int newDamage) {
int oldDamage = getDamage(stack);
if (newDamage <= oldDamage) {
super.setDamage(stack, newDamage);
}
int damage = newDamage - oldDamage;
EnergyUpgrade eu = EnergyUpgrade.loadFromItem(stack);
if(eu != null && eu.isAbsorbDamageWithPower(stack) && eu.getEnergy() > 0) {
eu.extractEnergy(damage * Config.darkSteelShearsPowerUsePerDamagePoint, false);
} else {
super.setDamage(stack, newDamage);
}
if(eu != null) {
eu.writeToItem(stack);
}
}
protected void init() {
GameRegistry.registerItem(this, getUnlocalizedName());
}
@Override
public int receiveEnergy(ItemStack container, int maxReceive, boolean simulate) {
return EnergyUpgrade.receiveEnergy(container, maxReceive, simulate);
}
@Override
public int extractEnergy(ItemStack container, int maxExtract, boolean simulate) {
return EnergyUpgrade.extractEnergy(container, maxExtract, simulate);
}
@Override
public int getEnergyStored(ItemStack container) {
return EnergyUpgrade.getEnergyStored(container);
}
@Override
public int getMaxEnergyStored(ItemStack container) {
return EnergyUpgrade.getMaxEnergyStored(container);
}
@Override
public boolean getIsRepairable(ItemStack i1, ItemStack i2) {
//return i2 != null && i2.getItem() == EnderIO.itemAlloy && i2.getItemDamage() == Alloy.DARK_STEEL.ordinal();
return false;
}
@Override
public int getItemEnchantability() {
return ItemDarkSteelSword.MATERIAL.getEnchantability();
}
@Override
public void addCommonEntries(ItemStack itemstack, EntityPlayer entityplayer, List list, boolean flag) {
DarkSteelRecipeManager.instance.addCommonTooltipEntries(itemstack, entityplayer, list, flag);
}
@Override
public void addBasicEntries(ItemStack itemstack, EntityPlayer entityplayer, List list, boolean flag) {
DarkSteelRecipeManager.instance.addBasicTooltipEntries(itemstack, entityplayer, list, flag);
}
@Override
public void addDetailedEntries(ItemStack itemstack, EntityPlayer entityplayer, List list, boolean flag) {
if(!Config.addDurabilityTootip) {
list.add(ItemUtil.getDurabilityString(itemstack));
}
String str = EnergyUpgrade.getStoredEnergyString(itemstack);
if(str != null) {
list.add(str);
}
if(EnergyUpgrade.itemHasAnyPowerUpgrade(itemstack)) {
list.add(EnderIO.lang.localize("item.darkSteel_shears.tooltip.multiHarvest"));
list.add(EnumChatFormatting.WHITE + "+" + Config.darkSteelShearsEffeciencyBoostWhenPowered + " "
+ EnderIO.lang.localize("item.darkSteel_pickaxe.tooltip.effPowered"));
}
DarkSteelRecipeManager.instance.addAdvancedTooltipEntries(itemstack, entityplayer, list, flag);
}
public ItemStack createItemStack() {
return new ItemStack(this);
}
private static class MultiHarvestComparator implements Comparator<BlockCoord> {
BlockCoord refPoint;
@Override
public int compare(BlockCoord arg0, BlockCoord arg1) {
int d1 = refPoint.getDistSq(arg0);
int d2 = refPoint.getDistSq(arg1);
return compare(d1, d2);
}
// NB: Copy of Integer.compare, which is only in Java 1.7+
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
}
private static class EntityComparator implements Comparator<Entity> {
Entity refPoint;
@Override
public int compare(Entity paramT1, Entity paramT2) {
double distanceSqToEntity1 = refPoint.getDistanceSqToEntity(paramT1);
double distanceSqToEntity2 = refPoint.getDistanceSqToEntity(paramT2);
if (distanceSqToEntity1 < distanceSqToEntity2)
return -1;
if (distanceSqToEntity1 > distanceSqToEntity2)
return 1;
// Double.compare() does something with bits now, but for distances it's clear:
// if it's neither farther nor nearer is same.
return 0;
}
}
}