// Path: stag-library-compiler/src/main/java/com/vimeo/stag/processor/utils/FileGenUtils.java
// public final class FileGenUtils {
// 
//     private static final String CODE_BLOCK_ESCAPED_SEPARATOR = "$$";
//     private static final String UNESCAPED_SEPARATOR = "$";
// 
//     private FileGenUtils() {
//         throw new UnsupportedOperationException("This class is not instantiable");
//     }
// 
//     /**
//      * Writes a Java file to the file system after
//      * deleting the previous copy.
//      *
//      * @param file  the file to write.
//      * @param filer the Filer to use to do the writing.
//      * @throws IOException throws an exception if we are unable
//      *                     to write the file to the filesystem.
//      */
//     public static void writeToFile(@NotNull JavaFile file, @NotNull Filer filer) throws IOException {
//         String fileName =
//                 file.packageName.isEmpty() ? file.typeSpec.name : file.packageName + '.' + file.typeSpec.name;
//         List<Element> originatingElements = file.typeSpec.originatingElements;
//         JavaFileObject filerSourceFile = filer.createSourceFile(fileName, originatingElements.toArray(
//                 new Element[originatingElements.size()]));
//         filerSourceFile.delete();
//         Writer writer = null;
//         try {
//             writer = filerSourceFile.openWriter();
//             file.writeTo(writer);
//         } catch (Exception e) {
//             try {
//                 filerSourceFile.delete();
//             } catch (Exception ignored) {
//             }
//             throw e;
//         } finally {
//             close(writer);
//         }
//     }
// 
//     @Nullable
//     static CharSequence readResource(@NotNull Filer filer, @NotNull String generatedPackageName,
//                                      @NotNull String resourceName) throws IOException {
//         try {
//             FileObject file =
//                     filer.getResource(StandardLocation.CLASS_OUTPUT, generatedPackageName, resourceName);
//             return file.getCharContent(false);
//         } catch (FileNotFoundException e) {
//             DebugLog.log("Resource not found: " + resourceName);
//             return null;
//         }
//     }
// 
//     static void writeToResource(@NotNull Filer filer, @NotNull String generatedPackageName,
//                                 @NotNull String resourceName, @NotNull CharSequence content)
//             throws IOException {
//         FileObject file =
//                 filer.createResource(StandardLocation.CLASS_OUTPUT, generatedPackageName, resourceName);
//         file.delete();
//         Writer writer = null;
//         try {
//             writer = file.openWriter();
//             writer.append(content);
//             DebugLog.log("Wrote to resource '" + resourceName + "':\n" + content);
//         } catch (Exception e) {
//             try {
//                 file.delete();
//             } catch (Exception ignored) {
//             }
//             throw e;
//         } finally {
//             close(writer);
//         }
//     }
// 
//     /**
//      * Safely closes a closeable.
//      *
//      * @param closeable object to close.
//      */
//     static void close(@Nullable Closeable closeable) {
//         if (closeable == null) {
//             return;
//         }
//         try {
//             closeable.close();
//         } catch (IOException e) {
//             // ignored
//         }
//     }
// 
//     /**
//      * Takes a String input and escapes it for use
//      * in the {@link CodeBlock} class.
//      *
//      * @param string the string to escape.
//      * @return a String safe to use in a {@link CodeBlock}
//      */
//     @NotNull
//     public static String escapeStringForCodeBlock(@NotNull String string) {
//         return string.replace(UNESCAPED_SEPARATOR, CODE_BLOCK_ESCAPED_SEPARATOR);
//     }
// 
//     /**
//      * Takes a String input that was escaped for
//      * use in the {@link CodeBlock} class and
//      * unescapes it for normal use.
//      *
//      * @param string the String to unescape,
//      * @return a String safe for normal use.
//      */
//     @NotNull
//     public static String unescapeEscapedString(@NotNull String string) {
//         return string.replace(CODE_BLOCK_ESCAPED_SEPARATOR, UNESCAPED_SEPARATOR);
//     }
// }


import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import com.vimeo.stag.processor.generators.model.ClassInfo;
import com.vimeo.stag.processor.utils.FileGenUtils;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
                .addParameter(JsonReader.class, "reader")
                .returns(typeName)
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Override.class)
                .addException(IOException.class)
                .beginControlFlow("if (reader.peek() == com.google.gson.stream.JsonToken.NULL)")
                .addStatement("reader.nextNull()")
                .addStatement("return null")
                .endControlFlow()
                .addStatement("return NAME_TO_CONSTANT.get(reader.nextString())")
                .build();
    }

    /**
     * Generates the TypeSpec for the TypeAdapter
     * that this enum generates.
     *
     * @return a valid TypeSpec that can be written
     * to a file or added to another class.
     */
    @Override
    @NotNull
    public TypeSpec createTypeAdapterSpec(@NotNull StagGenerator stagGenerator) {
        TypeMirror typeMirror = mInfo.getType();
        TypeName typeVariableName = TypeVariableName.get(typeMirror);

        MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC)
                .addParameter(Gson.class, "gson");

