/*******************************************************************************
 * Copyright (c) 2004, 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.wst.jsdt.web.core.javascript;

import java.io.File;

/**
*

* Provisional API: This class/interface is part of an interim API that is still under development and expected to
* change significantly before reaching stability. It is being made available at this early stage to solicit feedback
* from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken
* (repeatedly) as the API evolves.
*/
public class JsNameManglerUtil {
	/**
	 * Determine if given string is a valid Hex representation of an ASCII
	 * character (eg. 2F -> /)
	 * 
	 * @param possible
	 * @return
	 */
	private static boolean isValid(String possible) {
		boolean result = false;
		if (possible.length() == 2) {
			char c1 = possible.charAt(0);
			char c2 = possible.charAt(1);
			// 1st character must be a digit
			if (Character.isDigit(c1)) {
				// 2nd character must be digit or upper case letter A-F
				if (Character.isDigit(c2)) {
					result = true;
				} else if (Character.isUpperCase(c2) && (c2 == 'A' || c2 == 'B' || c2 == 'C' || c2 == 'D' || c2 == 'E' || c2 == 'F')) {
					result = true;
				}
			}
		}
		return result;
	}
	
	/**
	 * Mangle string to WAS-like specifications
	 * 
	 */
	public final static String mangle(String name) {
		StringBuffer modifiedName = new StringBuffer();
		// extension (.jsp, .jspf, .jspx, etc...) should already be encoded in
		// name
		int length = name.length();
		// in case name is forbidden (a number, class, for, etc...)
		modifiedName.append('_');
		// ensure rest of characters are valid
		for (int i = 0; i < length; i++) {
			char currentChar = name.charAt(i);
			if (Character.isJavaIdentifierPart(currentChar) == true) {
				modifiedName.append(currentChar);
			} else {
				modifiedName.append(JsNameManglerUtil.mangleChar(currentChar));
			}
		}
		return modifiedName.toString();
	}
	
	/**
	 * take a character and return its hex equivalent
	 */
	private final static String mangleChar(char ch) {
		if (ch == File.separatorChar) {
			ch = '/';
		}
		if (Character.isLetterOrDigit(ch) == true) {
			return "" + ch; //$NON-NLS-1$
		}
		return "_" + Integer.toHexString(ch).toUpperCase() + "_"; //$NON-NLS-1$ //$NON-NLS-2$
	}
	
	/**
	 * WAS mangles Tom&Jerry as: _Tom_26_Jerry; this takes in the mangled name
	 * and returns the original name.
	 * 
	 * Unmangles the qualified type name. If an underscore is found it is
	 * assumed to be a mangled representation of a non-alpha, non-digit
	 * character of the form _NN_, where NN are hex digits representing the
	 * encoded character. This routine converts it back to the original
	 * character.
	 */
	public final static String unmangle(String qualifiedTypeName) {
		if (qualifiedTypeName.charAt(0) != '_') {
			return qualifiedTypeName;
		}
		StringBuffer buf = new StringBuffer();
		String possible = ""; //$NON-NLS-1$
		// remove the .java extension if there is one
		if (qualifiedTypeName.endsWith(".js")) { //$NON-NLS-1$
			qualifiedTypeName = qualifiedTypeName.substring(0, qualifiedTypeName.length() - 3);
		}
		for (int i = 1; i < qualifiedTypeName.length(); i++) { // start at
			// index 1 b/c
			// 1st char is
			// always '_'
			char c = qualifiedTypeName.charAt(i);
			if (c == '_') {
				int endIndex = qualifiedTypeName.indexOf('_', i + 1);
				if (endIndex == -1) {
					buf.append(c);
				} else {
					char unmangled;
					try {
						possible = qualifiedTypeName.substring(i + 1, endIndex);
						if (JsNameManglerUtil.isValid(possible)) {
							unmangled = (char) Integer.decode("0x" + possible).intValue();//$NON-NLS-1$
							i = endIndex;
						} else {
							unmangled = c;
						}
					} catch (NumberFormatException e) {
						unmangled = c;
					}
					buf.append(unmangled);
				}
			} else {
				buf.append(c);
			}
		}
		return buf.toString();
	}
}
