/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.hadoop.classification.tools;

import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.AnnotationTypeDoc;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ConstructorDoc;
import com.sun.javadoc.Doc;
import com.sun.javadoc.FieldDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.ProgramElementDoc;
import com.sun.javadoc.RootDoc;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;

/**
 * Process the {@link RootDoc} by substituting with (nested) proxy objects that
 * exclude elements with Private or LimitedPrivate annotations.
 * <p>
 * Based on code from http://www.sixlegs.com/blog/java/exclude-javadoc-tag.html.
 */
class RootDocProcessor {

  static String stability = StabilityOptions.UNSTABLE_OPTION;
  static boolean treatUnannotatedClassesAsPrivate = false;

  public static RootDoc process(RootDoc root) {
    return (RootDoc) process(root, RootDoc.class);
  }

  private static Object process(Object obj, Class<?> type) {
    if (obj == null) {
      return null;
    }
    Class<?> cls = obj.getClass();
    if (cls.getName().startsWith("com.sun.")) {
      return getProxy(obj);
    } else if (obj instanceof Object[]) {
      Class<?> componentType = type.isArray() ? type.getComponentType()
          : cls.getComponentType();
      Object[] array = (Object[]) obj;
      Object[] newArray = (Object[]) Array.newInstance(componentType,
          array.length);
      for (int i = 0; i < array.length; ++i) {
        newArray[i] = process(array[i], componentType);
      }
      return newArray;
    }
    return obj;
  }

  private static Map<Object, Object> proxies =
    new WeakHashMap<Object, Object>();

  private static Object getProxy(Object obj) {
    Object proxy = proxies.get(obj);
    if (proxy == null) {
      proxy = Proxy.newProxyInstance(obj.getClass().getClassLoader(),
        obj.getClass().getInterfaces(), new ExcludeHandler(obj));
      proxies.put(obj, proxy);
    }
    return proxy;
  }

  private static class ExcludeHandler implements InvocationHandler {
    private Object target;

    public ExcludeHandler(Object target) {
      this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
      String methodName = method.getName();
      if (target instanceof Doc) {
        if (methodName.equals("isIncluded")) {
          Doc doc = (Doc) target;
          return !exclude(doc) && doc.isIncluded();
        }
        if (target instanceof RootDoc) {
          if (methodName.equals("classes")) {
            return filter(((RootDoc) target).classes(), ClassDoc.class);
          } else if (methodName.equals("specifiedClasses")) {
            return filter(((RootDoc) target).specifiedClasses(), ClassDoc.class);
          } else if (methodName.equals("specifiedPackages")) {
            return filter(((RootDoc) target).specifiedPackages(), PackageDoc.class);
          }
        } else if (target instanceof ClassDoc) {
          if (isFiltered(args)) {
            if (methodName.equals("methods")) {
              return filter(((ClassDoc) target).methods(true), MethodDoc.class);
            } else if (methodName.equals("fields")) {
              return filter(((ClassDoc) target).fields(true), FieldDoc.class);
            } else if (methodName.equals("innerClasses")) {
              return filter(((ClassDoc) target).innerClasses(true),
                  ClassDoc.class);
            } else if (methodName.equals("constructors")) {
              return filter(((ClassDoc) target).constructors(true),
                  ConstructorDoc.class);
            }
          } else {
            if (methodName.equals("methods")) {
              return filter(((ClassDoc) target).methods(true), MethodDoc.class);
            }
          }
        } else if (target instanceof PackageDoc) {
          if (methodName.equals("allClasses")) {
            if (isFiltered(args)) {
              return filter(((PackageDoc) target).allClasses(true),
                  ClassDoc.class);
            } else {
              return filter(((PackageDoc) target).allClasses(), ClassDoc.class);
            }
          } else if (methodName.equals("annotationTypes")) {
            return filter(((PackageDoc) target).annotationTypes(),
                AnnotationTypeDoc.class);
          } else if (methodName.equals("enums")) {
            return filter(((PackageDoc) target).enums(),
                ClassDoc.class);
          } else if (methodName.equals("errors")) {
            return filter(((PackageDoc) target).errors(),
                ClassDoc.class);
          } else if (methodName.equals("exceptions")) {
            return filter(((PackageDoc) target).exceptions(),
                ClassDoc.class);
          } else if (methodName.equals("interfaces")) {
            return filter(((PackageDoc) target).interfaces(),
                ClassDoc.class);
          } else if (methodName.equals("ordinaryClasses")) {
            return filter(((PackageDoc) target).ordinaryClasses(),
                ClassDoc.class);
          }
        }
      }

      if (args != null) {
        if (methodName.equals("compareTo") || methodName.equals("equals")
            || methodName.equals("overrides")
            || methodName.equals("subclassOf")) {
          args[0] = unwrap(args[0]);
        }
      }
      try {
        return process(method.invoke(target, args), method.getReturnType());
      } catch (InvocationTargetException e) {
        throw e.getTargetException();
      }
    }

    private static boolean exclude(Doc doc) {
      AnnotationDesc[] annotations = null;
      if (doc instanceof ProgramElementDoc) {
        annotations = ((ProgramElementDoc) doc).annotations();
      } else if (doc instanceof PackageDoc) {
        annotations = ((PackageDoc) doc).annotations();
      }
      if (annotations != null) {
        for (AnnotationDesc annotation : annotations) {
          String qualifiedTypeName = annotation.annotationType().qualifiedTypeName();
          if (qualifiedTypeName.equals(
              InterfaceAudience.Private.class.getCanonicalName())
              || qualifiedTypeName.equals(
              InterfaceAudience.LimitedPrivate.class.getCanonicalName())) {
            return true;
          }
          if (stability.equals(StabilityOptions.EVOLVING_OPTION)) {
            if (qualifiedTypeName.equals(
                InterfaceStability.Unstable.class.getCanonicalName())) {
              return true;
            }
          }
          if (stability.equals(StabilityOptions.STABLE_OPTION)) {
            if (qualifiedTypeName.equals(
                InterfaceStability.Unstable.class.getCanonicalName())
                || qualifiedTypeName.equals(
                InterfaceStability.Evolving.class.getCanonicalName())) {
              return true;
            }
          }
        }
        for (AnnotationDesc annotation : annotations) {
          String qualifiedTypeName =
              annotation.annotationType().qualifiedTypeName();
          if (qualifiedTypeName.equals(
              InterfaceAudience.Public.class.getCanonicalName())) {
            return false;
          }
        }
      }
      if (treatUnannotatedClassesAsPrivate) {
        return doc.isClass() || doc.isInterface() || doc.isAnnotationType();
      }
      return false;
    }

    private static Object[] filter(Doc[] array, Class<?> componentType) {
      if (array == null || array.length == 0) {
        return array;
      }
      List<Object> list = new ArrayList<Object>(array.length);
      for (Doc entry : array) {
        if (!exclude(entry)) {
          list.add(process(entry, componentType));
        }
      }
      return list.toArray((Object[]) Array.newInstance(componentType, list
          .size()));
    }

    private Object unwrap(Object proxy) {
      if (proxy instanceof Proxy)
        return ((ExcludeHandler) Proxy.getInvocationHandler(proxy)).target;
      return proxy;
    }

    private boolean isFiltered(Object[] args) {
      return args != null && Boolean.TRUE.equals(args[0]);
    }

  }

}
