/*******************************************************************************
 * Copyright (c) 2008 Red Hat, Inc.
 * 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:
 *    Elliott Baron <ebaron@redhat.com> - initial API and implementation
 *******************************************************************************/
package org.eclipse.linuxtools.valgrind.core;

import java.io.IOException;

import org.eclipse.linuxtools.internal.valgrind.core.Messages;
import org.eclipse.osgi.util.NLS;

/**
 * Class containing convenient methods common to Valgrind
 * parsers.
 */
public final class ValgrindParserUtils {
	private static final String DOT = "."; //$NON-NLS-1$
	private static final String EMPTY_STRING = ""; //$NON-NLS-1$

	/**
	 * Retrieves ARGUMENT portion of [OPTION][DELIMITER][ARGUMENT]
	 * where ARGUMENT is a Long
	 * @param line - the line to parse
	 * @param delim - the DELIMITER to separate on
	 * @return Long value of ARGUMENT
	 * @throws IOException
	 */
	public static Long parseLongValue(String line, String delim)
	throws IOException {
		Long result = null;
		String[] parts = line.split(delim, 2);
		if (parts.length > 1 && isNumber(parts[1])) {
			result = Long.parseLong(parts[1]);
		}
		else {
			fail(line);
		}
		return result;
	}

	/**
	 * Retrieves ARGUMENT portion of [OPTION][DELIMITER][ARGUMENT]
	 * where ARGUMENT is a String
	 * @param line - the line to parse
	 * @param delim - the DELIMITER to separate fields
	 * @return String value of ARGUMENT
	 * @throws IOException
	 */
	public static String parseStrValue(String line, String delim)
	throws IOException {
		String result = null;
		String[] parts = line.split(delim, 2);
		if (parts.length > 1) {
			result = parts[1];
		}
		else {
			fail(line);
		}
		return result;
	}
	
	/**
	 * Retrieves PID from filename with format [PREFIX][PID].[EXTENSION]
	 * @param filename - the file name to parse
	 * @param prefix - the prefix of the filename up to the PID
	 * @return - the PID portion of the filename as an Integer
	 * @throws IOException
	 */
	public static Integer parsePID(String filename, String prefix) throws IOException {
		String pidstr = filename.substring(prefix.length(), filename.lastIndexOf(DOT));
		if (isNumber(pidstr)) {
			return new Integer(pidstr);
		}
		else {
			throw new IOException("Cannot parse PID from output file"); //$NON-NLS-1$
		}
	}

	/**
	 * Throws an IOException indicating parsing failed on a given line
	 * @param line - line that parsing failed
	 * @throws IOException
	 */
	public static void fail(String line) throws IOException {
		throw new IOException(NLS.bind(Messages.getString("AbstractValgrindTextParser.Parsing_output_failed"), line)); //$NON-NLS-1$
	}

	/**
	 * Determines if argument is a number
	 * @param string - argument to test
	 * @return - true if argument is a number
	 */
	public static boolean isNumber(String string) {
		boolean result = true;
		char[] chars = string.toCharArray();
		for (int i = 0; i < chars.length; i++) {
			if (!Character.isDigit(chars[i])) {
				result = false;
			}
		}
		return result;
	}

	/**
	 * Parses string ending with format ([FILE]:[LINE])
	 * Assumes syntax is: "\(.*:[0-9]+\)$"
	 * @param line - String with the above criteria
	 * @return a tuple of [String filename, Integer line] 
	 */
	public static Object[] parseFilename(String line) {
		String filename = null;
		int lineNo = 0;
	
		int ix = line.lastIndexOf("("); //$NON-NLS-1$
		if (ix >= 0) {
			String part = line.substring(ix, line.length());
			part = part.substring(1, part.length() - 1); // remove leading and trailing parentheses
			if ((ix = part.lastIndexOf(":")) >= 0) { //$NON-NLS-1$		
				String strLineNo = part.substring(ix + 1);
				if (isNumber(strLineNo)) {
					lineNo = Integer.parseInt(strLineNo);
					filename = part.substring(0, ix);
				}
			}
			else {
				// check for "in " token (lib, with symbol)
				part = part.replaceFirst("^in ", EMPTY_STRING); //$NON-NLS-1$
				// check for "within " token (lib, without symbol)
				part = part.replaceFirst("^within ", EMPTY_STRING); //$NON-NLS-1$
				filename = part; // library, no line number
			}
		}
		
		return new Object[] { filename, lineNo };
	}	

}