/*******************************************************************************
 * Copyright (c) 2004, 2013 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.swt.tools.internal;

import java.lang.reflect.Modifier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LockGenerator extends CleanupClass {
	
public LockGenerator() {
}

String getParams(JNIMethod method) {
	int n_args = method.getParameters().length;
	if (n_args == 0) return "";
	String name = method.getName();
	String params = "";
	int index = 0;
	while (true) {
		index = classSource.indexOf(name, index + 1);
		if (!Character.isWhitespace(classSource.charAt(index - 1))) continue;
		if (index == -1) return null;
		int parantesesStart = classSource.indexOf("(", index);
		if (classSource.substring(index + name.length(), parantesesStart).trim().length() == 0) {
			int parantesesEnd = classSource.indexOf(")", parantesesStart);
 			params = classSource.substring(parantesesStart + 1, parantesesEnd);
 			break;
		}
	}
	return params;
}

String getReturn(JNIMethod method) {
	JNIType returnType = method.getReturnType();
	if (!returnType.isType("int")) return returnType.getTypeSignature3(false);
	String modifierStr = Modifier.toString(method.getModifiers());
	String name = method.getName();
	Pattern p = Pattern.compile(modifierStr + ".*" + name + ".*(.*)");
	Matcher m = p.matcher(classSource);
	if (m.find()) {
		String methodStr = classSource.substring(m.start(), m.end());
		int index = methodStr.indexOf("/*long*/");
		if (index != -1 && index < methodStr.indexOf(name)) {
			return new ReflectType(Integer.TYPE).getTypeSignature3(false) + " /*long*/";
		}		
	}
	return new ReflectType(Integer.TYPE).getTypeSignature3(false);
}

@Override
public void generate(JNIClass clazz) {
	super.generate(clazz);
	JNIMethod[] methods = clazz.getDeclaredMethods();
	generate(methods);
}

public void generate(JNIMethod[] methods) {
	sort(methods);	
	for (int i = 0; i < methods.length; i++) {
		JNIMethod method = methods[i];
		if ((method.getModifiers() & Modifier.NATIVE) == 0) continue;
		generate(method);
	}
}

public void generate(JNIMethod method) {
	int modifiers = method.getModifiers();
	boolean lock = (modifiers & Modifier.SYNCHRONIZED) != 0;
	String returnStr = getReturn(method);
	String paramsStr = getParams(method);
	if (lock) {
		String modifiersStr = Modifier.toString(modifiers & ~Modifier.SYNCHRONIZED);
		output(modifiersStr);
		if (modifiersStr.length() > 0) output(" ");
		output(returnStr);
		output(" _");
		output(method.getName());
		output("(");
		output(paramsStr);
		outputln(");");
	}
	String modifiersStr = Modifier.toString(modifiers & ~(Modifier.SYNCHRONIZED | (lock ? Modifier.NATIVE : 0)));
	output(modifiersStr);
	if (modifiersStr.length() > 0) output(" ");
	output(returnStr);
	output(" ");
	output(method.getName());
	output("(");
	output(paramsStr);
	output(")");
	if (lock) {
		outputln(" {");
		outputln("\tlock.lock();");
		outputln("\ttry {");
		output("\t\t");
		if (!method.getReturnType().isType("void")) {
			output("return ");
		}
		output("_");
		output(method.getName());
		output("(");
		String[] paramNames = getArgNames(method);
		for (int i = 0; i < paramNames.length; i++) {
			if (i != 0) output(", ");
			output(paramNames[i]);
		}
		outputln(");");
		outputln("\t} finally {");
		outputln("\t\tlock.unlock();");
		outputln("\t}");
		outputln("}");
	} else {
		outputln(";");
	}
}

public static void main(String[] args) {
	if (args.length < 2) {
		System.out.println("Usage: java LockGenerator <OS className> <OS class source>");
		return;
	}
	try {
		LockGenerator gen = new LockGenerator();
		String clazzName = args[0];
		String classSource = args[1]; 
		Class<?> clazz = Class.forName(clazzName);
		gen.setClassSourcePath(classSource);
		gen.generate(new ReflectClass(clazz));
	} catch (Exception e) {
		System.out.println("Problem");
		e.printStackTrace(System.out);
	}
}

}
