/*
 * Copyright 2008 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.dev.shell;

import com.google.gwt.dev.util.JsniRef;
import com.google.gwt.dev.util.StringInterner;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;

/**
 * Helper class for dispatching methods to Java objects. It takes methods on
 * various Java classes and assigns DISPID's to them.
 */
public class DispatchClassInfo {
  private Class<?> cls;

  private final int clsId;

  private ArrayList<Member> memberById;

  private HashMap<String, Integer> memberIdByName;

  public DispatchClassInfo(Class<?> cls, int classId) {
    this.cls = cls;
    clsId = classId;
  }

  public int getClassId() {
    return clsId;
  }

  public Member getMember(int id) {
    lazyInitTargetMembers();
    id &= 0xffff;
    return memberById.get(id);
  }

  public int getMemberId(String mangledMemberName) {
    lazyInitTargetMembers();

    Integer id = memberIdByName.get(mangledMemberName);
    if (id == null) {
      return -1;
    }

    return id.intValue();
  }

  private void addMember(
      LinkedHashMap<String, LinkedHashMap<String, Member>> members,
      Member member, String sig) {
    String fullSig = getJsniSignature(member, false);
    LinkedHashMap<String, Member> membersWithSig = members.get(sig);
    if (membersWithSig == null) {
      membersWithSig = new LinkedHashMap<String, Member>();
      members.put(sig, membersWithSig);
    }
    membersWithSig.put(fullSig, member);
  }

  private void addMemberIfUnique(String name, List<Member> membersForName) {
    if (membersForName.size() == 1) {
      memberById.add(membersForName.get(0));
      memberIdByName.put(
          StringInterner.get().intern(name), memberById.size() - 1);
    }
  }

  private List<Member> filterOutSyntheticMembers(Collection<Member> members) {
    List<Member> nonSynth = new ArrayList<Member>();
    for (Member member : members) {
      if (!member.isSynthetic()) {
        nonSynth.add(member);
      }
    }
    return nonSynth;
  }

  private LinkedHashMap<String, LinkedHashMap<String, Member>> findMostDerivedMembers(
      Class<?> targetClass, boolean addConstructors) {
    LinkedHashMap<String, LinkedHashMap<String, Member>> members = new LinkedHashMap<String, LinkedHashMap<String, Member>>();
    findMostDerivedMembers(members, targetClass, addConstructors);
    return members;
  }

  /**
   * For each available JSNI reference, find the most derived field or method
   * that matches it. For wildcard references, there will be more than one of
   * them, one for each signature matched.
   */
  private void findMostDerivedMembers(
      LinkedHashMap<String, LinkedHashMap<String, Member>> members,
      Class<?> targetClass, boolean addConstructors) {
    /*
     * Analyze superclasses and interfaces first. More derived members will thus
     * be seen later.
     */
    Class<?> superclass = targetClass.getSuperclass();
    if (superclass != null) {
      findMostDerivedMembers(members, superclass, false);
    }
    for (Class<?> intf : targetClass.getInterfaces()) {
      findMostDerivedMembers(members, intf, false);
    }

    if (addConstructors) {
      for (Constructor<?> ctor : targetClass.getDeclaredConstructors()) {
        ctor.setAccessible(true);
        addMember(members, ctor, getJsniSignature(ctor, false));
        addMember(members, ctor, getJsniSignature(ctor, true));
      }
    }

    // Get the methods on this class/interface.
    for (Method method : targetClass.getDeclaredMethods()) {
      method.setAccessible(true);
      addMember(members, method, getJsniSignature(method, false));
      addMember(members, method, getJsniSignature(method, true));
    }

    // Get the fields on this class/interface.
    Field[] fields = targetClass.getDeclaredFields();
    for (Field field : fields) {
      field.setAccessible(true);
      addMember(members, field, field.getName());
    }

    // Add a magic field to access class literals from JSNI
    addMember(members, new SyntheticClassMember(targetClass), "class");
  }

  private String getJsniSignature(Member member, boolean wildcardParamList) {
    String name;
    Class<?>[] paramTypes;

    if (member instanceof Field) {
      return member.getName();
    } else if (member instanceof SyntheticClassMember) {
      return member.getName();
    } else if (member instanceof Method) {
      name = member.getName();
      paramTypes = ((Method) member).getParameterTypes();
    } else if (member instanceof Constructor<?>) {
      name = "new";
      paramTypes = ((Constructor<?>) member).getParameterTypes();
    } else {
      throw new RuntimeException("Unexpected member type "
          + member.getClass().getName());
    }

    StringBuffer sb = new StringBuffer();
    sb.append(name);
    sb.append("(");
    if (wildcardParamList) {
      sb.append(JsniRef.WILDCARD_PARAM_LIST);
    } else {
      for (int i = 0; i < paramTypes.length; ++i) {
        Class<?> type = paramTypes[i];
        String typeSig = getTypeSig(type);
        sb.append(typeSig);
      }
    }
    sb.append(")");

    String mangledName = StringInterner.get().intern(sb.toString());
    
    return mangledName;
  }

  /*
   * TODO(jat): generics?
   */
  private String getTypeSig(Class<?> type) {
    if (type.isArray()) {
      return "[" + getTypeSig(type.getComponentType());
    }

    if (type.isPrimitive()) {
      if (type.equals(int.class)) {
        return "I";
      } else if (type.equals(boolean.class)) {
        return "Z";
      } else if (type.equals(char.class)) {
        return "C";
      } else if (type.equals(long.class)) {
        return "J";
      } else if (type.equals(short.class)) {
        return "S";
      } else if (type.equals(float.class)) {
        return "F";
      } else if (type.equals(double.class)) {
        return "D";
      } else if (type.equals(byte.class)) {
        return "B";
      } else {
        throw new RuntimeException("Unexpected primitive type: "
            + type.getName());
      }
    } else {
      StringBuffer sb = new StringBuffer();
      sb.append("L");
      sb.append(type.getName().replace('.', '/'));
      sb.append(";");
      return sb.toString();
    }
  }

  private void lazyInitTargetMembers() {
    if (memberById == null) {
      memberById = new ArrayList<Member>();
      memberById.add(null); // 0 is reserved; it's magic on Win32
      memberIdByName = new HashMap<String, Integer>();

      LinkedHashMap<String, LinkedHashMap<String, Member>> members = findMostDerivedMembers(
          cls, true);
      for (Entry<String, LinkedHashMap<String, Member>> entry : members.entrySet()) {
        String name = entry.getKey();

        List<Member> membersForName = new ArrayList<Member>(
            entry.getValue().values());
        addMemberIfUnique(name, membersForName); // backward compatibility
        addMemberIfUnique(name, filterOutSyntheticMembers(membersForName));
      }
    }
  }
}
