package de.skuzzle.polly.sdk;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* <p>This class represents a three-part version number. The parts are called
* VERSION, REVISION and BUILD and are integer fields. A Version has a natural order,
* which is given by the values of its parts in the order from VERSION to BUILD.</p>
*
* <p>A version number can optionally have a descriptive name.</p>
*
* @author Simon
* @version 28.07.2011
* @since Beta 0.9
* @see #compareTo(Version)
*/
public class Version implements Comparable<Version> {
/**
* The highest field part.
*/
public final static int VERSION = 0;
/**
* The middle field part.
*/
public final static int REVISION = 1;
/**
* The lowest field part.
*/
public final static int BUILD = 2;
private final static Pattern PATTERN = Pattern.compile(
"(\\d+).(\\d+).(\\d+)( - (.+))?"); //$NON-NLS-1$
private int[] fields;
private String versionString;
private String name;
/**
* <p>Creates a new version from a String. The String must follow exactly this
* formatting scheme: It must have three integer parts separated by a '.' (dot). Those
* three parts can optionally be followed by a dash surrounded by spaces following a
* description name of this version.</p>
*
* <p>For example {@code 1.3.4} as well as {@code 0.2.1} and {@code 0.0.0} are valid
* version strings as well as {@code 1.2.3 - beta}</p>
*
* @param version The version string to parse.
* @throws IllegalArgumentException If {@code version} does not follow the formatting
* rules.
*/
public Version(String version) {
Matcher m = PATTERN.matcher(version);
if (!m.matches()) {
throw new IllegalArgumentException("misformatted version string: " + version); //$NON-NLS-1$
}
String v1 = version.substring(m.start(1), m.end(1));
String v2 = version.substring(m.start(2), m.end(2));
String v3 = version.substring(m.start(3), m.end(3));
try {
this.fields = new int[] {Integer.parseInt(v1),
Integer.parseInt(v2),
Integer.parseInt(v3)};
} catch (NumberFormatException e) {
throw new IllegalArgumentException("misformatted version string: " + version); //$NON-NLS-1$
}
if (m.groupCount() >= 5) {
this.name = version.substring(m.start(5), m.end(5));
} else {
name = ""; //$NON-NLS-1$
}
this.versionString = version;
}
/**
* Creates a new version from its three integer parts with no version name.
*
* @param version The VERSION part.
* @param rev The REVISION part.
* @param build The BUILD part.
*/
public Version(int version, int rev, int build) {
this(version, rev, build, ""); //$NON-NLS-1$
}
/**
* Creates a new version from its three integer parts and the given version name.
*
* @param version The VERSION part.
* @param rev The REVISION part.
* @param build The BUILD part.
* @param name The name of this version.
* @since 0.9.1
*/
public Version(int version, int rev, int build, String name) {
this.fields = new int[] {version, rev, build};
String tmp = name == null ? "" : name; //$NON-NLS-1$
tmp = tmp.equals("") ? "" : " - " + tmp; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
this.versionString = version + "." + rev + "." + build + tmp; //$NON-NLS-1$ //$NON-NLS-2$
this.name = name;
}
/**
* Returns the value of any version field. Valid field values are: {@link #VERSION},
* {@link #REVISION} and {@link #BUILD}.
* @param field The version field.
* @return The version value for that field.
* @throws IndexOutOfBoundsException If {@code field} parameter is invalid.
*/
public int get(int field) {
if (field < VERSION || field > BUILD) {
throw new IndexOutOfBoundsException("" + field); //$NON-NLS-1$
}
return this.fields[field];
}
/**
* Returns the version name of this version. If it has no version this is the empty
* String.
*
* @return The name of this version.
* @since 0.9.1
*/
public String getName() {
return this.name;
}
/**
* Return this version as a String.
* @return A String representation for this Version.
*/
@Override
public String toString() {
return this.versionString;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(this.fields);
return result;
}
/**
* Considers {@code obj} equals to {@code this} iff all three version parts
* equals.
* @return <code>true</code> if {@code obj} is equal to {@code this}.
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Version)) {
return false;
}
Version other = (Version) obj;
if (!Arrays.equals(this.fields, other.fields)) {
return false;
}
return true;
}
/**
* Compares {@code this} to another Version. The ordering of Versions is defined as
* follows: The version with the higher value in a higher field is considered greater
* than the other. They are considered equal if all three version parts matches. The
* highest field is {@link #VERSION}, the lowest field is {@link #BUILD}.
*
* @param o The version to compare this version with.
* @return An integer representing the order of these Versions in the means of the
* Comparable contract.
*/
@Override
public int compareTo(Version o) {
for (int i = 0; i < this.fields.length; ++i) {
int diff = this.get(i) - o.get(i);
if (diff != 0) {
return diff;
}
}
return 0;
}
}