package be.jeffcheasey88.peeratcode.parser.java;

import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

import java.util.List;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;

import be.jeffcheasey88.peeratcode.parser.java.Variable.Value;

@TestInstance(Lifecycle.PER_CLASS)
class VariableTest{
	
	//int i = 4;
	//int i,j,k,l=1;
	//int lm      ;
	//public static int l;
	//Test<Test>t;
	//Test<Test,K,L>         j = new Test().schedule(p -> { return true;});
	//int i =j=k=l=4;

	private CleanerPool cleaner;
	
	@BeforeAll
	void init(){
		this.cleaner = new CleanerPool();
	}
	
	@Test
	void case1(){
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean("    int       i    =     4       ;                          "), cleaner);
			
			assertEquals(0, variable.getModifier());
			assertEquals("int", variable.getType());
			assertEquals("i", variable.getName());
			assertEquals("4", ((Value)variable.getValue()).value());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case2(){
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean("public    static   int    l         ;       "), cleaner);
			
			assertEquals(JavaParser.getModifier("public")+JavaParser.getModifier("static"), variable.getModifier());
			assertEquals("int", variable.getType());
			assertEquals("l", variable.getName());
			assertNull(variable.getValue());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case3(){
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean(" int lm      ;           "), cleaner);
			
			assertEquals(0, variable.getModifier());
			assertEquals("int", variable.getType());
			assertEquals("lm", variable.getName());
			assertNull(variable.getValue());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case4(){
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean("Test0<  List< Map< Test1, List<  Test2 >, Test3>> >t; "), cleaner);
			
