package net.osmand.router;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.set.hash.TIntHashSet;
public class TurnType {
public static final int C = 1;//"C"; // continue (go straight) //$NON-NLS-1$
public static final int TL = 2; // turn left //$NON-NLS-1$
public static final int TSLL = 3; // turn slightly left //$NON-NLS-1$
public static final int TSHL = 4; // turn sharply left //$NON-NLS-1$
public static final int TR = 5; // turn right //$NON-NLS-1$
public static final int TSLR = 6; // turn slightly right //$NON-NLS-1$
public static final int TSHR = 7; // turn sharply right //$NON-NLS-1$
public static final int KL = 8; // keep left //$NON-NLS-1$
public static final int KR = 9; // keep right//$NON-NLS-1$
public static final int TU = 10; // U-turn //$NON-NLS-1$
public static final int TRU = 11; // Right U-turn //$NON-NLS-1$
public static final int OFFR = 12; // Off route //$NON-NLS-1$
public static final int RNDB = 13; // Roundabout
public static final int RNLB = 14; // Roundabout left
public static TurnType straight() {
return valueOf(C, false);
}
public int getActiveCommonLaneTurn() {
if(lanes == null || lanes.length == 0) {
return C;
}
for(int i = 0; i < lanes.length; i++) {
if(lanes[i] % 2 == 1) {
return TurnType.getPrimaryTurn(lanes[i]);
}
}
return C;
}
public String toXmlString() {
switch (value) {
case C:
return "C";
case TL:
return "TL";
case TSLL:
return "TSLL";
case TSHL:
return "TSHL";
case TR:
return "TR";
case TSLR:
return "TSLR";
case TSHR:
return "TSHR";
case KL:
return "KL";
case KR:
return "KR";
case TU:
return "TU";
case TRU:
return "TRU";
case OFFR:
return "OFFR";
case RNDB:
return "RNDB"+exitOut;
case RNLB:
return "RNLB"+exitOut;
}
return "C";
}
public static TurnType fromString(String s, boolean leftSide) {
TurnType t = null;
if ("C".equals(s)) {
t = TurnType.valueOf(C, leftSide);
} else if ("TL".equals(s)) {
t = TurnType.valueOf(TL, leftSide);
} else if ("TSLL".equals(s)) {
t = TurnType.valueOf(TSLL, leftSide);
} else if ("TSHL".equals(s)) {
t = TurnType.valueOf(TSHL, leftSide);
} else if ("TR".equals(s)) {
t = TurnType.valueOf(TR, leftSide);
} else if ("TSLR".equals(s)) {
t = TurnType.valueOf(TSLR, leftSide);
} else if ("TSHR".equals(s)) {
t = TurnType.valueOf(TSHR, leftSide);
} else if ("KL".equals(s)) {
t = TurnType.valueOf(KL, leftSide);
} else if ("KR".equals(s)) {
t = TurnType.valueOf(KR, leftSide);
} else if ("TU".equals(s)) {
t = TurnType.valueOf(TU, leftSide);
} else if ("TRU".equals(s)) {
t = TurnType.valueOf(TRU, leftSide);
} else if ("OFFR".equals(s)) {
t = TurnType.valueOf(OFFR, leftSide);
} else if (s != null && (s.startsWith("EXIT") ||
s.startsWith("RNDB") || s.startsWith("RNLB"))) {
try {
t = TurnType.getExitTurn(Integer.parseInt(s.substring(4)), 0, leftSide);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
if(t == null) {
t = TurnType.straight();
}
return t;
}
public static TurnType valueOf(int vs, boolean leftSide) {
if(vs == TU && leftSide) {
vs = TRU;
} else if(vs == RNDB && leftSide) {
vs = RNLB;
}
return new TurnType(vs);
// if (s != null && s.startsWith("EXIT")) { //$NON-NLS-1$
// return getExitTurn(Integer.parseInt(s.substring(4)), 0, leftSide);
// }
// return null;
}
private final int value;
private int exitOut;
// calculated clockwise head rotation if previous direction to NORTH
private float turnAngle;
private boolean skipToSpeak;
private int[] lanes;
private boolean possiblyLeftTurn;
private boolean possiblyRightTurn;
public static TurnType getExitTurn(int out, float angle, boolean leftSide) {
TurnType r = valueOf(RNDB, leftSide); //$NON-NLS-1$
r.exitOut = out;
r.setTurnAngle(angle);
return r;
}
private TurnType(int vl) {
this.value = vl;
}
// calculated Clockwise head rotation if previous direction to NORTH
public float getTurnAngle() {
return turnAngle;
}
public boolean isLeftSide() {
return value == RNLB || value == TRU;
}
public void setTurnAngle(float turnAngle) {
this.turnAngle = turnAngle;
}
public int getValue() {
return value;
}
public int getExitOut() {
return exitOut;
}
public boolean isRoundAbout() {
return value == RNDB || value == RNLB; //$NON-NLS-1$
}
// lanes encoded as array of int
// 0 bit - 0/1 - to use or not
// 1-5 bits - additional turn info
// 6-10 bits - secondary turn
// 11-15 bits - tertiary turn
public void setLanes(int[] lanes) {
this.lanes = lanes;
}
// Note that the primary turn will be the one displayed on the map.
public static void setPrimaryTurnAndReset(int[] lanes, int lane, int turnType) {
lanes[lane] = (turnType << 1);
}
public static int getPrimaryTurn(int laneValue) {
// Get the primary turn modifier for the lane
return (laneValue >> 1) & ((1 << 4) - 1);
}
public static void setSecondaryTurn(int[] lanes, int lane, int turnType) {
lanes[lane] &= ~(15 << 5);
lanes[lane] |= (turnType << 5);
}
public static void setPrimaryTurn(int[] lanes, int lane, int turnType) {
lanes[lane] &= ~(15 << 1);
lanes[lane] |= (turnType << 1);
}
public static int getSecondaryTurn(int laneValue) {
// Get the secondary turn modifier for the lane
return (laneValue >> 5) & ((1 << 5) - 1);
}
public static void setPrimaryTurnShiftOthers(int[] lanes, int lane, int turnType) {
int pt = getPrimaryTurn(lanes[lane]);
int st = getSecondaryTurn(lanes[lane]);
//int tt = getTertiaryTurn(lanes[lane]);
setPrimaryTurnAndReset(lanes, lane, turnType);
setSecondaryTurn(lanes, lane, pt);
setTertiaryTurn(lanes, lane, st);
}
public static void setSecondaryTurnShiftOthers(int[] lanes, int lane, int turnType) {
int st = getSecondaryTurn(lanes[lane]);
//int tt = getTertiaryTurn(lanes[lane]);
setSecondaryTurn(lanes, lane, turnType);
setTertiaryTurn(lanes, lane, st);
}
public static void setTertiaryTurn(int[] lanes, int lane, int turnType) {
lanes[lane] &= ~(15 << 10);
lanes[lane] |= (turnType << 10);
}
public static int getTertiaryTurn(int laneValue) {
// Get the tertiary turn modifier for the lane
return (laneValue >> 10);
}
public static String toString(int[] lns) {
String s = "";
for (int h = 0; h < lns.length; h++) {
if (h > 0) {
s += "|";
}
if (lns[h] % 2 == 1) {
s += "+";
}
int pt = TurnType.getPrimaryTurn(lns[h]);
if (pt == 0) {
pt = 1;
}
s += TurnType.valueOf(pt, false).toXmlString();
int st = TurnType.getSecondaryTurn(lns[h]);
if (st != 0) {
s += "," + TurnType.valueOf(st, false).toXmlString();
}
int tt = TurnType.getTertiaryTurn(lns[h]);
if (tt != 0) {
s += "," + TurnType.valueOf(tt, false).toXmlString();
}
}
s += "";
return s;
}
public int[] getLanes() {
return lanes;
}
public void setPossibleLeftTurn(boolean possiblyLeftTurn) {
this.possiblyLeftTurn = possiblyLeftTurn;
}
public void setPossibleRightTurn(boolean possiblyRightTurn) {
this.possiblyRightTurn = possiblyRightTurn;
}
public boolean isPossibleLeftTurn() {
return possiblyLeftTurn;
}
public boolean isPossibleRightTurn() {
return possiblyRightTurn;
}
public boolean keepLeft() {
return value == KL;
}
public boolean keepRight() {
return value == KR;
}
public boolean goAhead() {
return value == C;
}
public boolean isSkipToSpeak() {
return skipToSpeak;
}
public void setSkipToSpeak(boolean skipToSpeak) {
this.skipToSpeak = skipToSpeak;
}
@Override
public String toString() {
String vl = null;
if (isRoundAbout()) {
vl = "Take " + getExitOut() + " exit";
} else if (value == C) {
vl = "Go ahead";
} else if (value == TSLL) {
vl = "Turn slightly left";
} else if (value == TL) {
vl = "Turn left";
} else if (value == TSHL) {
vl = "Turn sharply left";
} else if (value == TSLR) {
vl = "Turn slightly right";
} else if (value == TR) {
vl = "Turn right";
} else if (value == TSHR) {
vl = "Turn sharply right";
} else if (value == TU) {
vl = "Make uturn";
} else if (value == TRU) {
vl = "Make uturn";
} else if (value == KL) {
vl = "Keep left";
} else if (value == KR) {
vl = "Keep right";
} else if (value == OFFR) {
vl = "Off route";
}
if(vl != null) {
if(lanes != null) {
vl += "(" + toString(lanes) +")";
}
return vl;
}
return super.toString();
}
public static boolean isLeftTurn(int type) {
return type == TL || type == TSHL || type == TSLL || type == TU || type == KL;
}
public static boolean isLeftTurnNoUTurn(int type) {
return type == TL || type == TSHL || type == TSLL || type == KL;
}
public static boolean isRightTurn(int type) {
return type == TR || type == TSHR || type == TSLR || type == TRU || type == KR;
}
public static boolean isRightTurnNoUTurn(int type) {
return type == TR || type == TSHR || type == TSLR || type == KR;
}
public static boolean isSlightTurn(int type) {
return type == TSLL || type == TSLR || type == C || type == KL || type == KR;
}
public static boolean hasAnySlightTurnLane(int type) {
return TurnType.isSlightTurn(TurnType.getPrimaryTurn(type))
|| TurnType.isSlightTurn(TurnType.getSecondaryTurn(type))
|| TurnType.isSlightTurn(TurnType.getTertiaryTurn(type));
}
public static boolean hasAnyTurnLane(int type, int turn) {
return TurnType.getPrimaryTurn(type) == turn
|| TurnType.getSecondaryTurn(type) == turn
|| TurnType.getTertiaryTurn(type) == turn;
}
public static void collectTurnTypes(int lane, TIntHashSet set) {
int pt = TurnType.getPrimaryTurn(lane);
if(pt != 0) {
set.add(pt);
}
pt = TurnType.getSecondaryTurn(lane);
if(pt != 0) {
set.add(pt);
}
pt = TurnType.getTertiaryTurn(lane);
if(pt != 0) {
set.add(pt);
}
}
public static int orderFromLeftToRight(int type) {
switch(type) {
case TU:
return -5;
case TSHL:
return -4;
case TL:
return -3;
case TSLL:
return -2;
case KL:
return -1;
case TRU:
return 5;
case TSHR:
return 4;
case TR:
return 3;
case TSLR:
return 2;
case KR:
return 1;
default:
return 0;
}
}
public static int convertType(String lane) {
int turn;
if (lane.equals("none") || lane.equals("through")) {
turn = TurnType.C;
} else if (lane.equals("slight_right") ||
lane.equals("merge_to_right")) {
turn = TurnType.TSLR;
} else if (lane.equals("slight_left") ||
lane.equals("merge_to_left")) {
turn = TurnType.TSLL;
} else if (lane.equals("right")) {
turn = TurnType.TR;
} else if (lane.equals("left")) {
turn = TurnType.TL;
} else if (lane.equals("sharp_right")) {
turn = TurnType.TSHR;
} else if (lane.equals("sharp_left")) {
turn = TurnType.TSHL;
} else if (lane.equals("reverse")) {
turn = TurnType.TU;
} else {
// Unknown string
turn = TurnType.C;
// continue;
}
return turn;
}
}