package org.codecranachan.asteroidpush.content.actors;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import org.codecranachan.asteroidpush.base.simulation.Actor;
import org.codecranachan.asteroidpush.base.simulation.ActorFactory;
import org.codecranachan.asteroidpush.base.simulation.RigidBodyFactory;
import org.codecranachan.asteroidpush.base.workshop.actor.ActorSkeleton;
import org.codecranachan.asteroidpush.base.workshop.actor.Behavior;
import org.codecranachan.asteroidpush.base.workshop.actor.BodyVertex;
import org.codecranachan.asteroidpush.base.workshop.actor.ModularActor;
import org.codecranachan.asteroidpush.base.workshop.assembly.BehaviorFactory;
import org.codecranachan.asteroidpush.base.workshop.assembly.Component;
import org.codecranachan.asteroidpush.base.workshop.assembly.Part;
import org.codecranachan.asteroidpush.base.workshop.assembly.Plug;
import org.codecranachan.asteroidpush.base.workshop.assembly.Socket;
import org.codecranachan.asteroidpush.base.workshop.tokenboard.Board;
import org.codecranachan.asteroidpush.base.workshop.tokenboard.Placement;
import org.codecranachan.asteroidpush.base.workshop.tokenboard.Token;
import org.codecranachan.asteroidpush.utils.Angle;
import org.codecranachan.asteroidpush.utils.Arrow;
import org.codecranachan.asteroidpush.utils.NewtonianState;
import org.codecranachan.asteroidpush.utils.OrthogonalCoordinate;
import org.jbox2d.common.MathUtils;
import org.jbox2d.common.Vec2;
public class SpaceshipFactory implements ActorFactory {
private Board blueprint;
private RigidBodyFactory bodyFactory;
private float gridSize;
public SpaceshipFactory(Board blueprint, float gridSize) {
assert (blueprint != null);
this.blueprint = blueprint;
this.bodyFactory = null;
this.gridSize = gridSize;
}
public void setBodyFactory(RigidBodyFactory factory) {
assert (factory != null);
this.bodyFactory = factory;
}
public Actor createActor(NewtonianState initialState) {
assert (bodyFactory != null);
ActorSkeleton skeleton = assembleSkeleton();
ModularActor ship = new ModularActor(skeleton);
skeleton.spawnBodies(initialState, bodyFactory);
return ship;
}
/**
* Builds a new ActorSkeleton from the given Blueprint.
*/
private ActorSkeleton assembleSkeleton() {
ActorSkeleton skeleton = new ActorSkeleton();
for (Token token : blueprint.getTokens()) {
attachToken(skeleton, token);
}
return skeleton;
}
private void attachToken(ActorSkeleton skeleton, Token token) {
Part part = (Part) token.getData();
Placement placement = token.getPlacement();
HashMap<BehaviorFactory, Behavior> created = new HashMap<BehaviorFactory, Behavior>();
for (Component component : part.getComponents()) {
BodyVertex node = new BodyVertex();
Socket socket = component.getSocket();
Collection<OrthogonalCoordinate> links = transformLinks(socket.getLinks(),
placement);
skeleton.insertVertex(node, links);
for (Plug plug : component.getPlugs()) {
BehaviorFactory factory = plug.getFactory();
Behavior behavior;
if (created.containsKey(factory)) {
behavior = created.get(factory);
} else {
behavior = factory
.createBehavior(computeNodePlacement(placement), gridSize);
created.put(factory, behavior);
}
node.addPlug(behavior, plug.getIndex());
}
}
}
private Collection<OrthogonalCoordinate> transformLinks(Collection<OrthogonalCoordinate> links,
Placement placement) {
Collection<OrthogonalCoordinate> transformed = new LinkedList<OrthogonalCoordinate>();
for (OrthogonalCoordinate link : links) {
transformed.add(computeConnectorCoordinate(placement, link));
}
return transformed;
}
private OrthogonalCoordinate computeConnectorCoordinate(Placement placement,
OrthogonalCoordinate relativeCoordinate) {
OrthogonalCoordinate absoluteCoordinate = new OrthogonalCoordinate(
relativeCoordinate);
absoluteCoordinate.turn(placement.getOrientation());
absoluteCoordinate.move(placement.getPivotCoordinate().getX() * 2,
placement.getPivotCoordinate().getY() * 2);
return absoluteCoordinate;
}
private Arrow computeNodePlacement(Placement placement) {
float quarter_turns_per_revolution = 4f;
float orientation = (float) placement.getOrientation();
float angle = orientation * MathUtils.TWOPI
/ quarter_turns_per_revolution;
OrthogonalCoordinate loc = placement.getPivotCoordinate();
Vec2 origin = new Vec2((float) loc.getX(), (float) loc.getY());
origin.mulLocal(gridSize);
return new Arrow(origin, Angle.fromRad(angle));
}
}