/* Utils.java

	Purpose:
		
	Description:
		
	History:
		Wed Jul 11 14:47:08     2007, Created by tomyeh

Copyright (C) 2007 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
	This program is distributed under LGPL Version 2.1 in the hope that
	it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.util;

import java.util.List;
import java.util.LinkedList;

/**
 * Generic utilities.
 *
 * @author tomyeh
 * @since 3.0.0
 */
public class Utils {
	/** Returns a portion of the specified version in an integer,
	 * or 0 if no such portion exists.
	 *
	 * <p>For example, getSubversion(0) returns the so-called major version
	 * (2 in "2.4.0"), and getSubversion(1) returns the so-called
	 * minor version (4 in "2.4.0").
	 *
	 * <p>Note: alpha is consider as -500, beta -300, and rc -100.
	 * Moreover, beta3 is -497 (= -500 + 3) and rc5 -95 (-100 + 5)
	 *
	 * @param version the version. The version is assumed to
	 * a series of integer separated by a non-alphanumeric separator.
	 * @param portion which portion of the version; starting from 0.
	 * If you want to retrieve the major version, specify 0.
	 * @since 3.0.0
	 */
	public static final int getSubversion(String version, int portion) {
		if (portion < 0)
			throw new IllegalArgumentException("Negative not allowed: "+portion);

		final int len = version.length();
		int j = 0;
		while (--portion >= 0) {
			j = nextVerSeparator(version, j) + 1;
			if (j >= len) return 0; //no such portion
		}

		return convertSubversion(
			version.substring(j, nextVerSeparator(version, j)));
	}
	/** Parses the specified version into an array of integer.
	 * For example, parseVersion("3.5.2") will return [3, 5, 2].
	 * @since 3.5.2
	 */
	public static final int[] parseVersion(String version) {
		final List<Integer> vers = new LinkedList<Integer>();
		for (int j = 0, len = version.length(); j < len;) {
			int k = nextVerSeparator(version, j);
			vers.add(new Integer(convertSubversion(version.substring(j, k))));
			j = k + 1;
		}

		final int[] ivs = new int[vers.size()];
		int j = 0;
		for (Integer ver: vers)
			ivs[j++] = ver.intValue();
		return ivs;
	}
	/** Compares two version.
	 * @return 0 if equals, 1 if the first one is larger, -1 if smaller.
	 * @since 3.5.2
	 */
	public static final int compareVersion(int[] v1, int[] v2) {
		for (int j = 0;; ++j) {
			if (j == v1.length) {
				for (; j < v2.length; ++j) {
					if (v2[j] > 0) return -1;
					if (v2[j] < 0) return 1;
				}
				return 0;
			}
			if (j == v2.length) {
				for (; j < v1.length; ++j) {
					if (v1[j] > 0) return 1;
					if (v1[j] < 0) return -1;
				}
				return 0;
			}
			if (v1[j] > v2[j]) return 1;
			if (v1[j] < v2[j]) return -1;
		}
	}
	private static final int convertSubversion(String subver) {
		try {
			return Integer.parseInt(subver);
		} catch (Throwable ex) { //eat
		}

		subver = subver.toLowerCase(java.util.Locale.ENGLISH);
		final int base, j;
		if (subver.startsWith("rc")) {
			base = -100;
			j = 2;
		} else if (subver.startsWith("beta")) {
			base = -300;
			j = 4;
		} else if (subver.startsWith("alpha")) {
			base = -500;
			j = 5;
		} else {
			return 0; //unknown
		}
		if (j < subver.length()) {
			try {
				return base + Integer.parseInt(subver.substring(j));
			} catch (Throwable ex) { //eat
			}
		}
		return base;
	}
	private static final int nextVerSeparator(String version, int from) {
		for (final int len = version.length(); from < len; ++from) {
			final char cc = version.charAt(from);
			if ((cc < '0' || cc > '9') && (cc < 'a' || cc > 'z')
			&& (cc < 'A' || cc > 'Z'))
				break;
		}
		return from;
	}
}
