package trafficjams.model.classes;
import trafficjams.model.interfaces.ICrossRoad;
import trafficjams.model.interfaces.IElementPosition;
import trafficjams.model.interfaces.IRoad;
import trafficjams.model.interfaces.IVehicle;
import trafficjams.model.registers.RoadMap;
import trafficjams.model.trafficutils.Directions;
import trafficjams.model.util.Point;
import java.util.HashMap;
import java.util.HashSet;
/**
* Created by IntelliJ IDEA.
* User: Администратор
* Date: 13.11.11
* Time: 15:50
* To change this template use File | Settings | File Templates.
*/
public class CrossRoad implements ICrossRoad{
private Point coord = null; //координаты перекрестка
private IRoad[] roads = new Road[4]; //входящии в переврестов дороги, индекс соответствует тому откуда дорога входит
//можно посмотреть в классе CrossDirecctions
private int type = 0 ; //тип переврестка - сколько дорог в него входит
private RoadMap map = null;
private HashMap<Integer, IVehicle[]> crossQueues = null; // очереди для автомобилей на перекрестке, по ключю типа Integer
//получать соответсвующюю очередь по интовому ключу, который рассчитывается по формуле в функции
HashSet<IVehicle> vehiclesOnCross = null;
private static Integer queueKey(int fromDir, int toDir , int vehDir){
return new Integer(fromDir*toDir + fromDir*vehDir);
}
private CrossRoad(){
coord = null;
}
public CrossRoad(RoadMap map){
coord = null;
this.map = map;
vehiclesOnCross = new HashSet<IVehicle>();
}
public Point getCoord() {
return coord;
}
public int canOccupDirection(Directions direction) {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
public Directions directionForRoad(IRoad road) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public int canReleaseDirection(Directions direction) {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
public IElementPosition getNextPosition(IVehicle vehicle, float distance, IRoad nextElement) throws Exception {
try{
IRoad from = (IRoad)vehicle.getCurrentElement();
IRoad to = nextElement;
return this.tryToKeepFor(vehicle,from, to);
}catch (Exception ex){
try{
return this.findQueue(vehicle, distance, nextElement);
}
catch (Exception ex1){
ex1.printStackTrace();
return null;
}
}
}
private IElementPosition findQueue(IVehicle vehicle, float distance, IRoad nextElement) throws Exception {
if (vehiclesOnCross.contains(vehicle)){
//for (Integer key : crossQueues.keySet()){
Integer key = ((CrossPosition)vehicle.getCurrentPosition()).getQueueKey();
IVehicle[] retVal = crossQueues.get(key);
for (int i = 0 ; i<3 ; ++i){
if (vehicle.equals(retVal[i])){
if (i!=0){
if (retVal[i-1]==null){
retVal[i] = null;
retVal[i-1] = vehicle;
return new CrossPosition(this, i-1,key);
}else {
return null;
}
}else {
Object ret = nextElement.keepRoad(vehicle, distance);
if (ret != null){
vehiclesOnCross.remove(vehicle);
retVal[0] = null;
}
return (IElementPosition) ret;
}
}
}
//}
}else {
IVehicle[] retVal = this.findQueueForCarOnRoad(vehicle, nextElement);
if (retVal==null){
return null;
}
if (retVal[2] != null ){
return null;
}
vehiclesOnCross.add(vehicle);
retVal[2] = vehicle;
return new CrossPosition(this,2);
}
throw new Exception("хрень с очередями на перекрестке");
}
private IVehicle[] findQueueForCarOnRoad(IVehicle vehicle, IRoad nextElement) throws Exception {
int _from = -1 ;
int _to = -1 ;
for (int i = 0 ; i < 4 ; ++i){
if (vehicle.getCurrentPosition().getElement().equals(roads[i])){
_from = i;
//continue;
}
if (nextElement.equals(roads[i])){
_to = i ;
}
}
if (_from == -1 || _to == -1){
throw new Exception("хрень с направлениями");
}
return crossQueues.get(queueKey(_from,_to,getVehicleDirection(_from,_to)));
}
private IElementPosition tryToKeepFor(IVehicle vehicle, IRoad from, IRoad to) throws Exception {
int _from = -1 ;
int _to = -1 ;
for (int i = 0 ; i < 4 ; ++i){
if (from.equals(roads[i])){
_from = i;
//continue;
}
if (to.equals(roads[i])){
_to = i ;
}
}
if (_from == -1 || _to == -1){
throw new Exception("хрень с направлениями");
}
int key = queueKey(_from,_to,getVehicleDirection(_from,_to));
//еще дореализовать режимы!
if (crossQueues.get(key) != null ){
this.vehiclesOnCross.add(vehicle);
this.crossQueues.get(key)[2] = vehicle;
return new CrossPosition(this,key);
}else {
return null;
}
}
public void setCoord(Point coord){
this.coord = coord;
}
public CrossRoad (Point coord){
this.coord = coord;
}
public void setRoadForDirection(IRoad road, int dir){
if (roads[dir] == null){
++type;
}
roads[dir] = road;
}
public int deleteRoad(IRoad r) {
for (int i = 0 ; i< 4 ; ++i){
if (r.equals(roads[i])){
roads[i] = null;
--type;
return i;
}
}
return -1;
}
public int getType() {
return type;
}
public IRoad[] get2Roads() throws Exception {
IRoad[] retVal= new IRoad[2];
int j = 0;
for (int i = 0 ; i<4 ; ++i){
if (roads[i] !=null){
retVal[j++] = roads[i];
}
}
if (j != 2){
throw new Exception("Wrong 2 road count: "+j);
}
return retVal;
}
public IRoad[] getRoads() {
return roads;
}
public void setMap(RoadMap map) {
this.map = map;
}
public RoadMap getMap() {
return map;
}
private int getVehicleDirection(int fromDir, int toDir){
int vehDir = -1 ;
int dir = ((toDir+4) - fromDir) % 4;
switch (dir){
case 0:{
vehDir = Directions.Reverse;
break;
}
case 1:{
vehDir = Directions.Left;
break;
}
case 2:{
vehDir = Directions.Direct;
break;
}
case 3:{
vehDir = Directions.Right;
break;
}
default:
break;
}
return vehDir;
}
public IVehicle[] getQueueByDirections(int fromDir , int toDir){
return crossQueues.get(getVehicleDirection(queueKey(fromDir, toDir ,fromDir), toDir));
}
public void initQueues() {
crossQueues = new HashMap <Integer , IVehicle[]>();
for (int i = 0 ; i < 4 ; ++i ){
for (int j = 0 ; j < 4 ; ++j){
/*if (roads[i] == null || roads[j] == null){
continue;
}*/
IVehicle[] a = new IVehicle[3];
int vehDir = getVehicleDirection(i,j);
crossQueues.put(queueKey(i,j,vehDir), a);
}
}
}
public IRoad findRoad(ICrossRoad nextCross) throws Exception {
for(int i = 0 ; i < 4 ; ++i ){
if (((Road)roads[i]).getOtherEnd(this).equals(nextCross)){
return roads[i];
}
}
throw new Exception("find road error");
}
}