package com.voxeo.moho.util;
import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.voxeo.moho.common.util.NetworkUtils;
import com.voxeo.moho.common.util.StringUtils;
import com.voxeo.moho.remotejoin.RemoteParticipant;
public class ParticipantIDParser {
protected static long TYPE_CALL = 1L;
protected static long TYPE_CONFERENCE = 2L;
protected static long TYPE_DIALOG = 3L;
// format moho://ip:port/<type>/<callid>
public static Pattern pattern = Pattern.compile("moho://(\\S+):(\\S+)/(\\S+)/(\\S+)");
// We use only lowercased letters and numbers as other protocols may need normalized ids so
// using this alphabet makes things much simpler
static String alphabet = "abcdefghijklmnopqrstuvwxyz1234567890";
public static String encode(String raw) {
String[] parts = parseId(raw);
return shorten(toBigInteger(parts[0])) + "-" +
shorten(toBigInteger(parts[1], parts[2])) + "-" +
shorten(new BigInteger(parts[3]));
}
private static BigInteger toBigInteger(String ip) {
StringBuilder builder = new StringBuilder();
builder.append(ipToNormalizedLongString(ip));
return new BigInteger(builder.toString());
}
private static BigInteger toBigInteger(String port, String type) {
StringBuilder builder = new StringBuilder();
builder.append(portToNormalizedLongString(port));
builder.append(getNumericType(type));
return new BigInteger(builder.toString());
}
protected static Object portToNormalizedLongString(String port) {
return String.format("%05d", Long.parseLong(port));
}
protected static String ipToNormalizedLongString(String ip) {
StringBuilder builder = new StringBuilder();
int i = 0,j = 0;
while ((j=ip.indexOf('.', i)) != -1) {
builder.append(String.format("%03d",Integer.parseInt(ip.substring(i,j))));
i = j+1;
}
builder.append(String.format("%03d",Integer.parseInt(ip.substring(i, ip.length()))));
return builder.toString();
}
public static String decode(String encoded) {
String[] parts = StringUtils.split(encoded, "-");
BigInteger decodedIp = unshort(parts[0]);
String ipAddress = toIpAddress(decodedIp.longValue());
String portAndType = String.valueOf(unshort(parts[1]));
String type = toRemoteType(portAndType.charAt(portAndType.length()-1));
String port = String.valueOf(Long.valueOf(portAndType.substring(0, portAndType.length()-1)));
String timestamp = unshort(parts[2]).toString();
return String.format("moho://%s:%s/%s/%s", ipAddress, port, type, timestamp);
}
protected static String toIpAddress(long encodedIp) {
StringBuilder builder = new StringBuilder();
String str = String.format("%012d", encodedIp);
int i=0;
while (i<str.length()) {
builder.append(Long.valueOf(str.substring(i,i+3)) + ".");
i+=3;
}
builder.deleteCharAt(builder.length()-1);
return builder.toString();
}
public static String[] parseId(String raw) {
// ip, port, type, id
Matcher matcher = pattern.matcher(raw);
if (matcher.matches()) {
return new String[] { matcher.group(1), matcher.group(2),
matcher.group(3), matcher.group(4) };
}
throw new IllegalArgumentException("Illegal ID format:" + raw);
}
public static String getIpAddress(String encoded) {
String decoded = decode(encoded);
if (decoded != null) {
String[] parts = parseId(decoded);
if (parts != null && parts.length > 0) {
return parts[0];
}
}
return null;
}
public static String[] parseEncodedId(String encodedId) {
String raw = ParticipantIDParser.decode(encodedId);
return ParticipantIDParser.parseId(raw);
}
protected static long getNumericType(String raw) {
if (raw.contains(RemoteParticipant.RemoteParticipant_TYPE_CALL)) {
return TYPE_CALL;
} else if (raw.contains(RemoteParticipant.RemoteParticipant_TYPE_CONFERENCE)) {
return TYPE_CONFERENCE;
} else if (raw.contains(RemoteParticipant.RemoteParticipant_TYPE_DIALOG)) {
return TYPE_DIALOG;
}
return 0;
}
protected static String toRemoteType(char type) {
long value = Long.parseLong("" + type);
if (value == TYPE_CALL) {
return RemoteParticipant.RemoteParticipant_TYPE_CALL;
} else if (value == TYPE_CONFERENCE) {
return RemoteParticipant.RemoteParticipant_TYPE_CONFERENCE;
} else if (value == TYPE_DIALOG) {
return RemoteParticipant.RemoteParticipant_TYPE_DIALOG;
}
return null;
}
protected static String shorten(BigInteger number) {
StringBuilder builder = new StringBuilder();
int url;
do {
url = number.mod(new BigInteger("36")).intValue();
number = number.divide(new BigInteger("36"));
builder.append(alphabet.charAt(url));
} while (number.compareTo(BigInteger.ZERO) > 0);
return builder.toString();
}
protected static BigInteger unshort(String shorted) {
BigInteger total = new BigInteger("0");
//shorted = StringUtils.reverse(shorted);
for (int i=0;i<shorted.length();i++) {
long j = (long)(Math.pow(36, i) * alphabet.indexOf(shorted.charAt(i)));
total = total.add(new BigInteger(String.valueOf(j)));
}
return total;
}
public static boolean isCall(RemoteParticipant participant) {
long type = getNumericType(decode(participant.getId()));
return (type == TYPE_CALL);
}
public static boolean isMixer(RemoteParticipant participant) {
long type = getNumericType(decode(participant.getId()));
return (type == TYPE_CONFERENCE);
}
public static void main(String[] args) {
System.out.println(NetworkUtils.getLocalAddress().toString());
System.out.println(ipToNormalizedLongString("127.0.0.1"));
System.out.println(ipToNormalizedLongString("12.0.20.1"));
System.out.println(ipToNormalizedLongString("1.0.0.1"));
System.out.println(ipToNormalizedLongString("127.120.202.221"));
System.out.println(ipToNormalizedLongString("12.120.22.221"));
}
}