/**
 * Copyright (c) 2012-2015 DataTorrent, Inc.
 * All rights reserved.
 */
package com.datatorrent.stram.webapp;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.codehaus.jackson.annotate.JsonTypeInfo.As;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import org.junit.Assert;
import org.junit.Test;

import com.datatorrent.api.BaseOperator;
import com.google.common.collect.Lists;

public class OperatorDiscoveryTest
{
  @Test
  public void testPropertyDiscovery() throws Exception
  {
    OperatorDiscoverer od = new OperatorDiscoverer();
    Assert.assertNotNull(od.getOperatorClass(BaseOperator.class.getName()));

    JSONObject desc = od.describeClass(TestOperator.class);
    System.out.println("\ntype info for " + TestOperator.class + ":\n" + desc.toString(2));

    JSONArray props = desc.getJSONArray("properties");
    Assert.assertNotNull("properties", props);
    JSONObject mapProperty = props.getJSONObject(4);
    Assert.assertEquals("name " + mapProperty, "map", mapProperty.get("name"));
    Assert.assertEquals("canGet " + mapProperty, true, mapProperty.get("canGet"));
    Assert.assertEquals("canSet " + mapProperty, true, mapProperty.get("canSet"));
    Assert.assertEquals("type " + mapProperty, java.util.Map.class.toString(), mapProperty.get("type"));

    JSONArray typeArgs = mapProperty.getJSONArray("typeArgs");
    Assert.assertNotNull("typeArgs", typeArgs);
    Assert.assertEquals("typeArgs " + typeArgs, 2, typeArgs.length());
    Assert.assertEquals("", String.class.toString(), typeArgs.getJSONObject(0).get("type"));
    Assert.assertEquals("", Structured.class.toString(), typeArgs.getJSONObject(1).get("type"));


    JSONObject enumDesc = od.describeClass(Color.class);
    JSONArray enumNames = enumDesc.getJSONArray("enum");
    Assert.assertNotNull("enumNames", enumNames);
    Assert.assertEquals("", Color.BLUE.name(), enumNames.get(0));

    JSONObject structuredProperty = props.getJSONObject(6);
    Assert.assertEquals("name " + structuredProperty, "nested", structuredProperty.get("name"));
    Assert.assertEquals("type " + structuredProperty, Structured.class.toString(), structuredProperty.get("type"));

    // type is not a primitive type
    // fetch property meta data to find out how to render it
    desc = od.describeClass(Structured.class);
    System.out.println("\ntype info for " + Structured.class + ":\n" + desc.toString(2));

  }

  @Test
  public void testValueSerialization() throws Exception
  {
    TestOperator bean = new TestOperator();
    bean.map.put("key1", new Structured());
    bean.stringArray = new String[] { "one", "two", "three" };
    bean.stringList = Lists.newArrayList("four", "five");
    bean.props = new Properties();
    bean.props.setProperty("key1", "value1");
    bean.structuredArray = new Structured[]{new Structured()};
    bean.structuredArray[0].name = "s1";
    bean.color = Color.BLUE;

    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    //mapper.enableDefaultTypingAsProperty(ObjectMapper.DefaultTyping.NON_FINAL, Id.CLASS.getDefaultPropertyName());
    mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, As.WRAPPER_OBJECT);
    String s = mapper.writeValueAsString(bean);
    System.out.println(new JSONObject(s).toString(2));


    TestOperator clone = mapper.readValue(s, TestOperator.class);
    Assert.assertNotNull(clone.structuredArray);
    Assert.assertEquals(Color.BLUE, clone.color);
    Assert.assertEquals(bean.structuredArray.length, clone.structuredArray.length);


  }

  public static class Structured
  {
    private int size;
    private String name;
    private ArrayList<String> list;

    public int getSize()
    {
      return size;
    }

    public void setSize(int size)
    {
      this.size = size;
    }

    public String getName()
    {
      return name;
    }

    public void setName(String name)
    {
      this.name = name;
    }

    public ArrayList<String> getList()
    {
      return list;
    }

    public void setList(ArrayList<String> list)
    {
      this.list = list;
    }

  }

  public enum Color
  {
    BLUE,
    RED,
    WHITE
  }

  public static class TestOperator extends BaseOperator
  {
    private int intProp;
    private long longProp;
    private double doubleProp;

    private List<String> stringList;
    private Properties props;
    private Structured nested;
    private Map<String, Structured> map = new HashMap<String, Structured>();
    private String[] stringArray;
    private Color color;
    private Structured[] structuredArray;

    public int getIntProp()
    {
      return intProp;
    }

    public void setIntProp(int intProp)
    {
      this.intProp = intProp;
    }

    public long getLongProp()
    {
      return longProp;
    }

    public void setLongProp(long longProp)
    {
      this.longProp = longProp;
    }

    public double getDoubleProp()
    {
      return doubleProp;
    }

    public void setDoubleProp(double doubleProp)
    {
      this.doubleProp = doubleProp;
    }

    public List<String> getStringList()
    {
      return stringList;
    }

    public void setStringList(List<String> stringList)
    {
      this.stringList = stringList;
    }

    public Properties getProps()
    {
      return props;
    }

    public void setProps(Properties props)
    {
      this.props = props;
    }

    public Structured getNested()
    {
      return nested;
    }

    public void setNested(Structured n)
    {
      this.nested = n;
    }

    public Map<String, Structured> getMap()
    {
      return map;
    }

    public void setMap(Map<String, Structured> m)
    {
      this.map = m;
    }

    public Color getColor()
    {
      return color;
    }

    public void setColor(Color color)
    {
      this.color = color;
    }

    public String[] getStringArray()
    {
      return stringArray;
    }

    public Structured[] getStructuredArray()
    {
      return structuredArray;
    }

    public void setStructuredArray(Structured[] structuredArray)
    {
      this.structuredArray = structuredArray;
    }

  }

}

@@ -1104,9 +1104,9 @@
 ect(
-4
+5
 );%0A 
@@ -2121,9 +2121,9 @@
 ect(
-6
+7
 );%0A 
@@ -2570,16 +2570,144 @@
 g(2));%0A%0A
+    desc = od.describeClass(Color.class);%0A    System.out.println(%22%5Cntype info for %22 + Color.class + %22:%5Cn%22 + desc.toString(2));%0A%0A
   %7D%0A%0A  @
@@ -3193,16 +3193,45 @@
 or.BLUE;
+%0A    bean.booleanProp = true;
 %0A%0A    Ob
@@ -4693,16 +4693,49 @@
 bleProp;
+%0A    private boolean booleanProp;
 %0A%0A    pr
@@ -6529,19 +6529,187 @@
 ray;%0A    %7D%0A%0A
+    public boolean isBooleanProp() %7B%0A      return booleanProp;%0A    %7D%0A%0A    public void setBooleanProp(boolean booleanProp) %7B%0A      this.booleanProp = booleanProp;%0A    %7D%0A
   %7D%0A%0A%7D%0A

add boolean property to test operator