package com.twitter.elephantbird.mapreduce.io;

import static org.junit.Assert.assertEquals;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;

import org.apache.tools.ant.taskdefs.Java;
import org.apache.tools.ant.types.Environment;
import org.junit.BeforeClass;
import org.junit.Test;

import com.twitter.data.proto.tutorial.AddressBookProtos.AddressBook;
import com.twitter.data.proto.tutorial.AddressBookProtos.Person;
import com.twitter.data.proto.tutorial.AddressBookProtos.Person.PhoneNumber;
import com.twitter.data.proto.tutorial.AddressBookProtos.Person.PhoneType;
import com.twitter.elephantbird.mapreduce.io.ProtobufWritable;
import com.twitter.elephantbird.util.TypeRef;


public class TestProtobufWritable {

  static AddressBook referenceAb;
  static ProtobufWritable<AddressBook> referenceAbWritable;

  @BeforeClass
  public static void setUp() {
    Person p1 = Person.newBuilder()
    .setEmail("email1@example.com")
    .setId(74)
    .setName("Example Person")
    .addPhone(PhoneNumber.newBuilder().setType(PhoneType.MOBILE).setNumber("2930423").build())
    .addPhone(PhoneNumber.newBuilder().setType(PhoneType.HOME).setNumber("214121").build())
    .build();

    Person p2 = Person.newBuilder()
    .setEmail("email2@example.com")
    .setId(7334)
    .setName("Another person")
    .addPhone(PhoneNumber.newBuilder().setType(PhoneType.MOBILE).setNumber("030303").build())
    .build();

    referenceAb = AddressBook.newBuilder()
    .addPerson(p1)
    .addPerson(p2)
    .build();

    referenceAbWritable =
      new ProtobufWritable<AddressBook>(referenceAb, new TypeRef<AddressBook>(){});
  }

  @Test
  public void testReadWrite() throws IOException {

    DataOutputStream dos = new DataOutputStream(new FileOutputStream("test.txt"));
    referenceAbWritable.write(dos);
    dos.close();

    DataInputStream dis = new DataInputStream(new FileInputStream("test.txt"));
    ProtobufWritable<AddressBook> after = new ProtobufWritable<AddressBook>(new TypeRef<AddressBook>(){});
    after.readFields(dis);
    dis.close();

    AddressBook ab2 = after.get();
    assertEquals(referenceAb, ab2);
    assertEquals(referenceAbWritable.hashCode(), after.hashCode());
  }

//  @Test
//  public void testStableHashcodeAcrossJVMs() throws IOException {
//    int expectedHashCode = referenceAbWritable.hashCode();
//    Java otherJvm = new Java();
//    otherJvm.setNewenvironment(true);
//    otherJvm.setFork(true);
//    otherJvm.setClassname(OtherJvmClass.class.getName());
//    for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
//      Environment.Variable var = new Environment.Variable();
//      var.setKey(entry.getKey());
//      var.setValue(entry.getValue());
//      otherJvm.addEnv(var);
//    }
//    for (String prop : System.getProperties().stringPropertyNames()) {
//      String propValue = System.getProperty(prop);
//      Environment.Variable var = new Environment.Variable();
//      var.setKey(prop);
//      var.setValue(propValue);
//      otherJvm.addSysproperty(var);
//    }
//    otherJvm.setDir(new File(System.getProperty("java.io.tmpdir")));
//    File tmpOut = File.createTempFile("otherJvm", "txt");
//    otherJvm.setArgs(tmpOut.getAbsolutePath());
//    otherJvm.init();
//    otherJvm.executeJava();
//    DataInputStream is = new DataInputStream(new FileInputStream(tmpOut));
//    assertEquals(expectedHashCode, is.readInt());
//    is.close();
//  }

  public static class OtherJvmClass {
    /* Used for testStableHashcodeAcrossJVMs */
    public static void main(String[] args) throws IOException {
      setUp();
      int hashCode = referenceAbWritable.hashCode();
      File tmpFile = new File(args[0]);
      DataOutputStream os = new DataOutputStream(new FileOutputStream(tmpFile));
      os.writeInt(hashCode);
      os.close();
      System.exit(0);
    }
  }
}

@@ -289,16 +289,53 @@
 l.Map;%0A%0A
+import org.apache.tools.ant.Project;%0A
 import o
@@ -2383,18 +2383,16 @@
  %7D%0A%0A
-//
   @Test%0A
 //  
@@ -2387,18 +2387,16 @@
   @Test%0A
-//
   public
@@ -2453,18 +2453,16 @@
 ption %7B%0A
-//
     int 
@@ -2508,26 +2508,24 @@
 hashCode();%0A
-//
     Java oth
@@ -2540,26 +2540,24 @@
 new Java();%0A
-//
     otherJvm
@@ -2574,34 +2574,32 @@
 ironment(true);%0A
-//
     otherJvm.set
@@ -2606,26 +2606,64 @@
 Fork(true);%0A
-//
+    otherJvm.setProject(new Project());%0A
     otherJvm
@@ -2704,26 +2704,24 @@
 getName());%0A
-//
     for (Map
@@ -2777,26 +2777,24 @@
 trySet()) %7B%0A
-//
       Enviro
@@ -2834,34 +2834,32 @@
 ent.Variable();%0A
-//
       var.setKey
@@ -2872,26 +2872,24 @@
 .getKey());%0A
-//
       var.se
@@ -2910,26 +2910,24 @@
 etValue());%0A
-//
       otherJ
@@ -2938,34 +2938,30 @@
 ddEnv(var);%0A
-//
     %7D%0A
-//
     for (Str
@@ -3019,18 +3019,16 @@
 es()) %7B%0A
-//
       St
@@ -3066,26 +3066,24 @@
 erty(prop);%0A
-//
       Enviro
@@ -3127,26 +3127,24 @@
 Variable();%0A
-//
       var.se
@@ -3155,18 +3155,16 @@
 (prop);%0A
-//
       va
@@ -3186,18 +3186,16 @@
 Value);%0A
-//
       ot
@@ -3226,18 +3226,14 @@
 r);%0A
-//
     %7D%0A
-//
     
@@ -3293,26 +3293,24 @@
 tmpdir%22)));%0A
-//
     File tmp
@@ -3355,18 +3355,16 @@
 %22txt%22);%0A
-//
     othe
@@ -3399,26 +3399,24 @@
 utePath());%0A
-//
     otherJvm
@@ -3420,26 +3420,24 @@
 Jvm.init();%0A
-//
     otherJvm
@@ -3452,18 +3452,16 @@
 Java();%0A
-//
     Data
@@ -3523,26 +3523,24 @@
 m(tmpOut));%0A
-//
     assertEq
@@ -3577,18 +3577,16 @@
 Int());%0A
-//
     is.c
@@ -3597,10 +3597,8 @@
 ();%0A
-//
   %7D%0A

Fix the testStableHashcodeAcrossJVMs test