/*******************************************************************************
* Copyright (c) 2009 Vlad Dumitrescu and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Vlad Dumitrescu
*******************************************************************************/
package org.erlide.runtime.runtimeinfo;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.base.Preconditions;
public class RuntimeVersion implements Comparable<RuntimeVersion> {
public static final int UNUSED = Integer.MIN_VALUE;
public static final RuntimeVersion NO_VERSION = new RuntimeVersion(UNUSED);
private final int major;
private final int minor;
private final int micro;
private final String update_level;
public RuntimeVersion(final RuntimeVersion other) {
major = other.major;
minor = other.minor;
micro = other.micro;
update_level = other.update_level;
}
public RuntimeVersion(final int major, final int minor, final int micro,
final String update_level) {
this.major = major;
this.minor = minor;
this.micro = micro;
this.update_level = update_level;
}
public RuntimeVersion(final int major, final int minor, final int micro) {
this(major, minor, micro, null);
}
public RuntimeVersion(final int major, final int minor) {
this(major, minor, UNUSED, null);
}
public RuntimeVersion(final int major) {
this(major, UNUSED, UNUSED, null);
}
public static class Serializer {
private static final char[] minorMap = new char[] { 'A', 'B', 'C' };
public static RuntimeVersion parse(final String version) {
return parse(version, null);
}
public static RuntimeVersion parseOld(final String version, final String aMicro) {
int major;
int minor = UNUSED;
int micro = UNUSED;
String update_level = null;
Preconditions.checkArgument(version.charAt(0) == 'R');
int i = 1;
char c;
do {
c = version.charAt(i);
if (c >= '0' && c <= '9') {
i++;
}
} while (c >= '0' && c <= '9' && i < version.length());
final String substring = version.substring(1, i);
major = Integer.parseInt(substring);
if (i < version.length()) {
c = version.charAt(i);
minor = Arrays.binarySearch(minorMap, c);
i++;
if (i < version.length()) {
final int n1 = version.indexOf('-');
final int n2 = version.indexOf('_');
int n;
if (n1 == -1) {
n = n2;
} else if (n2 == -1) {
n = n1;
} else {
n = Math.min(n1, n2);
}
if (n == -1) {
micro = Integer.parseInt(version.substring(i));
} else {
micro = Integer.parseInt(version.substring(i, n));
update_level = version.substring(n);
}
} else {
micro = 0;
}
}
return new RuntimeVersion(major, minor, micro, update_level);
}
public static RuntimeVersion parseNew(final String version, final String aMicro) {
final int major;
int minor = 0;
int micro = 0;
String update_level = null;
final Pattern p = Pattern.compile("(\\d+)(\\.\\d+)?(\\.\\d+)?([\\._-].+)?");
final Matcher m = p.matcher(version);
if (!m.matches()) {
return null; // throw?
}
major = Integer.parseInt(m.group(1));
minor = getValue(m, 2);
micro = getValue(m, 3);
final String extra = m.group(4);
if (extra != null) {
try {
update_level = extra;
} catch (final Exception e) {
update_level = null;
}
}
return new RuntimeVersion(major, minor, micro, update_level);
}
private static int getValue(final Matcher m, final int i) {
final String group = m.group(i);
if (group == null) {
return 0;
}
return Integer.parseInt(group.substring(1));
}
public static RuntimeVersion parse(final String version, final String aMicro) {
if (version == null || version.length() == 0) {
return NO_VERSION;
}
if (version.charAt(0) == 'R') {
return parseOld(version, aMicro);
}
return parseNew(version, aMicro);
}
public static String toStringOld(final RuntimeVersion version) {
String result = "R" + Integer.toString(version.major);
if (version.minor != UNUSED) {
result += minorMap[version.minor];
if (version.micro != UNUSED) {
String m = Integer.toString(version.micro);
if (version.micro != 0) {
if (m.length() == 1) {
m = "0" + m;
}
result += m;
if (version.update_level != null) {
result += version.update_level;
}
}
}
}
return result;
}
public static String toStringNew(final RuntimeVersion version) {
String result = Integer.toString(version.major);
if (version.minor != UNUSED) {
result += "." + Integer.toString(version.minor);
}
if (version.micro != UNUSED) {
result += "." + Integer.toString(version.micro);
}
if (version.update_level != null) {
result += version.update_level;
}
return result;
}
}
@Override
public String toString() {
if (major == UNUSED) {
return "";
}
if (major < 17) {
return Serializer.toStringOld(this);
}
return Serializer.toStringNew(this);
}
@Override
public boolean equals(final Object v) {
if (!(v instanceof RuntimeVersion)) {
return false;
}
final RuntimeVersion other = (RuntimeVersion) v;
return compareTo(other) == 0;
}
@Override
public int compareTo(final RuntimeVersion o) {
if (major == o.major) {
final int isNew = major >= 17 ? -1 : 1;
if (minor == o.minor) {
if (micro == o.micro) {
if (update_level == o.update_level) {
return 0;
}
if (update_level == null) {
return -1 * isNew;
}
if (o.update_level == null) {
return 1 * isNew;
}
return update_level.compareTo(o.update_level);
}
return micro - o.micro;
}
return minor - o.minor;
}
return major - o.major;
}
public boolean isDefined() {
return major != UNUSED;
}
public boolean isCompatible(final RuntimeVersion other) {
return major >= other.major;
}
public boolean isReleaseCompatible(final RuntimeVersion other) {
return major == UNUSED || other.major == UNUSED || isCompatible(other);
}
public RuntimeVersion asMinor() {
return new RuntimeVersion(major, minor);
}
public RuntimeVersion asMajor() {
return new RuntimeVersion(major);
}
@Override
public int hashCode() {
return super.hashCode();
}
public boolean isStable() {
return minor > 0;
}
public int getMajor() {
return major;
}
public int getMinor() {
return major;
}
public int getMicro() {
return major;
}
}