/*******************************************************************************
 * Copyright (c) 2000, 2008 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.swt.e4.examples.st;

import java.util.Hashtable;

/**
 * A simple fuzzy scanner for Java
 */
public class JavaScanner {

	protected Hashtable fgKeys= null;
	protected StringBuffer fBuffer= new StringBuffer();
	protected String fDoc;
	protected int fPos;
	protected int fEnd;
	protected int fStartToken;
	protected boolean fEofSeen= false;

	public static final int EOF= -1;
	public static final int EOL= 10;

	public static final int WORD=		0;
	public static final int WHITE=		1;
	public static final int KEY=			2;
	public static final int COMMENT=		3;	
	public static final int STRING=		5;
	public static final int OTHER=		6;
	public static final int NUMBER=		7;

	
	private String[] fgKeywords= { 
		"abstract",
		"boolean", "break", "byte",
		"case", "catch", "char", "class", "continue",
		"default", "do", "double",
		"else", "extends",
		"false", "final", "finally", "float", "for",
		"if", "implements", "import", "instanceof", "int", "interface",
		"long",
		"native", "new", "null",
		"package", "private", "protected", "public",
		"return",
		"short", "static", "super", "switch", "synchronized",
		"this", "throw", "throws", "transient", "true", "try",
		"void", "volatile",
		"while"
	};

	public JavaScanner() {
		initialize();
	}

	/**
	 * Returns the ending location of the current token in the document.
	 */
	public final int getLength() {
		return fPos - fStartToken;
	}

	/**
	 * Initialize the lookup table.
	 */
	void initialize() {
		fgKeys= new Hashtable();
		Integer k= new Integer(KEY);
		for (int i= 0; i < fgKeywords.length; i++)
			fgKeys.put(fgKeywords[i], k);
	}

	/**
	 * Returns the starting location of the current token in the document.
	 */
	public final int getStartOffset() {
		return fStartToken;
	}

	/**
	 * Returns the next lexical token in the document.
	 */
	public int nextToken() {
		int c;
		fStartToken= fPos;
		while (true) {
			switch (c= read()) {			
			case EOF:
				return EOF;				
			case '/':	// comment
				c= read();
				if (c == '/') {
					while (true) {
						c= read();
						if ((c == EOF) || (c == EOL)) {
							unread(c);
							return COMMENT;
						}
					}
				}
				unread(c);
				return OTHER;
			case '\'':	// char const
				while(true) {
					c= read();
					switch (c) {
						case '\'':
							return STRING;
						case EOF:
							unread(c);
							return STRING;
						case '\\':
							c= read();
							break;
						}
				}

			case '"':	// string
				while(true) {
					c= read();
					switch (c) {
						case '"':
							return STRING;
						case EOF:
							unread(c);
							return STRING;
						case '\\':
							c= read();
							break;
						}
				}

			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
				do {
					c= read();
				} while(Character.isDigit((char)c));
				unread(c);
				return NUMBER;
			default: {
				if (Character.isSpace((char)c)) {
					int z = 0;
					do {
						z= read();
					} while(Character.isSpace((char)z));
					c = z;
					unread(c);
					return WHITE;
				}
				if (Character.isJavaLetter((char)c)) {
					fBuffer.setLength(0);
					int z = c;
					do {
						fBuffer.append((char)z);
						z= read();
					} while(Character.isJavaLetterOrDigit((char)z));
					c = z;
					unread(c);
					Integer i= (Integer) fgKeys.get(fBuffer.toString());
					if (i != null) return i.intValue();
					return WORD;
				}
				return OTHER;
			}
			}//switch
		}//while(true)
	}

	/**
	 * Returns next character.
	 */
	protected int read() {
		if (fPos <= fEnd) {
			return fDoc.charAt(fPos++);
		}
		return EOF;
	}

	public void setRange(String text) {
		fDoc= text;
		fPos= 0;
		fEnd= fDoc.length() -1;
	}

	protected void unread(int c) {
		if (c != EOF)
	    	fPos--;
	}
}