package pneumaticCraft.common.progwidgets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.command.IEntitySelector;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.world.ChunkCache;
import net.minecraft.world.ChunkPosition;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import pneumaticCraft.client.gui.GuiProgrammer;
import pneumaticCraft.client.gui.programmer.GuiProgWidgetAreaShow;
import pneumaticCraft.common.ai.DroneAIManager;
import pneumaticCraft.common.ai.StringFilterEntitySelector;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public abstract class ProgWidgetAreaItemBase extends ProgWidget implements IAreaProvider, IEntityProvider,
IItemFiltering, IVariableWidget{
private List<ChunkPosition> areaListCache;
private Set<ChunkPosition> areaSetCache;
private Map<String, ChunkPosition> areaVariableStates;
protected DroneAIManager aiManager;
private boolean canCache = true;
@Override
public boolean hasStepInput(){
return true;
}
@Override
public Class<? extends IProgWidget> returnType(){
return null;
}
@Override
public Class<? extends IProgWidget>[] getParameters(){
return new Class[]{ProgWidgetArea.class, ProgWidgetItemFilter.class};
}
@Override
public void addErrors(List<String> curInfo, List<IProgWidget> widgets){
super.addErrors(curInfo, widgets);
if(getConnectedParameters()[0] == null) {
curInfo.add("gui.progWidget.area.error.noArea");
}
}
public static IBlockAccess getCache(Collection<ChunkPosition> area, World world){
if(area.size() == 0) return world;
int minX, minY, minZ, maxX, maxY, maxZ;
Iterator<ChunkPosition> iterator = area.iterator();
ChunkPosition p = iterator.next();
minX = maxX = p.chunkPosX;
minY = maxY = p.chunkPosY;
minZ = maxZ = p.chunkPosZ;
while(iterator.hasNext()) {
p = iterator.next();
minX = Math.min(minX, p.chunkPosX);
minY = Math.min(minY, p.chunkPosY);
minZ = Math.min(minZ, p.chunkPosZ);
maxX = Math.max(maxX, p.chunkPosX);
maxY = Math.max(maxY, p.chunkPosY);
maxZ = Math.max(maxZ, p.chunkPosZ);
}
return new ChunkCache(world, minX, minY, minZ, maxX, maxY, maxZ, 0);
}
public List<ChunkPosition> getCachedAreaList(){
if(areaListCache != null) {
if(!canCache || updateVariables()) {
areaSetCache = new HashSet<ChunkPosition>(areaListCache.size());
getArea(areaSetCache);
areaListCache = new ArrayList<ChunkPosition>(areaSetCache.size());
areaListCache.addAll(areaSetCache);
}
} else {
areaSetCache = new HashSet<ChunkPosition>();
getArea(areaSetCache);
areaListCache = new ArrayList<ChunkPosition>(areaSetCache.size());
areaListCache.addAll(areaSetCache);
initializeVariableCache();
}
return areaListCache;
}
public Set<ChunkPosition> getCachedAreaSet(){
getCachedAreaList();
return areaSetCache;
}
private void initializeVariableCache(){
areaVariableStates = new HashMap<String, ChunkPosition>();
ProgWidgetArea whitelistWidget = (ProgWidgetArea)getConnectedParameters()[0];
ProgWidgetArea blacklistWidget = (ProgWidgetArea)getConnectedParameters()[getParameters().length];
if(whitelistWidget == null) return;
ProgWidgetArea widget = whitelistWidget;
while(widget != null) {
if(widget.type == ProgWidgetArea.EnumAreaType.RANDOM) canCache = false;
if(!widget.getCoord1Variable().equals("")) areaVariableStates.put(widget.getCoord1Variable(), aiManager.getCoordinate(widget.getCoord1Variable()));
if(!widget.getCoord2Variable().equals("")) areaVariableStates.put(widget.getCoord2Variable(), aiManager.getCoordinate(widget.getCoord2Variable()));
widget = (ProgWidgetArea)widget.getConnectedParameters()[0];
}
widget = blacklistWidget;
while(widget != null) {
if(widget.type == ProgWidgetArea.EnumAreaType.RANDOM) canCache = false;
if(!widget.getCoord1Variable().equals("")) areaVariableStates.put(widget.getCoord1Variable(), aiManager.getCoordinate(widget.getCoord1Variable()));
if(!widget.getCoord2Variable().equals("")) areaVariableStates.put(widget.getCoord2Variable(), aiManager.getCoordinate(widget.getCoord2Variable()));
widget = (ProgWidgetArea)widget.getConnectedParameters()[0];
}
}
private boolean updateVariables(){
boolean varChanged = false;
for(Map.Entry<String, ChunkPosition> entry : areaVariableStates.entrySet()) {
ChunkPosition newValue = aiManager.getCoordinate(entry.getKey());
if(!newValue.equals(entry.getValue())) {
varChanged = true;
entry.setValue(newValue);
}
}
return varChanged;
}
@Override
public void getArea(Set<ChunkPosition> area){
getArea(area, (ProgWidgetArea)getConnectedParameters()[0], (ProgWidgetArea)getConnectedParameters()[getParameters().length]);
}
public static void getArea(Set<ChunkPosition> area, ProgWidgetArea whitelistWidget, ProgWidgetArea blacklistWidget){
if(whitelistWidget == null) return;
ProgWidgetArea widget = whitelistWidget;
while(widget != null) {
widget.getArea(area);
widget = (ProgWidgetArea)widget.getConnectedParameters()[0];
}
widget = blacklistWidget;
Set<ChunkPosition> blacklistedArea = new HashSet<ChunkPosition>();
while(widget != null) {
widget.getArea(blacklistedArea);
widget = (ProgWidgetArea)widget.getConnectedParameters()[0];
}
area.removeAll(blacklistedArea);
}
@Override
public boolean isItemValidForFilters(ItemStack item){
return isItemValidForFilters(item, -1);
}
public boolean isItemValidForFilters(ItemStack item, int blockMetadata){
return ProgWidgetItemFilter.isItemValidForFilters(item, ProgWidget.getConnectedWidgetList(this, 1), ProgWidget.getConnectedWidgetList(this, getParameters().length + 1), blockMetadata);
}
public boolean isItemFilterEmpty(){
return getConnectedParameters()[1] == null && getConnectedParameters()[3] == null;
}
public List<Entity> getEntitiesInArea(World world, IEntitySelector filter){
return getEntitiesInArea((ProgWidgetArea)getConnectedParameters()[0], (ProgWidgetArea)getConnectedParameters()[getParameters().length], world, filter, null);
}
public static List<Entity> getValidEntities(World world, IProgWidget widget){
StringFilterEntitySelector whitelistFilter = getEntityFilter((ProgWidgetString)widget.getConnectedParameters()[1], true);
StringFilterEntitySelector blacklistFilter = getEntityFilter((ProgWidgetString)widget.getConnectedParameters()[widget.getParameters().length + 1], false);
return getEntitiesInArea((ProgWidgetArea)widget.getConnectedParameters()[0], (ProgWidgetArea)widget.getConnectedParameters()[widget.getParameters().length], world, whitelistFilter, blacklistFilter);
}
@Override
public List<Entity> getValidEntities(World world){
return getValidEntities(world, this);
}
public static boolean isEntityValid(Entity entity, IProgWidget widget){
StringFilterEntitySelector whitelistFilter = getEntityFilter((ProgWidgetString)widget.getConnectedParameters()[1], true);
StringFilterEntitySelector blacklistFilter = getEntityFilter((ProgWidgetString)widget.getConnectedParameters()[widget.getParameters().length + 1], false);
return whitelistFilter.isEntityApplicable(entity) && !blacklistFilter.isEntityApplicable(entity);
}
@Override
public boolean isEntityValid(Entity entity){
return isEntityValid(entity, this);
}
public static StringFilterEntitySelector getEntityFilter(ProgWidgetString widget, boolean allowEntityIfNoFilter){
StringFilterEntitySelector filter = new StringFilterEntitySelector();
if(widget != null) {
while(widget != null) {
filter.addEntry(widget.string);
widget = (ProgWidgetString)widget.getConnectedParameters()[0];
}
} else if(allowEntityIfNoFilter) {
filter.setFilter("");
}
return filter;
}
public static List<Entity> getEntitiesInArea(ProgWidgetArea whitelistWidget, ProgWidgetArea blacklistWidget, World world, IEntitySelector whitelistFilter, IEntitySelector blacklistFilter){
if(whitelistWidget == null) return new ArrayList<Entity>();
Set<Entity> entities = new HashSet<Entity>();
ProgWidgetArea widget = whitelistWidget;
while(widget != null) {
entities.addAll(widget.getEntitiesWithinArea(world, whitelistFilter));
widget = (ProgWidgetArea)widget.getConnectedParameters()[0];
}
widget = blacklistWidget;
while(widget != null) {
entities.removeAll(widget.getEntitiesWithinArea(world, whitelistFilter));
widget = (ProgWidgetArea)widget.getConnectedParameters()[0];
}
if(blacklistFilter != null) {
Entity[] entArray = entities.toArray(new Entity[entities.size()]);
for(Entity entity : entArray) {
if(blacklistFilter.isEntityApplicable(entity)) {
entities.remove(entity);
}
}
}
return new ArrayList<Entity>(entities);
}
@Override
@SideOnly(Side.CLIENT)
public GuiScreen getOptionWindow(GuiProgrammer guiProgrammer){
return new GuiProgWidgetAreaShow(this, guiProgrammer);
}
@Override
public WidgetDifficulty getDifficulty(){
return WidgetDifficulty.EASY;
}
@Override
public void setAIManager(DroneAIManager aiManager){
this.aiManager = aiManager;
}
@Override
public void addVariables(Set<String> variables){}
}