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

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.Modifier;

import com.sun.source.tree.AnnotatedTypeTree;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ArrayAccessTree;
import com.sun.source.tree.ArrayTypeTree;
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.BlockTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompoundAssignmentTree;
import com.sun.source.tree.ConditionalExpressionTree;
import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.InstanceOfTree;
import com.sun.source.tree.LambdaExpressionTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.MemberReferenceTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewArrayTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.ParameterizedTypeTree;
import com.sun.source.tree.ParenthesizedTree;
import com.sun.source.tree.PrimitiveTypeTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.tree.UnaryTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreeScanner;

import es.uniovi.reflection.patternmining.category.ExpressionCategory;
import es.uniovi.reflection.patternmining.category.ExpressionRole;
import es.uniovi.reflection.patternmining.category.StatementRole;
import es.uniovi.reflection.patternmining.category.TypeParent;
import es.uniovi.reflection.patternmining.category.TypeRole;
import es.uniovi.reflection.patternmining.features.ExpressionFeatures;
import es.uniovi.reflection.patternmining.features.StatementFeatures;
import es.uniovi.reflection.patternmining.features.TypeDefFeatures;
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 ExpressionsVisitor extends TreeScanner<ReturnFeatures, ExpressionFeatures>{
	
	@Override
    public ReturnFeatures visitLiteral(LiteralTree literalTree, ExpressionFeatures expressionFeatures)  {  
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(Util.getLiteralKind(literalTree.getKind().toString()));
		expressionFeatures.setSourceCode(literalTree.toString());
    
        expressionFeatures.setDepth(0);
        
        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
		List<StatementChild> statementChilds = new ArrayList<StatementChild>(); 
    	statementChilds.add(expressionFeatures.getExpressionCategory());
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> statementChildIds = new ArrayList<Long>(); 
		statementChildIds.add(expressionFeatures.getId());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());
		
        ReturnFeatures returnFeatures = new ReturnFeatures();
        returnFeatures.setDepth(0);
        returnFeatures.setStatementChild(statementChilds);
        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setStatementChildId(statementChildIds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        return returnFeatures; // es hoja
    }
	
	@Override
    public ReturnFeatures visitParenthesized(ParenthesizedTree parenthesizedTree, ExpressionFeatures expressionParentFeatures)  {
		// no cuenta como statement
        
		//always one child
		ReturnFeatures returnFeatures = super.visitParenthesized(parenthesizedTree, expressionParentFeatures);
		//returnFeatures.setDownDepth(expressionParentFeatures.getDownDepth());
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitUnary(UnaryTree unaryTree, ExpressionFeatures expressionFeatures)  {
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.valueOf(Util.getUnaryKind(unaryTree.getKind().toString())));
		expressionFeatures.setSourceCode(unaryTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
		ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.UnaryEncloses);
		ReturnFeatures returnAuxFeatures = scan(unaryTree.getExpression(), expressionChildFeatures);
		Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);

        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());
		
        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitIdentifier(IdentifierTree identifierTree, ExpressionFeatures expressionFeatures)  {
		
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.Variable);
		expressionFeatures.setSourceCode(identifierTree.toString());
		
		expressionFeatures.setDepth(0);
        
        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
        ReturnFeatures returnFeatures = new ReturnFeatures(); 

        List<StatementChild> statementChilds = new ArrayList<StatementChild>(); 
    	statementChilds.add(expressionFeatures.getExpressionCategory());
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> statementChildIds = new ArrayList<Long>(); 
		statementChildIds.add(expressionFeatures.getId());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());
		
        returnFeatures.setDepth(0);
        returnFeatures.setStatementChild(statementChilds);
        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setStatementChildId(statementChildIds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitBinary(BinaryTree binaryTree, ExpressionFeatures expressionFeatures)  {
		
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(Util.getBinaryKind(binaryTree.getKind().toString()));
		expressionFeatures.setSourceCode(binaryTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
		ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.BinopLHS);
        ReturnFeatures returnAuxFeatures = scan(binaryTree.getLeftOperand(), expressionChildFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        
        
        expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.BinopRHS);
		returnAuxFeatures = scan(binaryTree.getRightOperand(), expressionChildFeatures);
		Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        
        //llamada hijos
        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());
		
        returnFeatures.setDepth(expressionFeatures.getDepth());
        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	public ReturnFeatures visitCompoundAssignment(CompoundAssignmentTree compoundAssignmentTree, ExpressionFeatures expressionFeatures) {

		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.CompoundAssignment);
		expressionFeatures.setSourceCode(compoundAssignmentTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
		ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.CompoundAssignmentVariable);
		ReturnFeatures returnAuxFeatures = scan(compoundAssignmentTree.getVariable(), expressionChildFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        
        
        expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.CompoundAssignmentExpression);
		returnAuxFeatures = scan(compoundAssignmentTree.getExpression(), expressionChildFeatures);
		Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        
        //llamada hijos
        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());
		
        returnFeatures.setDepth(expressionFeatures.getDepth());
        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
	}
	
	@Override
    public ReturnFeatures visitLambdaExpression(LambdaExpressionTree lambdaExpressionTree, ExpressionFeatures expressionFeatures)  {
        
		//nodo lambda
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.LambdaExpression);
		expressionFeatures.setSourceCode(lambdaExpressionTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
        
        //LAMBDA EXPRESSION PARAMETERS
        ExpressionFeatures expressionFeaturesParameters = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.LambdaParameter);
  		
        expressionFeaturesParameters.setId(Util.getNextNodeId());
        expressionFeaturesParameters.setExpressionCategory(ExpressionCategory.LambdaExpressionParameter);
        expressionFeaturesParameters.setSourceCode(lambdaExpressionTree.getParameters().toString());
        
        expressionFeatures.setFirstChild(ExpressionCategory.LambdaExpressionParameter);
        expressionFeatures.setFirstChildId(expressionFeaturesParameters.getId());

        for(VariableTree st: lambdaExpressionTree.getParameters()) {
        	
        	//le paso lo del padre a cada hijo, necesito devolver el nº de statements y la profundidad
        	StatementFeatures statementFeatures = Util.setStatementChildFeatures(expressionFeaturesParameters, StatementRole.LambdaParameterStatement);
        	ReturnFeatures returnAuxFeatures = Util.visitors.getVisitorStatements().visitVariable(st, statementFeatures);
        	Util.updateExpressionFeatures(expressionFeaturesParameters, returnFeatures, returnAuxFeatures);
        	for (StatementChild statementChild : returnAuxFeatures.getStatementChild()) {
    			if(expressionFeaturesParameters.getFirstChild() == ExpressionCategory.None) expressionFeaturesParameters.setFirstChild((ExpressionChild) statementChild);
                else if(expressionFeaturesParameters.getSecondChild() == ExpressionCategory.None) expressionFeaturesParameters.setSecondChild((ExpressionChild) statementChild);
                else if(expressionFeaturesParameters.getThirdChild() == ExpressionCategory.None) expressionFeaturesParameters.setThirdChild((ExpressionChild) statementChild); 
    	    }
        	for (long id : returnAuxFeatures.getStatementChildId()) {
        		if(expressionFeaturesParameters.getFirstChildId() == 0) expressionFeaturesParameters.setFirstChildId(id);
                else if(expressionFeaturesParameters.getSecondChildId() == 0) expressionFeaturesParameters.setSecondChildId(id);
                else if(expressionFeaturesParameters.getThirdChildId() == 0) expressionFeaturesParameters.setThirdChildId(id);
    	    }
        }
        
        //lambda parameters insertion
        try {
			Util.databaseService.insertExpression(expressionFeaturesParameters);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
        
        //LAMBDA EXPRESSION BODY
        ExpressionFeatures expressionFeaturesBody = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.LambdaParameter);
        
        expressionFeaturesBody.setId(Util.getNextNodeId());
        expressionFeaturesBody.setExpressionCategory(ExpressionCategory.LambdaExpressionBody);
        expressionFeaturesBody.setSourceCode(lambdaExpressionTree.getBody().toString());
        
        expressionFeatures.setSecondChild(ExpressionCategory.LambdaExpressionBody);
        expressionFeatures.setSecondChildId(expressionFeaturesBody.getId());
        
        ReturnFeatures returnAuxFeatures = new ReturnFeatures();

        //Check que tipo de body es, si expresión o statement
        if(lambdaExpressionTree.getBodyKind().toString() == "EXPRESSION") {
            ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeaturesBody, ExpressionRole.LambdaBody);
            returnAuxFeatures = scan(lambdaExpressionTree.getBody(), expressionChildFeatures);
        	Util.updateExpressionFeatures(expressionFeaturesBody, returnFeatures, returnAuxFeatures);
        }else {
            if(lambdaExpressionTree.getBody().getKind().toString() == "BLOCK") { //block
            	StatementFeatures statementChildFeatures = Util.setStatementChildFeatures(expressionFeaturesBody, StatementRole.LambdaBodyStatement);
            	returnAuxFeatures = Util.visitors.getVisitorStatements().scan(lambdaExpressionTree.getBody(), statementChildFeatures);
            	Util.updateExpressionFeatures(expressionFeaturesBody, returnFeatures, returnAuxFeatures);
            	for (StatementChild statementChild : returnAuxFeatures.getStatementChild()) {
        			if(expressionFeaturesBody.getFirstChild() == ExpressionCategory.None) expressionFeaturesBody.setFirstChild((ExpressionChild) statementChild);
                    else if(expressionFeaturesBody.getSecondChild() == ExpressionCategory.None) expressionFeaturesBody.setSecondChild((ExpressionChild) statementChild);
                    else if(expressionFeaturesBody.getThirdChild() == ExpressionCategory.None) expressionFeaturesBody.setThirdChild((ExpressionChild) statementChild); 
        	    }
            	for (long id : returnAuxFeatures.getStatementChildId()) {
            		if(expressionFeaturesBody.getFirstChildId() == 0) expressionFeaturesBody.setFirstChildId(id);
                    else if(expressionFeaturesBody.getSecondChildId() == 0) expressionFeaturesBody.setSecondChildId(id);
                    else if(expressionFeaturesBody.getThirdChildId() == 0) expressionFeaturesBody.setThirdChildId(id);
        	    }
            }else { //solo un hijo
        		StatementFeatures statementChildFeatures = Util.setStatementChildFeatures(expressionFeaturesBody, StatementRole.LambdaBodyStatement);
                returnAuxFeatures = Util.visitors.getVisitorStatements().scan(lambdaExpressionTree.getBody(), statementChildFeatures);
            	Util.updateExpressionFeatures(expressionFeaturesBody, returnFeatures, returnAuxFeatures);
            	for (StatementChild statementChild : returnAuxFeatures.getStatementChild()) {
        			if(expressionFeaturesBody.getFirstChild() == ExpressionCategory.None) expressionFeaturesBody.setFirstChild((ExpressionChild) statementChild);
                    else if(expressionFeaturesBody.getSecondChild() == ExpressionCategory.None) expressionFeaturesBody.setSecondChild((ExpressionChild) statementChild);
                    else if(expressionFeaturesBody.getThirdChild() == ExpressionCategory.None) expressionFeaturesBody.setThirdChild((ExpressionChild) statementChild); 
        	    }
            	for (long id : returnAuxFeatures.getStatementChildId()) {
            		if(expressionFeaturesBody.getFirstChildId() == 0) expressionFeaturesBody.setFirstChildId(id);
                    else if(expressionFeaturesBody.getSecondChildId() == 0) expressionFeaturesBody.setSecondChildId(id);
                    else if(expressionFeaturesBody.getThirdChildId() == 0) expressionFeaturesBody.setThirdChildId(id);
        	    }
            }
        }
        
        //lambda body insertion
        try {
			Util.databaseService.insertExpression(expressionFeaturesBody);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

        //lambda insertion
        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

        returnFeatures.setDepth(expressionFeatures.getDepth());
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitBlock(BlockTree blockTree, ExpressionFeatures expressionFeatures) {
		//ExpressionParentFeatures siempre es el Body de LambdaExpressionTree
        
        ReturnFeatures returnFeatures = new ReturnFeatures();
        //System.out.println("Statements size "+blockTree.getStatements().size());
        for(StatementTree st: blockTree.getStatements()) {
        	StatementFeatures statementFeatures = new StatementFeatures();
        	statementFeatures.setId(expressionFeatures.getId());
            statementFeatures.setHeight(expressionFeatures.getHeight()); // because block it is not considered an statement
            //statementFeatures.setStatementCategory(NodeASTTypes.LambdaExpressionBody);
            //statementFeatures.setParentChild(ExpressionRole.LambdaBody);
            
            returnFeatures = Util.visitors.getVisitorStatements().scan(st, statementFeatures);
            //Util.setExpressionChild(expressionParentFeatures, auxReturnMethodFeatures.getNodeType());
            
        }
        //este no cuenta como statement
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitNewClass(NewClassTree newClassTree, ExpressionFeatures expressionFeatures)  {
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.NewClass);
		expressionFeatures.setSourceCode(newClassTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
        ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.NewClassEnclosingExpression);
        ReturnFeatures returnAuxFeatures = scan(newClassTree.getEnclosingExpression(), expressionChildFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
               
        TypeFeatures typeFeatures = Util.setTypeChildFeatures(expressionFeatures, TypeParent.NewClass, TypeRole.NewClassType);
        returnAuxFeatures = Util.visitors.getVisitorType().scan(newClassTree.getIdentifier(), typeFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
                
        for(ExpressionTree exp: newClassTree.getArguments()) {
        	expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.NewClassArguments);
            returnAuxFeatures = scan(exp, expressionChildFeatures);
            Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        }
        
        try {
        	expressionFeatures.setParentChild(expressionFeatures.getParentChild());
			returnAuxFeatures = scan(newClassTree.getClassBody(), expressionFeatures);
			Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
			//returnFeatures.setInnerClasses(expressionFeatures.getInnerClasses() + returnFeatures.getInnerClasses());
        }catch(Exception e) {}
        
        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitAssignment(AssignmentTree assignmentTree, ExpressionFeatures expressionFeatures) {
        
        expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.Assignment);
		expressionFeatures.setSourceCode(assignmentTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 

        ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.AssigmentLHS);
        ReturnFeatures returnAuxFeatures = scan(assignmentTree.getVariable(), expressionChildFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);

        expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.AssigmentRHS);
		returnAuxFeatures = scan(assignmentTree.getExpression(), expressionChildFeatures);
		Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
	       
        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
       
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);  
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitAnnotation(AnnotationTree annotationTree, ExpressionFeatures expressionFeatures)  {
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.Annotation);
		expressionFeatures.setSourceCode(annotationTree.toString());
		expressionFeatures.setDepth(0);
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
		
		for(ExpressionTree exp: annotationTree.getArguments()) {
    		ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.AnnotationsArguments);
        	ReturnFeatures returnAuxFeatures = scan(exp, expressionChildFeatures);
        	Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
    	}

        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	
	@Override
    public ReturnFeatures visitArrayAccess(ArrayAccessTree arrayAccessTree, ExpressionFeatures expressionFeatures)  {
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.ArrayAccess);
		expressionFeatures.setSourceCode(arrayAccessTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
		ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.ArrayAccessExpression);
        ReturnFeatures returnAuxFeatures = scan(arrayAccessTree.getExpression(), expressionChildFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        
        expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.ArrayAccessIndex);
        returnAuxFeatures = scan(arrayAccessTree.getIndex(), expressionChildFeatures);
		Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);

        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitNewArray(NewArrayTree newArrayTree, ExpressionFeatures expressionFeatures)  {
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.NewArray);
		expressionFeatures.setSourceCode(newArrayTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
		TypeFeatures typeChildFeatures = Util.setTypeChildFeatures(expressionFeatures, TypeParent.NewArray, TypeRole.NewArrayType);
        ReturnFeatures returnAuxFeatures = Util.visitors.getVisitorType().scan(newArrayTree.getType(), typeChildFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        
        for(ExpressionTree exp: newArrayTree.getDimensions()) {
        	ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.NewArrayDimension);
        	returnAuxFeatures = scan(exp, expressionChildFeatures);
        	Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        }
        
        if (newArrayTree.getInitializers() != null) {
            for(ExpressionTree exp: newArrayTree.getInitializers()) {
            	ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.NewArrayInitializer);
            	returnAuxFeatures = scan(exp, expressionChildFeatures);
            	Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
            }
        }

        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());
		
        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitTypeCast(TypeCastTree typeCastTree, ExpressionFeatures expressionFeatures)  {
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.CastExpression);
		expressionFeatures.setSourceCode(typeCastTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
		TypeFeatures typeFeatures = Util.setTypeChildFeatures(expressionFeatures, TypeParent.CastExpression, TypeRole.CastType);
        ReturnFeatures returnAuxFeatures = Util.visitors.getVisitorType().scan(typeCastTree.getType(), typeFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        
        ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.CastEncloses);
		returnAuxFeatures = scan(typeCastTree.getExpression(), expressionChildFeatures);
		Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);

        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitInstanceOf(InstanceOfTree instanceOfTree, ExpressionFeatures expressionFeatures)  {
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.InstanceOf);
		expressionFeatures.setSourceCode(instanceOfTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
        ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.InstanceOfExpression);
        ReturnFeatures returnAuxFeatures = scan(instanceOfTree.getExpression(), expressionChildFeatures);
		Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
		
		TypeFeatures typeFeatures = Util.setTypeChildFeatures(expressionFeatures, TypeParent.InstanceOf, TypeRole.InstanceOfType);
        returnAuxFeatures = Util.visitors.getVisitorType().scan(instanceOfTree.getType(), typeFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
		

        //llamada hijos
        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitConditionalExpression(ConditionalExpressionTree conditionalExpressionTree, ExpressionFeatures expressionFeatures)  {
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.ConditionalExpression);
		expressionFeatures.setSourceCode(conditionalExpressionTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
		ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.ConditionalCondition);
        ReturnFeatures returnAuxFeatures = scan(conditionalExpressionTree.getCondition(), expressionChildFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        
        expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.ConditionalThen);
		returnAuxFeatures = scan(conditionalExpressionTree.getTrueExpression(), expressionChildFeatures);
		Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
		
		expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.ConditionalElse);
		returnAuxFeatures = scan(conditionalExpressionTree.getFalseExpression(), expressionChildFeatures);
		Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
		
        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitMemberSelect(MemberSelectTree memberSelectTree, ExpressionFeatures expressionFeatures)  {
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.MemberSelect);
		expressionFeatures.setSourceCode(memberSelectTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
		ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.MemberSelectedExpression);
        ReturnFeatures returnAuxFeatures = scan(memberSelectTree.getExpression(), expressionChildFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
		
        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			e.printStackTrace();
		}
        
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitMemberReference(MemberReferenceTree memberReferenceTree, ExpressionFeatures expressionFeatures)  {
        
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.MemberReference);
		expressionFeatures.setSourceCode(memberReferenceTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
		ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.MemberReferenceQualifierExpression);
        ReturnFeatures returnAuxFeatures = scan(memberReferenceTree.getQualifierExpression(), expressionChildFeatures);
        Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);

        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }

	@Override
    public ReturnFeatures visitMethodInvocation(MethodInvocationTree methodInvocationTree, ExpressionFeatures expressionFeatures)  {
		
		expressionFeatures.setId(Util.getNextNodeId());
		expressionFeatures.setExpressionCategory(ExpressionCategory.MethodInvocation);
		expressionFeatures.setSourceCode(methodInvocationTree.toString());
		
		ReturnFeatures returnFeatures = new ReturnFeatures(); 
        
        ExpressionFeatures expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.MethodInvocationMethodSelect);
        ReturnFeatures returnAuxFeatures = scan(methodInvocationTree.getMethodSelect(), expressionChildFeatures);
		Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
		
		for(ExpressionTree exp: methodInvocationTree.getArguments()) {
			expressionChildFeatures = Util.setExpressionChildFeatures(expressionFeatures, ExpressionRole.MethodInvocationArguments);
			returnAuxFeatures = scan(exp, expressionChildFeatures);
			Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        }
		
		for(Tree typeArg: methodInvocationTree.getTypeArguments()) {
        	TypeFeatures typeFeatures = Util.setTypeChildFeatures(expressionFeatures, TypeParent.MethodInvocation, TypeRole.MethodInvocationTypeArgument);    		
        	returnAuxFeatures = Util.visitors.getVisitorType().scan(typeArg, typeFeatures);
        	Util.updateExpressionFeatures(expressionFeatures, returnFeatures, returnAuxFeatures);
        }

        returnFeatures.setDepth(expressionFeatures.getDepth());

        try {
			Util.databaseService.insertExpression(expressionFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		List<ExpressionChild> expressionChilds = new ArrayList<ExpressionChild>(); 
		expressionChilds.add(expressionFeatures.getExpressionCategory());
		List<Long> expressionChildIds = new ArrayList<Long>(); 
		expressionChildIds.add(expressionFeatures.getId());

        returnFeatures.setExpressionChild(expressionChilds);
        returnFeatures.setExpressionChildId(expressionChildIds);
        returnFeatures.setStatementChild(Util.setStatementChild(expressionFeatures.getExpressionCategory()));
        returnFeatures.setStatementChildId(Util.setStatementChildId(expressionFeatures.getId()));
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitPrimitiveType(PrimitiveTypeTree primitiveTypeTree, ExpressionFeatures expressionFeatures)  {
		TypeFeatures typeFeatures = new TypeFeatures();
        
        typeFeatures.setParentId(expressionFeatures.getId());
        if(expressionFeatures.getExpressionCategory() == ExpressionCategory.CastExpression) {
        	typeFeatures.setParentNode(TypeParent.CastExpression); 
        } else {
        	typeFeatures.setParentNode(TypeParent.InstanceOf); 
        }
        typeFeatures.setParentChild(TypeRole.CastType);
        typeFeatures.setHeight(expressionFeatures.getHeight());
		
        ReturnFeatures returnFeatures = Util.visitors.getVisitorType().visitPrimitiveType(primitiveTypeTree, typeFeatures); 
		return returnFeatures;
    }	
    
    @Override
    public ReturnFeatures visitArrayType(ArrayTypeTree arrayTypeTree, ExpressionFeatures expressionFeatures) {
    	
        
    	TypeFeatures typeFeatures = new TypeFeatures();
        
        typeFeatures.setParentId(expressionFeatures.getId());
        if(expressionFeatures.getExpressionCategory() == ExpressionCategory.CastExpression) {
        	typeFeatures.setParentNode(TypeParent.CastExpression); 
        } else {
        	typeFeatures.setParentNode(TypeParent.InstanceOf); 
        }
        typeFeatures.setParentChild(TypeRole.CastType);
        typeFeatures.setHeight(expressionFeatures.getHeight());
		
        ReturnFeatures returnFeatures = Util.visitors.getVisitorType().visitArrayType(arrayTypeTree, typeFeatures); 
		return returnFeatures;
        
    }
	
	//class, not expression
	@Override
    public ReturnFeatures visitClass(ClassTree classTree, ExpressionFeatures expressionFeatures)  {
		
		ReturnFeatures returnFeatures = new ReturnFeatures();
        
        TypeDefFeatures typeDefFeatures = new TypeDefFeatures();
        typeDefFeatures.setParentId(expressionFeatures.getParentId());
        typeDefFeatures.setInnerClass(true);
        typeDefFeatures.setFileId(0);
        typeDefFeatures.setInnerId(expressionFeatures.getId());
        typeDefFeatures.setHeight(expressionFeatures.getHeight() + 1); //actualizo la altura
        typeDefFeatures.setPackageName(expressionFeatures.getPackageName());
        
        //nested, inner and nested static
	      typeDefFeatures.setNestedClass(true);
	      if (classTree.getModifiers().getFlags().contains(Modifier.STATIC))
	    		typeDefFeatures.setStatic(true);
	      else
	    	  typeDefFeatures.setInnerClass(true);
	      
        returnFeatures = Util.visitors.getVisitorTypeDefs().visitClass(classTree, typeDefFeatures);
        
        returnFeatures.setDepth(expressionFeatures.getDepth());
        return returnFeatures;
    }
	
	@Override
    public ReturnFeatures visitExpressionStatement(ExpressionStatementTree expressionStatementTree, ExpressionFeatures expressionFeatures)  {
    	
        ReturnFeatures returnFeatures = super.visitExpressionStatement(expressionStatementTree, expressionFeatures);
        return returnFeatures;
    }
	
    
}
