package ttftcuts.physis.puzzle.oddoneout;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import ttftcuts.physis.Physis;
import ttftcuts.physis.common.block.tile.TileEntityDigSite;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
public class OddOneOutBuilder {
private LinkedBlockingQueue<Request> queue;
private volatile Queue<Request> finishedQueue;
private Set<Request> waitingRoom;
private Builder builder;
private final Request poison = new Request(-1, null, 0, 0);
public OddOneOutBuilder() {
queue = new LinkedBlockingQueue<Request>();
finishedQueue = new ConcurrentLinkedQueue<Request>();
waitingRoom = new HashSet<Request>();
OddOneOutProperty.registerProperties();
OddOneOutConstraintSolver.makePermutationList();
}
public void requestPuzzle(int difficulty, TileEntity tile, int layerid, int seed) {
World world = tile.getWorldObj();
if (world.isRemote) { return; }
if (queue != null) {
try {
Request req = new Request(difficulty, tile, layerid, seed);
if (!waitingRoom.contains(req)) {
queue.put(req);
waitingRoom.add(req);
}
//Physis.logger.info(queue);
//Physis.logger.info(waitingRoom);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void start() {
Physis.logger.info("Starting Odd One Out Builder");
queue.clear();
finishedQueue.clear();
waitingRoom.clear();
builder = new Builder("Physis Odd One Out Builder");
builder.setPriority(Thread.MIN_PRIORITY);
builder.start();
}
public void stop() {
if (builder != null) {
try {
Physis.logger.info("Stopping Odd One Out Builder");
queue.clear();
queue.put(poison);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void update() {
Request r = finishedQueue.poll();
if (r != null) {
//Physis.logger.info("Received finished puzzle for tile at "+r.x+","+r.y+","+r.z+" in "+r.world+" with difficulty "+r.difficulty);
waitingRoom.remove(r);
if (r.world != null) {
TileEntity tile = r.world.getTileEntity(r.x, r.y, r.z);
if (tile != null && (tile instanceof TileEntityDigSite)) {
TileEntityDigSite dig = (TileEntityDigSite)tile;
dig.setLayerPuzzle(r.layerid, r.puzzle);
}
}
}
}
@SuppressWarnings("unused")
private class Request {
public final World world;
public final int x;
public final int y;
public final int z;
public final int difficulty;
public final int layerid;
public final int seed;
public boolean finished = false;
public OddOneOutPuzzle puzzle;
//public
public Request(int difficulty, TileEntity tile, int layerid, int seed) {
this.difficulty = difficulty;
this.world = tile == null ? null : tile.getWorldObj();
this.x = tile == null ? 0 : tile.xCoord;
this.y = tile == null ? 0 : tile.yCoord;
this.z = tile == null ? 0 : tile.zCoord;
this.layerid = layerid;
this.seed = seed;
}
@Override
public boolean equals(Object other) {
if (other instanceof Request) {
Request or = (Request) other;
if (this.world == or.world
&& this.x == or.x
&& this.y == or.y
&& this.z == or.z
&& this.difficulty == or.difficulty
&& this.layerid == or.layerid
&& this.seed == or.seed) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return this.world.hashCode()
// 8 digit primes
+ this.x * 45269999
+ this.y * 10312007
+ this.z * 60686069
+ this.difficulty * 23010067
+ this.layerid * 37171397
+ this.seed; // big random number anyway
}
@Override
public String toString() {
return "(Request "+this.hashCode()+" ("+this.x+","+this.y+","+this.z+") "+this.difficulty+", "+this.layerid+", "+this.seed+")";
}
}
private class Builder extends Thread {
private volatile boolean keepRunning = true;
public Builder(String name) {
super(name);
}
public void run() {
Physis.logger.info("Starting thread");
while(keepRunning) {
try {
Request r = queue.take();
if ( r.difficulty == -1 ){ break; }
process(r);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
}
}
Physis.logger.info("Shutting down thread");
}
private void process(Request r) {
//Physis.logger.info("Took request by tile at "+r.x+","+r.y+","+r.z+" in "+r.world+" with difficulty "+r.difficulty);
r.finished = true;
r.puzzle = OddOneOutConstraintSolver.buildPuzzle(r.difficulty, r.seed);
finishedQueue.add(r);
}
}
}