package es.uniovi.reflection.patternmining.visitor.type;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale.Category;

import com.sun.source.tree.ArrayTypeTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.IntersectionTypeTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.ParameterizedTypeTree;
import com.sun.source.tree.PrimitiveTypeTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.UnionTypeTree;
import com.sun.source.util.TreeScanner;
import com.sun.tools.jdeps.Analyzer.Type;

import es.uniovi.reflection.patternmining.category.JavaType;
import es.uniovi.reflection.patternmining.category.Others;
import es.uniovi.reflection.patternmining.category.TypeCategory;
import es.uniovi.reflection.patternmining.features.ExpressionFeatures;
import es.uniovi.reflection.patternmining.features.TypeFeatures;
import es.uniovi.reflection.patternmining.model.ReturnFeatures;
import es.uniovi.reflection.patternmining.model.interfaces.ExpressionChild;
import es.uniovi.reflection.patternmining.model.interfaces.StatementChild;
import es.uniovi.reflection.patternmining.util.Util;

public class TypeVisitor extends TreeScanner<ReturnFeatures, TypeFeatures>{

	
	@Override
    public ReturnFeatures visitPrimitiveType(PrimitiveTypeTree primitiveTypeTree, TypeFeatures typeFeatures)  {
		
		typeFeatures.setTypeCategory(Util.getTypeCategory(primitiveTypeTree.getPrimitiveTypeKind().toString()));
		
		if(typeFeatures.getDimensions() > 0) {
			try {
				Util.databaseService.insertType(typeFeatures);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			ReturnFeatures returnFeatures = new ReturnFeatures();
			List<Long> statementChildIds = new ArrayList<Long>(); 
			statementChildIds.add(typeFeatures.getId());
			List<Long> expressionChildIds = new ArrayList<Long>(); 
			expressionChildIds.add(typeFeatures.getId());
	        returnFeatures.setStatementChildId(statementChildIds);
	        returnFeatures.setExpressionChildId(expressionChildIds);
	        return returnFeatures;
		}
        
		typeFeatures.setId(Util.getNextNodeId());
        typeFeatures.setPrimitive(true);
        typeFeatures.setSourceCode(primitiveTypeTree.toString());
        
        // leaf
        
        try {
			Util.databaseService.insertType(typeFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(typeFeatures.getTypeCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(typeFeatures.getId());
        
        ReturnFeatures returnFeatures = new ReturnFeatures();
        returnFeatures.setDepth(0);
        returnFeatures.setType(Util.getTypeFromCategory(typeFeatures.getTypeCategory()));
        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(typeFeatures.getTypeCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(typeFeatures.getId()));
        returnFeatures.setMethodTypeId(typeFeatures.getId());
        returnFeatures.setMethodParameterType(Util.getTypeFromCategory(typeFeatures.getTypeCategory()));
        return returnFeatures; 
    }
	
	@Override
    public ReturnFeatures visitIdentifier(IdentifierTree identifierTree, TypeFeatures typeFeatures)  {
		
		typeFeatures.setTypeCategory(Util.getTypeCategory(identifierTree.getName().toString()));
		
		if(typeFeatures.getDimensions() > 0) {
			try {
				Util.databaseService.insertType(typeFeatures);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			ReturnFeatures returnFeatures = new ReturnFeatures();
			List<Long> statementChildIds = new ArrayList<Long>(); 
			statementChildIds.add(typeFeatures.getId());
			List<Long> expressionChildIds = new ArrayList<Long>(); 
			expressionChildIds.add(typeFeatures.getId());
	        returnFeatures.setStatementChildId(statementChildIds);
	        returnFeatures.setExpressionChildId(expressionChildIds);
	        return returnFeatures;
		} 		

		typeFeatures.setSourceCode(identifierTree.toString());
        typeFeatures.setId(Util.getNextNodeId());
        
        // leaf
        
        try {
			Util.databaseService.insertType(typeFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
        List<StatementChild> statementChilds = new ArrayList<StatementChild>(); 
    	statementChilds.add(typeFeatures.getTypeCategory());
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(typeFeatures.getTypeCategory());
		List<Long> statementChildIds = new ArrayList<Long>(); 
		statementChildIds.add(typeFeatures.getId());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(typeFeatures.getId());
        
        ReturnFeatures returnFeatures = new ReturnFeatures();
        returnFeatures.setDepth(0);
        returnFeatures.setType(Util.getTypeFromCategory(typeFeatures.getTypeCategory()));
        returnFeatures.setStatementChild(statementChilds);
        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setStatementChildId(statementChildIds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setMethodTypeId(typeFeatures.getId());
        returnFeatures.setMethodParameterType(Util.getTypeFromCategory(typeFeatures.getTypeCategory()));
        return returnFeatures; // es hoja
    }
	
	@Override
    public ReturnFeatures visitArrayType(ArrayTypeTree arrayTypeTree, TypeFeatures typeFeatures)  {

		typeFeatures.setId(Util.getNextNodeId());
		typeFeatures.setDimensions(typeFeatures.getDimensions() + 1);
		
		if(typeFeatures.getDimensions() == 1) {
			typeFeatures.setSourceCode(arrayTypeTree.toString());
		}
		
		ReturnFeatures returnFeatures = scan(arrayTypeTree.getType(), typeFeatures);

		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(TypeCategory.Array);
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(typeFeatures.getId());

		returnFeatures.setDepth(0);
        returnFeatures.setType(TypeCategory.Array);
        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(TypeCategory.Array));
        returnFeatures.setStatementChildId(Util.setStatementChildId(typeFeatures.getId()));
        returnFeatures.setMethodTypeId(typeFeatures.getId());
        returnFeatures.setMethodParameterType(TypeCategory.Array);
		return returnFeatures;

    }
	
	@Override
    public ReturnFeatures visitParameterizedType(ParameterizedTypeTree parameterizedTypeTree, TypeFeatures typeFeatures)  {
		
		typeFeatures.setId(Util.getNextNodeId());
		
		for(Tree tree: parameterizedTypeTree.getTypeArguments()) {
			typeFeatures.setGenerics(typeFeatures.getGenerics() + 1);
		}
		
		typeFeatures.setSourceCode(parameterizedTypeTree.toString());
		
		try {
			typeFeatures.setTypeCategory(JavaType.Reference);
			Util.databaseService.insertType(typeFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(typeFeatures.getTypeCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(typeFeatures.getId());
		
		ReturnFeatures returnFeatures = new ReturnFeatures();
		returnFeatures.setDepth(0);
        returnFeatures.setType(TypeCategory.Generic);
        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(typeFeatures.getTypeCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(typeFeatures.getId()));
        returnFeatures.setMethodTypeId(typeFeatures.getId());
        returnFeatures.setMethodParameterType(TypeCategory.Generic);
		return returnFeatures;     
    }

	@Override
	public ReturnFeatures visitUnionType(UnionTypeTree node, TypeFeatures typeFeatures) {
		typeFeatures.setTypeCategory(JavaType.UnionType);
		typeFeatures.setSourceCode(node.toString());
		try {
			Util.databaseService.insertType(typeFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		ReturnFeatures returnFeatures = new ReturnFeatures();
		List<Long> statementChildIds = new ArrayList<Long>(); 
		statementChildIds.add(typeFeatures.getId());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(typeFeatures.getId());
        returnFeatures.setStatementChildId(statementChildIds);
        returnFeatures.setExpressionChildId(expressionChildIds);        
        return returnFeatures;
	}

	@Override
	public ReturnFeatures visitIntersectionType(IntersectionTypeTree node, TypeFeatures typeFeatures) {
		typeFeatures.setTypeCategory(JavaType.IntersectionType);
		typeFeatures.setSourceCode(node.toString());
		try {
			Util.databaseService.insertType(typeFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		ReturnFeatures returnFeatures = new ReturnFeatures();
		List<Long> statementChildIds = new ArrayList<Long>(); 
		statementChildIds.add(typeFeatures.getId());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(typeFeatures.getId());
	    returnFeatures.setStatementChildId(statementChildIds);
	    returnFeatures.setExpressionChildId(expressionChildIds);	    
	    return returnFeatures;
	}
	
	

}
