// Path: stag-library-compiler/src/main/java/com/vimeo/stag/processor/utils/logging/DebugLog.java
// public final class DebugLog {
// 
//     private static final String TAG = "Stag";
//     @Nullable
//     private static Logger sLogger;
// 
//     private DebugLog() {
//         throw new UnsupportedOperationException("This class is not instantiable");
//     }
// 
//     /**
//      * Initialize the log utils with the logging instance.
//      *
//      * @param logger the logging instance, if null is provided, logging will result in a crash.
//      */
//     public static void initialize(@Nullable Logger logger) {
//         sLogger = logger;
//     }
// 
//     @NotNull
//     private static Logger safeLogger() {
//         if (sLogger == null) {
//             throw new IllegalStateException("initialize must be called first");
//         }
//         return sLogger;
//     }
// 
//     /**
//      * Log the provided message with the default log tag "Stag"
//      *
//      * @param message the message to log.
//      */
//     public static void log(@Nullable CharSequence message) {
//         safeLogger().log(TAG + ": " + message);
//     }
// 
//     /**
//      * Log the provided message with an additional log tag.
//      *
//      * @param tag     the tag to add to the log.
//      * @param message the message to log.
//      */
//     public static void log(@NotNull CharSequence tag, @Nullable CharSequence message) {
//         safeLogger().log(TAG + ":" + tag + ": " + message);
//     }
// 
// }


import com.google.gson.JsonDeserializer;
import com.google.gson.JsonSerializer;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.vimeo.stag.processor.generators.model.accessor.FieldAccessor;
import com.vimeo.stag.processor.utils.logging.DebugLog;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Types;
     * VideoFactory extends {@literal Factory<Video>}{
     *
     *   // other variables in here
     *
     * }
     * </code></pre>
     * In this example, VideoFactory has a public member variable T that is of type Video.
     * Since the Factory class has the UseStag annotation, we cannot just generate
     * parsing code for the Factory class, since it is generic and we need concrete types.
     * Instead when we generate the adapter for VideoFactory, we crawl the inheritance
     * hierarchy gathering the member variables. When we get to VideoFactory, we see it
     * has one member variable, T. We then look at the inherited type, Factory{@literal <Video>},
     * and compare it to the original type, Factory{@literal <T>}, and then infer the type
     * of T to be Video.
     *
     * @param concreteInherited the type inherited for the class you are using, in the example,
     *                          this would be Factory{@literal <Video>}
     * @param genericInherited  the raw type inherited for the class you are using, in the example,
     *                          this would be Factory{@literal <T>}
     * @param members           the member variable map of the field (Element) to their concrete
     *                          type (TypeMirror). This should be retrieved by calling getConcreteMembers
     *                          on the inherited class.
     * @return returns a LinkedHashMap of the member variables mapped to their concrete types for the concrete
     * inherited class. (to maintain the ordering)
     */
    @NotNull
    public static LinkedHashMap<FieldAccessor, TypeMirror> getConcreteMembers(@NotNull TypeMirror concreteInherited,
                                                                              @NotNull TypeElement genericInherited,
                                                                              @NotNull Map<FieldAccessor, TypeMirror> members) {

// Path: stag-library-compiler/src/main/java/com/vimeo/stag/processor/utils/logging/DebugLog.java
// public final class DebugLog {
// 
//     private static final String TAG = "Stag";
//     @Nullable
//     private static Logger sLogger;
// 
//     private DebugLog() {
//         throw new UnsupportedOperationException("This class is not instantiable");
//     }
// 
//     /**
//      * Initialize the log utils with the logging instance.
//      *
//      * @param logger the logging instance, if null is provided, logging will result in a crash.
//      */
//     public static void initialize(@Nullable Logger logger) {
//         sLogger = logger;
//     }
// 
//     @NotNull
//     private static Logger safeLogger() {
//         if (sLogger == null) {
//             throw new IllegalStateException("initialize must be called first");
//         }
//         return sLogger;
//     }
// 
//     /**
//      * Log the provided message with the default log tag "Stag"
//      *
//      * @param message the message to log.
//      */
//     public static void log(@Nullable CharSequence message) {
//         safeLogger().log(TAG + ": " + message);
//     }
// 
//     /**
//      * Log the provided message with an additional log tag.
//      *
//      * @param tag     the tag to add to the log.
//      * @param message the message to log.
//      */
//     public static void log(@NotNull CharSequence tag, @Nullable CharSequence message) {
//         safeLogger().log(TAG + ":" + tag + ": " + message);
//     }
// 
// }


// Path: stag-library-compiler/src/main/java/com/vimeo/stag/processor/utils/TypeUtils.java
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonSerializer;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.vimeo.stag.processor.generators.model.accessor.FieldAccessor;
import com.vimeo.stag.processor.utils.logging.DebugLog;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Types;

     * VideoFactory extends {@literal Factory<Video>}{
     *
     *   // other variables in here
     *
     * }
     * </code></pre>
     * In this example, VideoFactory has a public member variable T that is of type Video.
     * Since the Factory class has the UseStag annotation, we cannot just generate
     * parsing code for the Factory class, since it is generic and we need concrete types.
     * Instead when we generate the adapter for VideoFactory, we crawl the inheritance
     * hierarchy gathering the member variables. When we get to VideoFactory, we see it
     * has one member variable, T. We then look at the inherited type, Factory{@literal <Video>},
     * and compare it to the original type, Factory{@literal <T>}, and then infer the type
     * of T to be Video.
     *
     * @param concreteInherited the type inherited for the class you are using, in the example,
     *                          this would be Factory{@literal <Video>}
     * @param genericInherited  the raw type inherited for the class you are using, in the example,
     *                          this would be Factory{@literal <T>}
     * @param members           the member variable map of the field (Element) to their concrete
     *                          type (TypeMirror). This should be retrieved by calling getConcreteMembers
     *                          on the inherited class.
     * @return returns a LinkedHashMap of the member variables mapped to their concrete types for the concrete
     * inherited class. (to maintain the ordering)
     */
    @NotNull
    public static LinkedHashMap<FieldAccessor, TypeMirror> getConcreteMembers(@NotNull TypeMirror concreteInherited,
                                                                              @NotNull TypeElement genericInherited,
                                                                              @NotNull Map<FieldAccessor, TypeMirror> members) {

        DebugLog.log(TAG, "Inherited concrete type: " + concreteInherited.toString());