			assertEquals(0, variable.getModifier());
			assertEquals("Test0<List<Map<Test1,List<Test2>,Test3>>>", variable.getType());
			assertEquals("t", variable.getName());
			assertNull(variable.getValue());
		}catch(Exception e){
			fail(e);
		}
	}

	@Test
	void case5(){
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean("  int i,j,k,l=1;   "), cleaner);
			
			assertEquals(0, variable.getModifier());
			assertEquals("int", variable.getType());
			assertEquals("i", variable.getName());
			assertNull(variable.getValue());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case6(){
		try {
			Class clazz = new Class();
			clazz.parse(cleaner.clean("public class Test{  int i ,j,k,l=1;  } "), cleaner);

			List<Variable> vars = clazz.getVariables();
			assertEquals(4, vars.size());
			for(int i = 0; i < 3; i++){
				Variable v = vars.get(i);
				assertEquals(0, v.getModifier());
				assertEquals("int", v.getType());
				assertEquals((char)('i'+i), v.getName().charAt(0));
				assertNull(v.getValue());
			}
			Variable v = vars.get(3);
			assertEquals(0, v.getModifier());
			assertEquals("int", v.getType());
			assertEquals('l', v.getName().charAt(0));
			assertEquals("1", ((Value)v.getValue()).value());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case7(){
		try {
			Class clazz = new Class();
			clazz.parse(cleaner.clean("public class Test{  int i ,j,k; int l=i=k=l=4;  } "), new CleanerPool());

			List<Variable> vars = clazz.getVariables();
			assertEquals(4, vars.size());
			for(int i = 0; i < 4; i++){
				Variable v = vars.get(i);
				assertEquals(0, v.getModifier());
				assertEquals("int", v.getType());
				assertEquals((char)('i'+i), v.getName().charAt(0));
			}
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case8(){
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean("int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]t; "), cleaner);
			
			assertEquals(0, variable.getModifier());
			assertEquals("int[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", variable.getType());
			assertEquals("t", variable.getName());
			assertNull(variable.getValue());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case9(){
		try {
			Class clazz = new Class();
			clazz.parse(cleaner.clean("public class Test{  int i ,j,k,l;  } "), cleaner);

			List<Variable> vars = clazz.getVariables();
			assertEquals(vars.size(), 4);
			for(int i = 0; i < 3; i++){
				Variable v = vars.get(i);
				assertEquals(0, v.getModifier());
				assertEquals("int", v.getType());
				assertEquals((char)('i'+i), v.getName().charAt(0));
				assertNull(v.getValue());
			}
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case10(){
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean("    boolean       i    =     j <<       3==0       ;                          "), cleaner);
			
			assertEquals(0, variable.getModifier());
			assertEquals("boolean", variable.getType());
			assertEquals("i", variable.getName());
			assertEquals("j<< 3 == 0", ((Value)variable.getValue()).value());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case11(){
		
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean("java.util.function.Function<Integer, Integer> j = ((i) -> {return 4;});"), cleaner);
			
			assertEquals(0, variable.getModifier());
			assertEquals("java.util.function.Function<Integer,Integer>", variable.getType());
			assertEquals("j", variable.getName());
			assertEquals("((i)-> {return 4;})", ((Value)variable.getValue()).value());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case12(){
		
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean(" public static final Locale FRENCH = createConstant(\"fr\", \"\");"), cleaner);
			
			assertEquals(JavaParser.getModifier("public")+JavaParser.getModifier("static")+JavaParser.getModifier("final"), variable.getModifier());
			assertEquals("Locale", variable.getType());
			assertEquals("FRENCH", variable.getName());
			assertEquals("createConstant(\"fr\",\"\")", ((Value)variable.getValue()).value());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case13(){
		
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean("private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[] { new ObjectStreamField(\"language\", String.class), new ObjectStreamField(\"country\", String.class), new ObjectStreamField(\"variant\", String.class), new ObjectStreamField(\"hashcode\", int.class), new ObjectStreamField(\"script\", String.class), new ObjectStreamField(\"extensions\", String.class) };"), cleaner);
			
			assertEquals(JavaParser.getModifier("private")+JavaParser.getModifier("static")+JavaParser.getModifier("final"), variable.getModifier());
			assertEquals("ObjectStreamField[]", variable.getType());
			assertEquals("serialPersistentFields", variable.getName());
			assertEquals("new ObjectStreamField[] { new ObjectStreamField(\"language\", String.class), new ObjectStreamField(\"country\", String.class), new ObjectStreamField(\"variant\", String.class), new ObjectStreamField(\"hashcode\", int.class), new ObjectStreamField(\"script\", String.class), new ObjectStreamField(\"extensions\", String.class) }", ((Value)variable.getValue()).value());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case14(){
		
		
		try {
			Class clazz = new Class();
			clazz.parse(cleaner.clean("public class Test{  private java.util.function.Function<Integer, Integer> j = ((i) -> {return 4;}), k = ((i) -> 4);  } "), cleaner);

			List<Variable> vars = clazz.getVariables();
			assertEquals(2, vars.size());
			Variable variable;
			variable = vars.get(0);
			assertEquals(JavaParser.getModifier("private"), variable.getModifier());
			assertEquals("java.util.function.Function<Integer,Integer>", variable.getType());
			assertEquals("j", variable.getName());
			assertEquals("((i)-> {return 4;})", ((Value)variable.getValue()).value());
			
			variable = vars.get(1);
			assertEquals(JavaParser.getModifier("private"), variable.getModifier());
			assertEquals("java.util.function.Function<Integer,Integer>", variable.getType());
			assertEquals("k", variable.getName());
			assertEquals("((i)->4)", ((Value)variable.getValue()).value());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case15(){
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean("    List <String>   list   = new ArrayList   <> ()  ;                          "), cleaner);
			
			assertEquals(0, variable.getModifier());
			assertEquals("List<String>", variable.getType());
			assertEquals("list", variable.getName());
			assertEquals("new ArrayList<>()", ((Value)variable.getValue()).value());
		}catch(Exception e){
			fail(e);
		}
	}
	
	@Test
	void case16(){
		try {
			Variable variable = new Variable();
			variable.parse(cleaner.clean("    List <String> a [] = new ArrayList   [   0] ;                          "), cleaner);
			
			assertEquals(0, variable.getModifier());
			assertEquals("List<String>", variable.getType());
			assertEquals("a[]", variable.getName());
			assertEquals("new ArrayList[0]", ((Value)variable.getValue()).value());
		}catch(Exception e){
			fail(e);
		}
	}
}
