package mekanism.api.transmitters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import mekanism.api.Object3D;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
public abstract class DynamicNetwork implements ITransmitterNetwork
{
public HashSet> transmitters = new HashSet>();
public HashSet possibleAcceptors = new HashSet();
public HashMap acceptorDirections = new HashMap();
protected int ticksSinceCreate = 0;
protected boolean fixed = false;
protected abstract ITransmitterNetwork create(ITransmitter... varTransmitters);
protected abstract ITransmitterNetwork create(Collection> collection);
protected abstract ITransmitterNetwork create(Set networks);
public void addAllTransmitters(Set> newTransmitters)
{
transmitters.addAll(newTransmitters);
}
@Override
public void removeTransmitter(ITransmitter transmitter)
{
transmitters.remove(transmitter);
if(transmitters.size() == 0)
{
deregister();
}
}
@Override
public void register()
{
try {
ITransmitter aTransmitter = transmitters.iterator().next();
if(aTransmitter instanceof TileEntity && !((TileEntity)aTransmitter).worldObj.isRemote)
{
TransmitterNetworkRegistry.getInstance().registerNetwork(this);
}
} catch(NoSuchElementException e) {}
}
@Override
public void deregister()
{
transmitters.clear();
TransmitterNetworkRegistry.getInstance().removeNetwork(this);
}
@Override
public int getSize()
{
return transmitters.size();
}
@Override
public int getAcceptorSize()
{
return possibleAcceptors.size();
}
@Override
public void tick()
{
if(!fixed)
{
++ticksSinceCreate;
if(ticksSinceCreate > 1200)
{
ticksSinceCreate = 0;
fixMessedUpNetwork(transmitters.iterator().next());
}
}
}
@Override
public synchronized void fixMessedUpNetwork(ITransmitter transmitter)
{
if(transmitter instanceof TileEntity)
{
NetworkFinder finder = new NetworkFinder(((TileEntity)transmitter).getWorldObj(), getTransmissionType(), Object3D.get((TileEntity)transmitter));
List partNetwork = finder.exploreNetwork();
Set> newTransporters = new HashSet>();
for(Object3D node : partNetwork)
{
TileEntity nodeTile = node.getTileEntity(((TileEntity)transmitter).worldObj);
if(TransmissionType.checkTransmissionType(nodeTile, getTransmissionType(), (TileEntity) transmitter))
{
((ITransmitter)nodeTile).removeFromTransmitterNetwork();
newTransporters.add((ITransmitter)nodeTile);
}
}
ITransmitterNetwork newNetwork = create(newTransporters);
newNetwork.refresh();
newNetwork.setFixed(true);
deregister();
}
}
@Override
public synchronized void split(ITransmitter splitPoint)
{
if(splitPoint instanceof TileEntity)
{
removeTransmitter(splitPoint);
TileEntity[] connectedBlocks = new TileEntity[6];
boolean[] dealtWith = {false, false, false, false, false, false};
for(ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS)
{
TileEntity sideTile = Object3D.get((TileEntity)splitPoint).getFromSide(direction).getTileEntity(((TileEntity)splitPoint).worldObj);
if(sideTile != null)
{
connectedBlocks[Arrays.asList(ForgeDirection.values()).indexOf(direction)] = sideTile;
}
}
for(int countOne = 0; countOne < connectedBlocks.length; countOne++)
{
TileEntity connectedBlockA = connectedBlocks[countOne];
if(TransmissionType.checkTransmissionType(connectedBlockA, getTransmissionType()) && !dealtWith[countOne])
{
NetworkFinder finder = new NetworkFinder(((TileEntity)splitPoint).worldObj, getTransmissionType(), Object3D.get(connectedBlockA), Object3D.get((TileEntity)splitPoint));
List partNetwork = finder.exploreNetwork();
for(int countTwo = countOne + 1; countTwo < connectedBlocks.length; countTwo++)
{
TileEntity connectedBlockB = connectedBlocks[countTwo];
if(TransmissionType.checkTransmissionType(connectedBlockB, getTransmissionType()) && !dealtWith[countTwo])
{
if(partNetwork.contains(Object3D.get(connectedBlockB)))
{
dealtWith[countTwo] = true;
}
}
}
Set> newNetCables = new HashSet>();
for(Object3D node : finder.iterated)
{
TileEntity nodeTile = node.getTileEntity(((TileEntity)splitPoint).worldObj);
if(TransmissionType.checkTransmissionType(nodeTile, getTransmissionType()))
{
if(nodeTile != splitPoint)
{
newNetCables.add((ITransmitter)nodeTile);
}
}
}
ITransmitterNetwork newNetwork = create(newNetCables);
newNetwork.refresh();
}
}
deregister();
}
}
@Override
public void setFixed(boolean value)
{
fixed = value;
}
public static class NetworkFinder
{
public TransmissionType transmissionType;
public World worldObj;
public Object3D start;
public List iterated = new ArrayList();
public List toIgnore = new ArrayList();
public NetworkFinder(World world, TransmissionType type, Object3D location, Object3D... ignore)
{
worldObj = world;
start = location;
transmissionType = type;
if(ignore != null)
{
for(int i = 0; i < ignore.length; i++)
{
this.toIgnore.add(ignore[i]);
}
}
}
public void loopAll(Object3D location)
{
if(TransmissionType.checkTransmissionType(location.getTileEntity(worldObj), transmissionType))
{
iterated.add(location);
}
else {
toIgnore.add(location);
}
for(ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS)
{
Object3D obj = location.getFromSide(direction);
if(!iterated.contains(obj) && !toIgnore.contains(obj))
{
TileEntity tileEntity = obj.getTileEntity(worldObj);
if(TransmissionType.checkTransmissionType(tileEntity, transmissionType, location.getTileEntity(worldObj)))
{
loopAll(obj);
}
}
}
}
public List exploreNetwork()
{
loopAll(start);
return iterated;
}
}
}