package com.apollographql.android.gradle;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import org.gradle.api.Task;
import org.gradle.api.specs.Spec;
import org.gradle.api.tasks.OutputDirectory;

import com.google.common.collect.Lists;

import com.moowork.gradle.node.npm.NpmTask;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;

import okio.Okio;

public class ApolloCodeGenInstallTask extends NpmTask {
  static final String NAME = "installApolloCodegen";
  private static final String INSTALL_DIR = "node_modules/apollo-codegen";
  private static final String APOLLOCODEGEN_VERSION = "0.10.1";

  @OutputDirectory private File installDir;

  public ApolloCodeGenInstallTask() {
    // TODO: set to const when ApolloPlugin is in java
    setGroup("apollo");
    setDescription("Runs npm install for apollo-codegen");
    installDir = getProject().file(INSTALL_DIR);

    final File apolloPackageFile = getProject().file("package.json");
    final String apolloVersion = getApolloVersion();

    getOutputs().upToDateWhen(new Spec<Task>() {
      public boolean isSatisfiedBy(Task element) {
        return !(apolloPackageFile.isFile() || (apolloVersion != null && apolloVersion.equals(APOLLOCODEGEN_VERSION)));
      }
    });
    if (!apolloPackageFile.isFile()) {
      writePackageFile(apolloPackageFile);
    }
    setArgs(Lists.newArrayList("install", "apollo-codegen@" + APOLLOCODEGEN_VERSION, "--save", "--save-exact"));
  }

  /**
   * Returns the locally install apollo-codegen version as found in the package.json file.
   *
   * @return null if node_modules/apollo-codegen/package.json wasn't found, version otherwise
   */
  private String getApolloVersion() {
    File packageFile = getProject().file(INSTALL_DIR + "/package.json");
    if (!packageFile.isFile()) {
      return null;
    }
    JsonReader jsonReader;
    try {
      jsonReader = JsonReader.of(Okio.buffer(Okio.source(packageFile)));
      jsonReader.beginObject();

      while (jsonReader.hasNext()) {
        String name = jsonReader.nextName();
        if (name.equals("version")) {
          return jsonReader.nextString();
        }
      }
      jsonReader.endObject();
      jsonReader.close();

    }
    catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }

  /**
   * Generates a dummy package.json file to silence npm warnings
   */
  private void writePackageFile(File apolloPackageFile) {
    try {
      JsonWriter writer = JsonWriter.of(Okio.buffer(Okio.sink(apolloPackageFile)));

      writer.beginObject();

      writer.name("name").value("apollo-android");
      writer.name("version").value("0.0.1");
      writer.name("description").value("Generates Java code based on a GraphQL schema and query documents. Uses " +
          "apollo-codegen under the hood.");
      writer.name("name").value("apollo-android");
      writer.name("repository");
      writer.beginObject();
      writer.name("type").value("git");
      writer.name("url").value("git+https://github.com/apollostack/apollo-android.git");
      writer.endObject();
      writer.name("author").value("Apollo");
      writer.name("license").value("MIT");
      writer.endObject();
      writer.close();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }

  public File getInstallDir() {
    return installDir;
  }
}

@@ -408,16 +408,88 @@
 nWriter;
+%0Aimport com.squareup.moshi.JsonAdapter;%0Aimport com.squareup.moshi.Moshi;
 %0A%0Aimport
@@ -1583,24 +1583,77 @@
 ct%22));%0A  %7D%0A%0A
+  static class PackageJson %7B%0A    String version;%0A  %7D%0A
   /**%0A   * R
@@ -2015,397 +2015,267 @@
   %7D%0A
+%0A
     
-JsonReader jsonReader;%0A    try %7B%0A      jsonReader = JsonReader.of(Okio.buffer(Okio.source(packageFile)));%0A      jsonReader.beginObject();%0A%0A      while (jsonReader.hasNext()) %7B%0A        String name = jsonReader.nextName();%0A        if (name.equals(%22version%22)) %7B%0A          return jsonReader.nextString();%0A        %7D%0A      %7D%0A      jsonReader.endObject();%0A      jsonReader.close();%0A%0A    %7D%0A   
+Moshi moshi = new Moshi.Builder().build();%0A    JsonAdapter%3CPackageJson%3E adapter = moshi.adapter(PackageJson.class);%0A    try %7B%0A      PackageJson packageJson = adapter.fromJson(Okio.buffer(Okio.source(packageFile)));%0A      return packageJson.version;%0A    %7D
  cat
@@ -2320,28 +2320,24 @@
 kTrace();%0A  
-  %7D%0A
     return n
@@ -2341,16 +2341,22 @@
 n null;%0A
+    %7D%0A
   %7D%0A%0A  /

Fix apollo codegen task (#131)