/*
 * Created on 29.06.2004
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 */
package networkconsole.datamodel;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;

/**
 * @author Eugene Prokopiev <eugene_prokopiev@mail.ru>
 * 
 */
public class LdapEntryReflector {
	
	private Class entryClass;	
	
	private ArrayList describeMethods = new ArrayList();
	private ArrayList getterMethods = new ArrayList();
	private ArrayList setterMethods = new ArrayList();
	
	public LdapEntryReflector(Class entryClass){			
		readMethods(entryClass);	
	}
	
	private void readMethods(Class entryClass) {
		
		this.entryClass = entryClass;	
		
		Method methods[] = entryClass.getMethods();
		Arrays.sort(methods, new MethodsComparator());
		
		for(int i = 0; i < methods.length; i++) {
			String describeMethodName = methods[i].getName();
			if (describeMethodName.startsWith("describe")) {
				describeMethods.add(describeMethodName);
				String methodName = describeMethodName.substring(10);
				if (Arrays.binarySearch(methods, "is"+methodName, new Methods2StringComparator()) >= 0)
					getterMethods.add("is"+methodName);
				else if (Arrays.binarySearch(methods, "get"+methodName, new Methods2StringComparator()) >= 0)
					getterMethods.add("get"+methodName);
				else
					getterMethods.add(null);
				if (Arrays.binarySearch(methods, "set"+methodName, new Methods2StringComparator()) >= 0)
					setterMethods.add("set"+methodName);
				else
					setterMethods.add(null);
			}
		}	
	}
	
	public String invokeMethod(LdapEntry entry, String methodName) throws IOException {
		try {
			if (entry != null) {
				Object result = entryClass.getMethod(methodName, null).invoke(entry, null);
				if (result != null)
					return result.toString();
				else
					return "null";
			} else {
				Object result = entryClass.getMethod(methodName, null).invoke(entryClass, null).toString();
				if (result != null)
					return result.toString();
				else
					return "null";
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new IOException("Invoking method "+methodName+" failed");
		}		
	}
	
	public void invokeMethod(LdapEntry entry, String methodName, Object param) throws IOException {
		try {
			if (entry != null) {
				entryClass.getMethod(methodName, new Class[] {param.getClass()} ).invoke(entry, new Object[] {param});
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new IOException("Invoking method "+methodName+" failed");
		}		
	}
	
	public ArrayList getDescribeMethods() {
		return describeMethods;
	}

	public ArrayList getGetterMethods() {
		return getterMethods;
	}

	public ArrayList getSetterMethods() {
		return setterMethods;
	}
	
	public String asString() {
		
		String result = "";
		
		result += "describe methods:\n";
		Iterator methodsIterator = describeMethods.iterator();
		while (methodsIterator.hasNext()) {	
			result += ("\t"+methodsIterator.next().toString()+"\n");
		}
		
		return result;
	}
	
	private class MethodsComparator implements Comparator {
		public int compare(Object o1, Object o2) {
			return ((Method)o1).getName().compareTo(((Method)o2).getName());
		}
	}
		
	private class Methods2StringComparator implements Comparator {
		public int compare(Object o1, Object o2) {
			return ((Method)o1).getName().compareTo(o2.toString());
		}
	}

}
