/*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at http://www.netbeans.org/cddl.html
* or http://www.netbeans.org/cddl.txt.
*
* When distributing Covered Code, include this CDDL Header Notice in each file
* and include the License file at http://www.netbeans.org/cddl.txt.
* If applicable, add the following below the CDDL Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.gwt4nb;
import java.util.Arrays;
/**
* A simple immutable container for a Version number. The main reason for this
* implementation is to simplify comparison of version numbers. The version
* number
* may be specified as an array of parts or as a version string.
*
* @author jason.morris@cocosoft.co.za
*/
public class Version implements Comparable<Version> {
/**
* The array of parts that make up the stored version number. Only
* integer parts of a
* version number will be stored.
*/
private final int[] parts;
/**
* Our cached hash-code.
*/
private int hash = 0;
/**
* @param part0 first part of the version
* @param parts other parts
*/
public Version(int part0, int... parts) {
this.parts = new int[1 + parts.length];
this.parts[0] = part0;
System.arraycopy(parts, 0, this.parts, 1, parts.length);
}
/**
* Create a new {@code Version} object with an array of numeric parts.
* The more common
* way to construct a {@code Version} object is with a
* {@link #Version(String) String}
*
* @param parts the array of numeric parts that make up the version string
* @throws IllegalArgumentException if the specified array is either null
* or empty
*/
public Version(final int[] parts) throws IllegalArgumentException {
if(parts == null || parts.length == 0) {
throw new IllegalArgumentException(
"A Version must have at least one part."); // NOI18N
}
/**
* Mac OS Note:
* Arrays.copyOf requires Java 6, on a mac do edit project properties,
* goto "libraries" and set "JDK 1.6"
* if not available, "Manage Java Platforms" -> "Add Platform"
* and browse to find a 1.6 platform (on Mac OS X 10.5.7:
* "/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home")
*/
// this.parts = Arrays.copyOf(parts, parts.length);
this.parts = new int[parts.length];
System.arraycopy(parts, 0, this.parts, 0, parts.length);
}
/**
* <p>
* Create a new {@code Version} object holding the value of the given
* {@code versionString}.
* This constructor will break the String into parts separated by any
* non-numeric characters,
* each part will then be stored internally as an integer.
* </p><p>
* Thus the string {@code "1.4.2_b24"} will tokenize to:
* </p><ol>
* <li>1</li>
* <li>4</li>
* <li>2</li>
* <li>24</li>
* </ol>
*
* @param versionString the version string to decode
*/
public Version(final String versionString) {
final String[] stringParts = versionString.split("\\D+"); // NOI18N
this.parts = new int[stringParts.length];
for(int i = 0; i < stringParts.length; i++) {
this.parts[i] = Integer.parseInt(stringParts[i]);
}
}
/**
* Converts this version to a string.
*
* @param min minimum number of parts in the version
* @param max maximum number of parts in the version
* @return version like "1.2.3"
*/
public String toString(int min, int max) {
int n = this.getPartsCount();
if (n < min)
n = min;
if (n > max)
n = max;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
if (i != 0)
sb.append('.');
sb.append(getVersionPart(i));
}
return sb.toString();
}
/**
* Fetches a single part of this {@code Version} object by it's index. This
* method will accept any non-negative index as valid. Any index larger than
* or equal to {@link #getPartsCount()} will be returned as {@literal 0}.
*
* @param index the index of the part to fetch from this {@code Version}
* @return the value of the part at the specified index
* @throws IllegalArgumentException if the index is negative
*/
public int getVersionPart(final int index) throws IllegalArgumentException {
if(index < 0) {
throw new IllegalArgumentException(
"First part in a Version is 0."); // NOI18N
}
return index < parts.length
? parts[index]
: 0; // anything after the last part is .0.0.0.0
}
/**
* The exact number of parts in this {@code Version}.
*
* @return the number of numeric parts the make up this {@code Version}
* object
*/
public int getPartsCount() {
return parts.length;
}
public int compareTo(final Version o) {
final int partsCount = Math.max(getPartsCount(), o.getPartsCount());
for(int i = 0; i < partsCount; i++) {
final int r = getVersionPart(i) - o.getVersionPart(i);
if(r != 0) {
return r;
}
}
return 0;
}
@Override
public boolean equals(final Object obj) {
if(obj == null) {
return false;
}
if(!(obj instanceof Version)) {
return false;
}
final Version other = (Version)obj;
return Arrays.equals(this.parts, other.parts);
}
@Override
public int hashCode() {
if(hash == 0) {
final int partsCount = getPartsCount();
int h = 0;
for(int i = 0; i < partsCount; i++) {
// for the most part, bits of the version will be less than 256
// if they aren't, then we may or may not loose a bit of them
// here
final int shift = 8 * (i % 4);
h ^= getVersionPart(i) << shift;
}
hash = h;
}
return hash;
}
@Override
public String toString() {
final StringBuilder out = new StringBuilder();
final int partsCount = getPartsCount();
for(int i = 0; i < partsCount; i++) {
out.append(getVersionPart(i));
if(i + 1 < partsCount) {
out.append('.');
}
}
return out.toString();
}
}