package aQute.bnd.compatibility;

import java.lang.reflect.*;

public class RuntimeSignatureBuilder {
	final Scope	root;

	public RuntimeSignatureBuilder(Scope root) {
		this.root = root;
	}

	static public String identity(Class<?> c) {
		return Scope.classIdentity(c.getName());
	}

	static public String identity(Method m) {
		return Scope.methodIdentity(m.getName(), getDescriptor(m.getReturnType(), m
				.getParameterTypes()));
	}

	static public String identity(Constructor m) {
		return Scope.constructorIdentity(getDescriptor(void.class, m.getParameterTypes()));
	}

	static public String identity(Field m) {
		return Scope.fieldIdentity(m.getName(), getDescriptor(m.getType(), null));
	}

	static public String getDescriptor(Class<?> base, Class<?>[] parameters) {
		StringBuilder sb = new StringBuilder();
		if (parameters != null) {
			sb.append("(");
			for (Class<?> parameter : parameters) {
				sb.append(getDescriptor(parameter));
			}
			sb.append(")");
		}
		sb.append(getDescriptor(base));
		return sb.toString();
	}

	public Scope add(Class<?> c) {
		Scope local = add(root, getEnclosingScope(c), c.getModifiers(), c.getTypeParameters(),
				Kind.CLASS, identity(c), c.getGenericSuperclass(), c.getGenericInterfaces(), null);

		for (Field f : c.getDeclaredFields()) {
			add(local, // declaring scope
					local, // enclosing
					f.getModifiers(), // access modifiers
					null, // fields have no type vars
					Kind.FIELD, // field
					identity(f), // the name of the field
					f.getGenericType(), // the type of the field
					null, // fields have no parameters
					null // fields have no exceptions
			);
		}

		for (Constructor constr : c.getConstructors()) {
			add(local, // class scope
					local, // enclosing
					constr.getModifiers(), // access modifiers
					constr.getTypeParameters(), // Type vars
					Kind.CONSTRUCTOR, // constructor
					identity(constr), // <init>(type*)
					void.class, // Always void
					constr.getGenericParameterTypes(), // parameters types
					constr.getGenericExceptionTypes() // exception types
			);
		}

		for (Method m : c.getDeclaredMethods()) {
			if (m.getDeclaringClass() != Object.class) {
				add(local, // class scope
						local, // enclosing
						m.getModifiers(), // access modifiers
						m.getTypeParameters(), Kind.METHOD, // method
						identity(m), // <name>(type*)return
						m.getGenericReturnType(), // return type
						m.getGenericParameterTypes(), // parameter types
						m.getGenericExceptionTypes() // exception types
				);
			}
		}

		return local;
	}

	private Scope getEnclosingScope(Class<?> c) {
		Method m = c.getEnclosingMethod();
		if (m != null) {
			Scope s = getGlobalScope(m.getDeclaringClass());
			return s.getScope(identity(m));
		}
// TODO
//		Constructor cnstr = c.getEnclosingConstructor();
//		if (m != null) {
//			Scope s = getGlobalScope(cnstr.getDeclaringClass());
//			return s.getScope(identity(cnstr));
//
//		}
		Class<?> enclosingClass = c.getEnclosingClass();
		if (enclosingClass != null) {
			return getGlobalScope(enclosingClass);
		}

		return null;
	}

	private Scope getGlobalScope(Class<?> c) {
		if (c == null)
			return null;
		String id = identity(c);
		return root.getScope(id);
	}

	private Scope add(Scope declaring, Scope enclosing, int modifiers,
			TypeVariable<?>[] typeVariables, Kind kind, String id, Type mainType,
			Type[] parameterTypes, Type exceptionTypes[]) {

		Scope scope = declaring.getScope(id);
		assert scope.access == Access.UNKNOWN;
		scope.setAccess(Access.modifier(modifiers));
		scope.setKind(kind);
		scope.setGenericParameter(convert(typeVariables));
		scope.setBase(convert(scope,mainType));
		scope.setParameterTypes(convert(parameterTypes));
		scope.setExceptionTypes(convert(exceptionTypes));
		scope.setDeclaring(declaring);
		scope.setEnclosing(enclosing);
		return scope;
	}

	private GenericType convert(Scope source, Type t) {
		if (t instanceof ParameterizedType) {
			// C<P..>
			ParameterizedType pt = (ParameterizedType) t;
			/*Scope reference =*/ root.getScope(identity((Class<?>)pt.getRawType()));			
			Type args[] = pt.getActualTypeArguments();
			GenericType[] arguments = new GenericType[args.length];
			int n = 0;
			for (Type arg : args)
				arguments[n++] = convert(source,arg);
//			return new GenericType(reference,null,arguments);
			
		} else if (t instanceof TypeVariable) {
//			TypeVariable tv = (TypeVariable) t;
//			return new GenericType(source,tv.getName(), null);
		} else if (t instanceof WildcardType) {
//			WildcardType wc = (WildcardType) t;
//			wc.
		} else if (t instanceof GenericArrayType) {

		}
		if (t instanceof Class<?>) {
//			raw = ((Class<?>) t).getName() + ";";
		} else
			throw new IllegalArgumentException(t.toString());

		return null;
	}

	private GenericParameter[] convert(TypeVariable vars[]) {
		if (vars == null)
			return null;

		GenericParameter out[] = new GenericParameter[vars.length];
		for (int i = 0; i < vars.length; i++) {
			GenericType gss[] = convert(vars[i].getBounds());
			out[i] = new GenericParameter(vars[i].getName(), gss);
		}
		return out;
	}

	private GenericType[] convert(Type[] parameterTypes) {
		if (parameterTypes == null || parameterTypes.length == 0)
			return GenericType.EMPTY;

		GenericType tss[] = new GenericType[parameterTypes.length];
		for (int i = 0; i < parameterTypes.length; i++) {
			//tss[i] = new GenericType(parameterTypes[i]);
		}
		return tss;
	}

	private static String getDescriptor(Class<?> c) {
		StringBuilder sb = new StringBuilder();
		if (c.isPrimitive()) {
			if (c == boolean.class)
				sb.append("Z");
			else if (c == byte.class)
				sb.append("Z");
			else if (c == char.class)
				sb.append("C");
			else if (c == short.class)
				sb.append("S");
			else if (c == int.class)
				sb.append("I");
			else if (c == long.class)
				sb.append("J");
			else if (c == float.class)
				sb.append("F");
			else if (c == double.class)
				sb.append("D");
			else if (c == void.class)
				sb.append("V");
			else
				throw new IllegalArgumentException("unknown primitive type: " + c);
		} else if (c.isArray()) {
			sb.append("[");
			sb.append(getDescriptor(c));
		} else {
			sb.append("L");
			sb.append(c.getName().replace('.', '/'));
			sb.append(";");
		}
		return sb.toString();
	}

}