// Path: stag-library-compiler/src/main/java/com/vimeo/stag/processor/utils/FileGenUtils.java
// public final class FileGenUtils {
// 
//     private static final String CODE_BLOCK_ESCAPED_SEPARATOR = "$$";
//     private static final String UNESCAPED_SEPARATOR = "$";
// 
//     private FileGenUtils() {
//         throw new UnsupportedOperationException("This class is not instantiable");
//     }
// 
//     /**
//      * Writes a Java file to the file system after
//      * deleting the previous copy.
//      *
//      * @param file  the file to write.
//      * @param filer the Filer to use to do the writing.
//      * @throws IOException throws an exception if we are unable
//      *                     to write the file to the filesystem.
//      */
//     public static void writeToFile(@NotNull JavaFile file, @NotNull Filer filer) throws IOException {
//         String fileName =
//                 file.packageName.isEmpty() ? file.typeSpec.name : file.packageName + '.' + file.typeSpec.name;
//         List<Element> originatingElements = file.typeSpec.originatingElements;
//         JavaFileObject filerSourceFile = filer.createSourceFile(fileName, originatingElements.toArray(
//                 new Element[originatingElements.size()]));
//         filerSourceFile.delete();
//         Writer writer = null;
//         try {
//             writer = filerSourceFile.openWriter();
//             file.writeTo(writer);
//         } catch (Exception e) {
//             try {
//                 filerSourceFile.delete();
//             } catch (Exception ignored) {
//             }
//             throw e;
//         } finally {
//             close(writer);
//         }
//     }
// 
//     @Nullable
//     static CharSequence readResource(@NotNull Filer filer, @NotNull String generatedPackageName,
//                                      @NotNull String resourceName) throws IOException {
//         try {
//             FileObject file =
//                     filer.getResource(StandardLocation.CLASS_OUTPUT, generatedPackageName, resourceName);
//             return file.getCharContent(false);
//         } catch (FileNotFoundException e) {
//             DebugLog.log("Resource not found: " + resourceName);
//             return null;
//         }
//     }
// 
//     static void writeToResource(@NotNull Filer filer, @NotNull String generatedPackageName,
//                                 @NotNull String resourceName, @NotNull CharSequence content)
//             throws IOException {
//         FileObject file =
//                 filer.createResource(StandardLocation.CLASS_OUTPUT, generatedPackageName, resourceName);
//         file.delete();
//         Writer writer = null;
//         try {
//             writer = file.openWriter();
//             writer.append(content);
//             DebugLog.log("Wrote to resource '" + resourceName + "':\n" + content);
//         } catch (Exception e) {
//             try {
//                 file.delete();
//             } catch (Exception ignored) {
//             }
//             throw e;
//         } finally {
//             close(writer);
//         }
//     }
// 
//     /**
//      * Safely closes a closeable.
//      *
//      * @param closeable object to close.
//      */
//     static void close(@Nullable Closeable closeable) {
//         if (closeable == null) {
//             return;
//         }
//         try {
//             closeable.close();
//         } catch (IOException e) {
//             // ignored
//         }
//     }
// 
//     /**
//      * Takes a String input and escapes it for use
//      * in the {@link CodeBlock} class.
//      *
//      * @param string the string to escape.
//      * @return a String safe to use in a {@link CodeBlock}
//      */
//     @NotNull
//     public static String escapeStringForCodeBlock(@NotNull String string) {
//         return string.replace(UNESCAPED_SEPARATOR, CODE_BLOCK_ESCAPED_SEPARATOR);
//     }
// 
//     /**
//      * Takes a String input that was escaped for
//      * use in the {@link CodeBlock} class and
//      * unescapes it for normal use.
//      *
//      * @param string the String to unescape,
//      * @return a String safe for normal use.
//      */
//     @NotNull
//     public static String unescapeEscapedString(@NotNull String string) {
//         return string.replace(CODE_BLOCK_ESCAPED_SEPARATOR, UNESCAPED_SEPARATOR);
//     }
// }


// Path: stag-library-compiler/src/main/java/com/vimeo/stag/processor/generators/EnumTypeAdapterGenerator.java
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import com.vimeo.stag.processor.generators.model.ClassInfo;
import com.vimeo.stag.processor.utils.FileGenUtils;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;

                .addParameter(JsonReader.class, "reader")
                .returns(typeName)
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Override.class)
                .addException(IOException.class)
                .beginControlFlow("if (reader.peek() == com.google.gson.stream.JsonToken.NULL)")
                .addStatement("reader.nextNull()")
                .addStatement("return null")
                .endControlFlow()
                .addStatement("return NAME_TO_CONSTANT.get(reader.nextString())")
                .build();
    }

    /**
     * Generates the TypeSpec for the TypeAdapter
     * that this enum generates.
     *
     * @return a valid TypeSpec that can be written
     * to a file or added to another class.
     */
    @Override
    @NotNull
    public TypeSpec createTypeAdapterSpec(@NotNull StagGenerator stagGenerator) {
        TypeMirror typeMirror = mInfo.getType();
        TypeName typeVariableName = TypeVariableName.get(typeMirror);

        MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC)
                .addParameter(Gson.class, "gson");

        String className = FileGenUtils.unescapeEscapedString(mInfo.getTypeAdapterClassName());