/*
 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.jfr.internal;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;

import jdk.jfr.AnnotationElement;
import jdk.jfr.Description;
import jdk.jfr.Label;
import jdk.jfr.MetadataDefinition;
import jdk.jfr.Name;
import jdk.jfr.SettingDescriptor;
import jdk.jfr.Timespan;
import jdk.jfr.Timestamp;
import jdk.jfr.ValueDescriptor;

public final class TypeLibrary {

    private static TypeLibrary instance;
    private static final Map<Long, Type> types = new LinkedHashMap<>(100);
    static final ValueDescriptor DURATION_FIELD = createDurationField();
    static final ValueDescriptor THREAD_FIELD = createThreadField();
    static final ValueDescriptor STACK_TRACE_FIELD = createStackTraceField();
    static final ValueDescriptor START_TIME_FIELD = createStartTimeField();

    private TypeLibrary(List<Type> jvmTypes) {
        visitReachable(jvmTypes, t -> !types.containsKey(t.getId()), t -> types.put(t.getId(), t));
        if (Logger.shouldLog(LogTag.JFR_SYSTEM_METADATA, LogLevel.INFO)) {
            Stream<Type> s = types.values().stream().sorted((x, y) -> Long.compare(x.getId(), y.getId()));
            s.forEach(t -> t.log("Added", LogTag.JFR_SYSTEM_METADATA, LogLevel.INFO));
        }
    }

    private static ValueDescriptor createStartTimeField() {
        List<AnnotationElement> annos = createStandardAnnotations("Start Time", null);
        annos.add(new jdk.jfr.AnnotationElement(Timestamp.class, Timestamp.TICKS));
        return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_START_TIME, Type.LONG, annos, 0, false,
                EventInstrumentation.FIELD_START_TIME);

    }

    private static ValueDescriptor createStackTraceField() {
        List<AnnotationElement> annos = new ArrayList<>();
        annos = createStandardAnnotations("Stack Trace", "Stack Trace starting from the method the event was committed in");
        return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_STACK_TRACE, Type.STACK_TRACE, annos, 0, true,
                EventInstrumentation.FIELD_STACK_TRACE);
    }

    private static ValueDescriptor createThreadField() {
        List<AnnotationElement> annos = new ArrayList<>();
        annos = createStandardAnnotations("Event Thread", "Thread in which event was committed in");
        return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_EVENT_THREAD, Type.THREAD, annos, 0, true,
                EventInstrumentation.FIELD_EVENT_THREAD);
    }

    private static ValueDescriptor createDurationField() {
        List<AnnotationElement> annos = new ArrayList<>();
        annos = createStandardAnnotations("Duration", null);
        annos.add(new jdk.jfr.AnnotationElement(Timespan.class, Timespan.TICKS));
        return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_DURATION, Type.LONG, annos, 0, false, EventInstrumentation.FIELD_DURATION);
    }

    public static TypeLibrary getInstance() {
        synchronized (TypeLibrary.class) {
            if (instance == null) {
                List<Type> jvmTypes;
                try {
                    jvmTypes = MetadataHandler.createTypes();
                    Collections.sort(jvmTypes, (a,b) -> Long.compare(a.getId(), b.getId()));
                } catch (IOException e) {
                    throw new Error("JFR: Could not read metadata");
                }
                instance = new TypeLibrary(jvmTypes);
            }
            return instance;
        }
    }

    public List<Type> getTypes() {
        return new ArrayList<>(types.values());
    }

    public static Type createAnnotationType(Class<? extends Annotation> a) {
        if (shouldPersist(a)) {
            Type type = defineType(a, Type.SUPER_TYPE_ANNOTATION, false);
            if (type != null) {
                SecuritySupport.makeVisibleToJFR(a);
                for (Method method : a.getDeclaredMethods()) {
                    type.add(PrivateAccess.getInstance().newValueDescriptor(method.getReturnType(), method.getName()));
                }
                ArrayList<AnnotationElement> aes = new ArrayList<>();
                for (Annotation annotation : resolveRepeatedAnnotations(a.getAnnotations())) {
                    AnnotationElement ae = createAnnotation(annotation);
                    if (ae != null) {
                        aes.add(ae);
                    }
                }
                aes.trimToSize();
                type.setAnnotations(aes);
            }
            return getType(a);
        }
        return null;
    }

    static AnnotationElement createAnnotation(Annotation annotation) {
        Class<? extends Annotation> annotationType = annotation.annotationType();
        Type type = createAnnotationType(annotationType);
        if (type != null) {
            List<Object> values = new ArrayList<>();
            for (ValueDescriptor v : type.getFields()) {
                values.add(invokeAnnotation(annotation, v.getName()));
            }

            return PrivateAccess.getInstance().newAnnotation(type, values, annotation.annotationType().getClassLoader() == null);
        }
        return null;
    }

    private static Object invokeAnnotation(Annotation annotation, String methodName) {
        final Method m;
        try {
            m = annotation.getClass().getMethod(methodName, new Class<?>[0]);
        } catch (NoSuchMethodException e1) {
            throw (Error) new InternalError("Could not loacate method " + methodName + " in annotation " + annotation.getClass().getName());
        }
        SecuritySupport.setAccessible(m);
        try {
            return m.invoke(annotation, new Object[0]);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw (Error) new InternalError("Could not get value for method " + methodName + " in annotation " + annotation.getClass().getName());
        }
    }

    private static boolean shouldPersist(Class<? extends Annotation> a) {
        if (a == MetadataDefinition.class || a.getAnnotation(MetadataDefinition.class) == null) {
            return false;
        }
        return true;
    }

    private static boolean isDefined(Class<?> clazz) {
        return types.containsKey(Type.getTypeId(clazz));
    }

    private static Type getType(Class<?> clazz) {
        return types.get(Type.getTypeId(clazz));
    }

    private static Type defineType(Class<?> clazz, String superType, boolean eventType) {
        if (!isDefined(clazz)) {
            Name name = clazz.getAnnotation(Name.class);
            String typeName = name != null ? name.value() : clazz.getName();
            long id = Type.getTypeId(clazz);
            Type t;
            if (eventType) {
                t = new PlatformEventType(typeName, id, clazz.getClassLoader() == null, true);
            } else {
                t = new Type(typeName, superType, id);
            }
            types.put(t.getId(), t);
            return t;
        }
        return null;
    }
    public static Type createType(Class<?> clazz) {
        return createType(clazz, Collections.emptyList(), Collections.emptyList());
    }

    public static Type createType(Class<?> clazz, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) {

        if (Thread.class == clazz) {
            return Type.THREAD;
        }

        if (Class.class.isAssignableFrom(clazz)) {
            return Type.CLASS;
        }

        if (String.class.equals(clazz)) {
            return Type.STRING;
        }

        if (isDefined(clazz)) {
            return getType(clazz);
        }

        if (clazz.isPrimitive()) {
            return defineType(clazz, null,false);
        }

        if (clazz.isArray()) {
            throw new InternalError("Arrays not supported");
        }

        // STRUCT
        String superType = null;
        boolean eventType = false;
        if (jdk.internal.event.Event.class.isAssignableFrom(clazz)) {
            superType = Type.SUPER_TYPE_EVENT;
            eventType= true;
        }
        if (Control.class.isAssignableFrom(clazz)) {
            superType = Type.SUPER_TYPE_SETTING;
        }

        // forward declare to avoid infinite recursion
        defineType(clazz, superType, eventType);
        Type type = getType(clazz);

        if (eventType) {
            addImplicitFields(type, true, true, true, true ,false);
            addUserFields(clazz, type, dynamicFields);
            type.trimFields();
        }
        addAnnotations(clazz, type, dynamicAnnotations);

        if (clazz.getClassLoader() == null) {
            type.log("Added", LogTag.JFR_SYSTEM_METADATA, LogLevel.INFO);
        } else {
            type.log("Added", LogTag.JFR_METADATA, LogLevel.INFO);
        }
        return type;
    }

    private static void addAnnotations(Class<?> clazz, Type type, List<AnnotationElement> dynamicAnnotations) {
        ArrayList<AnnotationElement> aes = new ArrayList<>();
        if (dynamicAnnotations.isEmpty()) {
            for (Annotation a : Utils.getAnnotations(clazz)) {
                AnnotationElement ae = createAnnotation(a);
                if (ae != null) {
                    aes.add(ae);
                }
            }
        } else {
            List<Type> newTypes = new ArrayList<>();
            aes.addAll(dynamicAnnotations);
            for (AnnotationElement ae : dynamicAnnotations) {
                newTypes.add(PrivateAccess.getInstance().getType(ae));
            }
            addTypes(newTypes);
        }
        type.setAnnotations(aes);
        aes.trimToSize();
    }

    private static void addUserFields(Class<?> clazz, Type type, List<ValueDescriptor> dynamicFields) {
        Map<String, ValueDescriptor> dynamicFieldSet = new HashMap<>();
        for (ValueDescriptor dynamicField : dynamicFields) {
            dynamicFieldSet.put(dynamicField.getName(), dynamicField);
        }
        List<Type> newTypes = new ArrayList<>();
        for (Field field : Utils.getVisibleEventFields(clazz)) {
            ValueDescriptor vd = dynamicFieldSet.get(field.getName());
            if (vd != null) {
                if (!vd.getTypeName().equals(field.getType().getName())) {
                    throw new InternalError("Type expected to match for field " + vd.getName() + " expected "  + field.getName() + " but got " + vd.getName());
                }
                for (AnnotationElement ae : vd.getAnnotationElements()) {
                    newTypes.add(PrivateAccess.getInstance().getType(ae));
                }
                newTypes.add(PrivateAccess.getInstance().getType(vd));
            } else {
                vd = createField(field);
            }
            if (vd != null) {
                type.add(vd);
            }
        }
        addTypes(newTypes);
    }

    // By convention all events have these fields.
    static void addImplicitFields(Type type, boolean requestable, boolean hasDuration, boolean hasThread, boolean hasStackTrace, boolean hasCutoff) {
        createAnnotationType(Timespan.class);
        createAnnotationType(Timestamp.class);
        createAnnotationType(Label.class);
        defineType(long.class, null,false);
        addFields(type, requestable, hasDuration, hasThread, hasStackTrace, hasCutoff);
    }

    private static void addFields(Type type, boolean requestable, boolean hasDuration, boolean hasThread, boolean hasStackTrace, boolean hasCutoff) {
        type.add(START_TIME_FIELD);
        if (hasDuration || hasCutoff) {
            type.add(DURATION_FIELD);
        }
        if (hasThread) {
            type.add(THREAD_FIELD);
        }
        if (hasStackTrace) {
            type.add(STACK_TRACE_FIELD);
        }
    }

    private static List<AnnotationElement> createStandardAnnotations(String name, String description) {
        List<AnnotationElement> annotationElements = new ArrayList<>(2);
        annotationElements.add(new jdk.jfr.AnnotationElement(Label.class, name));
        if (description != null) {
            annotationElements.add(new jdk.jfr.AnnotationElement(Description.class, description));
        }
        return annotationElements;
    }

    private static ValueDescriptor createField(Field field) {
        int mod = field.getModifiers();
        if (Modifier.isTransient(mod)) {
            return null;
        }
        if (Modifier.isStatic(mod)) {
            return null;
        }
        Class<?> fieldType = field.getType();
        if (!Type.isKnownType(fieldType)) {
            return null;
        }
        boolean constantPool = Thread.class == fieldType || fieldType == Class.class;
        Type type = createType(fieldType);
        String fieldName = field.getName();
        Name name = field.getAnnotation(Name.class);
        String useName = fieldName;
        if (name != null) {
            useName = name.value();
        }
        List<jdk.jfr.AnnotationElement> ans = new ArrayList<>();
        for (Annotation a : resolveRepeatedAnnotations(field.getAnnotations())) {
            AnnotationElement ae = createAnnotation(a);
            if (ae != null) {
                ans.add(ae);
            }
        }
        return PrivateAccess.getInstance().newValueDescriptor(useName, type, ans, 0, constantPool, fieldName);
    }

    private static List<Annotation> resolveRepeatedAnnotations(Annotation[] annotations) {
        List<Annotation> annos = new ArrayList<>(annotations.length);
        for (Annotation a : annotations) {
            boolean repeated = false;
            Method m;
            try {
                m = a.annotationType().getMethod("value");
                Class<?> returnType = m.getReturnType();
                if (returnType.isArray()) {
                    Class<?> ct = returnType.getComponentType();
                    if (Annotation.class.isAssignableFrom(ct) && ct.getAnnotation(Repeatable.class) != null) {
                        Object res = m.invoke(a, new Object[0]);
                        if (res != null && Annotation[].class.isAssignableFrom(res.getClass())) {
                            for (Annotation rep : (Annotation[]) m.invoke(a, new Object[0])) {
                                annos.add(rep);
                            }
                            repeated = true;
                        }
                    }
                }
            } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                // Ignore, can't access repeatable information
            }
            if (!repeated) {
                annos.add(a);
            }
        }
        return annos;
    }

    // Purpose of this method is to mark types that are reachable
    // from registered event types. Those types that are not reachable can
    // safely be removed
    public boolean clearUnregistered() {
        Logger.log(LogTag.JFR_METADATA, LogLevel.TRACE, "Cleaning out obsolete metadata");
        List<Type> registered = new ArrayList<>();
        for (Type type : types.values()) {
            if (type instanceof PlatformEventType) {
                if (((PlatformEventType) type).isRegistered()) {
                    registered.add(type);
                }
            }
        }
        visitReachable(registered, t -> t.getRemove(), t -> t.setRemove(false));
        List<Long> removeIds = new ArrayList<>();
        for (Type type :  types.values()) {
            if (type.getRemove() && !Type.isDefinedByJVM(type.getId())) {
                removeIds.add(type.getId());
                if (Logger.shouldLog(LogTag.JFR_METADATA, LogLevel.TRACE)) {
                    Logger.log(LogTag.JFR_METADATA, LogLevel.TRACE, "Removed obsolete metadata " + type.getName());
                }
            }
            // Optimization, set to true now to avoid iterating
            // types first thing at next call to clearUnregistered
            type.setRemove(true);
        }
        for (Long id : removeIds) {
            types.remove(id);
        }
        return !removeIds.isEmpty();
    }

    public void addType(Type type) {
        addTypes(Collections.singletonList(type));
    }

    public static void addTypes(List<Type> ts) {
        if (!ts.isEmpty()) {
            visitReachable(ts, t -> !types.containsKey(t.getId()), t -> types.put(t.getId(), t));
        }
    }

    /**
     * Iterates all reachable types from a start collection
     *
     * @param rootSet the types to start from
     * @param p if a type should be accepted
     * @param c action to take on an accepted type
     */
    private  static void visitReachable(Collection<Type> rootSet, Predicate<Type> p,  Consumer<Type> c) {
        Queue<Type> typeQ = new ArrayDeque<>(rootSet);
        while (!typeQ.isEmpty()) {
            Type type = typeQ.poll();
            if (p.test(type)) {
                c.accept(type);
                visitAnnotations(typeQ, type.getAnnotationElements());
                for (ValueDescriptor v : type.getFields()) {
                    typeQ.add(PrivateAccess.getInstance().getType(v));
                    visitAnnotations(typeQ, v.getAnnotationElements());
                }
                if (type instanceof PlatformEventType) {
                    PlatformEventType pe = (PlatformEventType) type;
                    for (SettingDescriptor s : pe.getAllSettings()) {
                        typeQ.add(PrivateAccess.getInstance().getType(s));
                        visitAnnotations(typeQ, s.getAnnotationElements());
                    }
                }
            }
        }
    }

    private static void visitAnnotations(Queue<Type> typeQ, List<AnnotationElement> aes) {
        Queue<AnnotationElement> aQ = new ArrayDeque<>(aes);
        Set<AnnotationElement> visited = new HashSet<>();
        while (!aQ.isEmpty()) {
            AnnotationElement ae = aQ.poll();
            if (!visited.contains(ae)) {
                Type ty = PrivateAccess.getInstance().getType(ae);
                typeQ.add(ty);
                visited.add(ae);
            }
            aQ.addAll(ae.getAnnotationElements());
        }
    }

    public void removeType(long id) {
        types.remove(id);
    }
}
