package pneumaticCraft.client.render.pneumaticArmor.hacking;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.monster.EntityBlaze;
import net.minecraft.entity.monster.EntityCaveSpider;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntityEnderman;
import net.minecraft.entity.monster.EntityGhast;
import net.minecraft.entity.monster.EntityWitch;
import net.minecraft.entity.passive.EntityCow;
import net.minecraft.entity.passive.EntityTameable;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.IExtendedEntityProperties;
import pneumaticCraft.PneumaticCraft;
import pneumaticCraft.api.PneumaticRegistry;
import pneumaticCraft.api.client.pneumaticHelmet.IHackableBlock;
import pneumaticCraft.api.client.pneumaticHelmet.IHackableEntity;
import pneumaticCraft.client.render.pneumaticArmor.BlockTrackUpgradeHandler;
import pneumaticCraft.client.render.pneumaticArmor.EntityTrackUpgradeHandler;
import pneumaticCraft.client.render.pneumaticArmor.HUDHandler;
import pneumaticCraft.client.render.pneumaticArmor.RenderBlockTarget;
import pneumaticCraft.client.render.pneumaticArmor.RenderTarget;
import pneumaticCraft.client.render.pneumaticArmor.hacking.block.HackableButton;
import pneumaticCraft.client.render.pneumaticArmor.hacking.block.HackableDispenser;
import pneumaticCraft.client.render.pneumaticArmor.hacking.block.HackableDoor;
import pneumaticCraft.client.render.pneumaticArmor.hacking.block.HackableJukebox;
import pneumaticCraft.client.render.pneumaticArmor.hacking.block.HackableLever;
import pneumaticCraft.client.render.pneumaticArmor.hacking.block.HackableMobSpawner;
import pneumaticCraft.client.render.pneumaticArmor.hacking.block.HackableNoteblock;
import pneumaticCraft.client.render.pneumaticArmor.hacking.block.HackableSecurityStation;
import pneumaticCraft.client.render.pneumaticArmor.hacking.block.HackableTNT;
import pneumaticCraft.client.render.pneumaticArmor.hacking.block.HackableTripwire;
import pneumaticCraft.client.render.pneumaticArmor.hacking.entity.HackableBlaze;
import pneumaticCraft.client.render.pneumaticArmor.hacking.entity.HackableCaveSpider;
import pneumaticCraft.client.render.pneumaticArmor.hacking.entity.HackableCow;
import pneumaticCraft.client.render.pneumaticArmor.hacking.entity.HackableCreeper;
import pneumaticCraft.client.render.pneumaticArmor.hacking.entity.HackableEnderman;
import pneumaticCraft.client.render.pneumaticArmor.hacking.entity.HackableGhast;
import pneumaticCraft.client.render.pneumaticArmor.hacking.entity.HackableLivingDisarm;
import pneumaticCraft.client.render.pneumaticArmor.hacking.entity.HackableTameable;
import pneumaticCraft.client.render.pneumaticArmor.hacking.entity.HackableWitch;
import pneumaticCraft.common.PneumaticCraftAPIHandler;
import pneumaticCraft.common.block.Blockss;
import pneumaticCraft.common.util.WorldAndCoord;
import pneumaticCraft.lib.Log;
import cpw.mods.fml.relauncher.Side;
public class HackableHandler{
private final Map<Entity, IHackableEntity> trackedHackableEntities = new HashMap<Entity, IHackableEntity>();
private final Map<WorldAndCoord, IHackableBlock> trackedHackableBlocks = new HashMap<WorldAndCoord, IHackableBlock>();
private static HackableHandler clientInstance, serverInstance;
private static HackableHandler getInstance(){
if(PneumaticCraft.proxy.getSide() == Side.CLIENT) {
if(clientInstance == null) clientInstance = new HackableHandler();
return clientInstance;
} else {
if(serverInstance == null) serverInstance = new HackableHandler();
return serverInstance;
}
}
public static void addDefaultEntries(){
PneumaticRegistry.instance.addHackable(Blocks.tnt, HackableTNT.class);
PneumaticRegistry.instance.addHackable(Blocks.mob_spawner, HackableMobSpawner.class);
PneumaticRegistry.instance.addHackable(Blocks.lever, HackableLever.class);
PneumaticRegistry.instance.addHackable(Blocks.stone_button, HackableButton.class);
PneumaticRegistry.instance.addHackable(Blocks.wooden_button, HackableButton.class);
PneumaticRegistry.instance.addHackable(Blocks.wooden_door, HackableDoor.class);
PneumaticRegistry.instance.addHackable(Blocks.tripwire_hook, HackableTripwire.class);
PneumaticRegistry.instance.addHackable(Blocks.dispenser, HackableDispenser.class);
PneumaticRegistry.instance.addHackable(Blocks.dropper, HackableDispenser.class);
PneumaticRegistry.instance.addHackable(Blockss.securityStation, HackableSecurityStation.class);
PneumaticRegistry.instance.addHackable(Blocks.monster_egg, HackableTripwire.class);
PneumaticRegistry.instance.addHackable(Blocks.noteblock, HackableNoteblock.class);
PneumaticRegistry.instance.addHackable(Blocks.jukebox, HackableJukebox.class);
PneumaticRegistry.instance.addHackable(EntityCreeper.class, HackableCreeper.class);
PneumaticRegistry.instance.addHackable(EntityTameable.class, HackableTameable.class);
PneumaticRegistry.instance.addHackable(EntityCow.class, HackableCow.class);
PneumaticRegistry.instance.addHackable(EntityCaveSpider.class, HackableCaveSpider.class);
PneumaticRegistry.instance.addHackable(EntityBlaze.class, HackableBlaze.class);
PneumaticRegistry.instance.addHackable(EntityGhast.class, HackableGhast.class);
PneumaticRegistry.instance.addHackable(EntityWitch.class, HackableWitch.class);
PneumaticRegistry.instance.addHackable(EntityLiving.class, HackableLivingDisarm.class);
PneumaticRegistry.instance.addHackable(EntityEnderman.class, HackableEnderman.class);
}
public static IHackableEntity getHackableForEntity(Entity entity, EntityPlayer player){
//clean up the map
Iterator<Map.Entry<Entity, IHackableEntity>> iterator = getInstance().trackedHackableEntities.entrySet().iterator();
while(iterator.hasNext()) {
Map.Entry<Entity, IHackableEntity> entry = iterator.next();
if(entry.getKey().isDead || !entry.getValue().canHack(entry.getKey(), player) && !isInDisplayCooldown(entry.getValue(), entry.getKey())) iterator.remove();
}
if(entity instanceof IHackableEntity && ((IHackableEntity)entity).canHack(entity, player)) return (IHackableEntity)entity;
IHackableEntity hackable = getInstance().trackedHackableEntities.get(entity);
if(hackable == null) {
for(Map.Entry<Class<? extends Entity>, Class<? extends IHackableEntity>> entry : PneumaticCraftAPIHandler.getInstance().hackableEntities.entrySet()) {
if(entry.getKey().isAssignableFrom(entity.getClass())) {
try {
hackable = entry.getValue().newInstance();
if(hackable.canHack(entity, player)) {
getInstance().trackedHackableEntities.put(entity, hackable);
break;
} else {
hackable = null;
}
} catch(Exception e) {
//shouldn't happen, checked earlier.
e.printStackTrace();
}
}
}
}
return hackable;
}
public static IHackableBlock getHackableForCoord(WorldAndCoord coord, EntityPlayer player){
return getHackableForCoord(coord.world, coord.x, coord.y, coord.z, player);
}
public static IHackableBlock getHackableForCoord(IBlockAccess world, int x, int y, int z, EntityPlayer player){
//clean up the map
Iterator<Map.Entry<WorldAndCoord, IHackableBlock>> iterator = getInstance().trackedHackableBlocks.entrySet().iterator();
while(iterator.hasNext()) {
Map.Entry<WorldAndCoord, IHackableBlock> entry = iterator.next();
Class<? extends IHackableBlock> hackableBlockClazz = PneumaticCraftAPIHandler.getInstance().hackableBlocks.get(entry.getKey().getBlock());
if(hackableBlockClazz != entry.getValue().getClass() || !entry.getValue().canHack(entry.getKey().world, entry.getKey().x, entry.getKey().y, entry.getKey().z, player) && !isInDisplayCooldown(entry.getValue(), entry.getKey().world, entry.getKey().x, entry.getKey().y, entry.getKey().z, player)) iterator.remove();
}
Block block = world.getBlock(x, y, z);
if(block instanceof IHackableBlock && ((IHackableBlock)block).canHack(world, x, y, z, player)) return (IHackableBlock)block;
IHackableBlock hackable = getInstance().trackedHackableBlocks.get(new WorldAndCoord(world, x, y, z));
if(hackable == null) {
if(!PneumaticCraftAPIHandler.getInstance().hackableBlocks.containsKey(block)) return null;
try {
hackable = PneumaticCraftAPIHandler.getInstance().hackableBlocks.get(block).newInstance();
if(hackable.canHack(world, x, y, z, player)) {
getInstance().trackedHackableBlocks.put(new WorldAndCoord(world, x, y, z), hackable);
} else {
hackable = null;
}
} catch(Exception e) {
//shouldn't happen, checked earlier.
e.printStackTrace();
}
}
return hackable;
}
private static boolean isInDisplayCooldown(IHackableBlock hackableBlock, IBlockAccess world, int x, int y, int z, EntityPlayer player){
if(player.worldObj.isRemote) {
RenderBlockTarget target = ((BlockTrackUpgradeHandler)HUDHandler.instance().getSpecificRenderer(BlockTrackUpgradeHandler.class)).getTargetForCoord(x, y, z);
int requiredHackTime = hackableBlock.getHackTime(world, x, y, z, player);
return target != null && target.getHackTime() >= requiredHackTime && target.getHackTime() <= requiredHackTime + 20;
} else {
return false;
}
}
private static boolean isInDisplayCooldown(IHackableEntity hackableBlock, Entity entity){
if(entity.worldObj.isRemote) {
RenderTarget target = ((EntityTrackUpgradeHandler)HUDHandler.instance().getSpecificRenderer(EntityTrackUpgradeHandler.class)).getTargetForEntity(entity);
int requiredHackTime = hackableBlock.getHackTime(entity, PneumaticCraft.proxy.getPlayer());
return target != null && target.getHackTime() >= requiredHackTime && target.getHackTime() <= requiredHackTime + 20;
} else {
return false;
}
}
public static void onEntityConstruction(Entity entity){
entity.registerExtendedProperties("PneumaticCraftHacking", new HackingEntityProperties());
}
public static class HackingEntityProperties implements IExtendedEntityProperties{
private List<IHackableEntity> hackables;
@Override
public void saveNBTData(NBTTagCompound compound){
if(hackables != null && !hackables.isEmpty()) {
NBTTagList tagList = new NBTTagList();
for(IHackableEntity hackableEntity : hackables) {
if(hackableEntity.getId() != null) {
NBTTagCompound tag = new NBTTagCompound();
tag.setString("id", hackableEntity.getId());
tagList.appendTag(tag);
}
}
compound.setTag("hackables", tagList);
}
}
@Override
public void loadNBTData(NBTTagCompound compound){
hackables = null;
NBTTagList tagList = compound.getTagList("hackables", 10);
for(int i = 0; i < tagList.tagCount(); i++) {
String hackableId = tagList.getCompoundTagAt(i).getString("id");
Class<? extends IHackableEntity> hackableClass = PneumaticCraftAPIHandler.getInstance().stringToEntityHackables.get(hackableId);
if(hackableClass != null) {
try {
if(hackables == null) hackables = new ArrayList<IHackableEntity>();
hackables.add(hackableClass.newInstance());
} catch(Exception e) {
e.printStackTrace();
}
} else {
Log.warning("hackable \"" + hackableId + "\" not found when constructing from nbt. Was it deleted?");
}
}
}
@Override
public void init(Entity entity, World world){}
public void update(Entity entity){
if(hackables != null) {
Iterator<IHackableEntity> iterator = hackables.iterator();
while(iterator.hasNext()) {
IHackableEntity hackable = iterator.next();
if(!hackable.afterHackTick(entity)) {
iterator.remove();
}
}
}
}
public void addHackable(IHackableEntity hackable){
if(hackables == null) hackables = new ArrayList<IHackableEntity>();
hackables.add(hackable);
}
public List<IHackableEntity> getCurrentHacks(){
return hackables;
}
}
}