package es.uniovi.reflection.patternmining.util;

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

import javax.lang.model.element.Modifier;

import com.sun.source.tree.ModifiersTree;

import es.uniovi.reflection.patternmining.category.ExpressionCategory;
import es.uniovi.reflection.patternmining.category.ExpressionRole;
import es.uniovi.reflection.patternmining.category.JavaType;
import es.uniovi.reflection.patternmining.category.Others;
import es.uniovi.reflection.patternmining.category.StatementCategory;
import es.uniovi.reflection.patternmining.category.StatementRole;
import es.uniovi.reflection.patternmining.category.TypeCategory;
import es.uniovi.reflection.patternmining.category.TypeParent;
import es.uniovi.reflection.patternmining.category.TypeRole;
import es.uniovi.reflection.patternmining.dao.ASTNodesInsertion;
import es.uniovi.reflection.patternmining.features.ExpressionFeatures;
import es.uniovi.reflection.patternmining.features.MethodFeatures;
import es.uniovi.reflection.patternmining.features.StatementFeatures;
import es.uniovi.reflection.patternmining.features.TypeFeatures;
import es.uniovi.reflection.patternmining.model.ReturnFeatures;
import es.uniovi.reflection.patternmining.model.Visitors;
import es.uniovi.reflection.patternmining.model.interfaces.ExpressionChild;
import es.uniovi.reflection.patternmining.model.interfaces.StatementChild;

public class Util {
	
	public static Visitors visitors = new Visitors();	

	public static ASTNodesInsertion databaseService;
    
    public static String userID;

	public static String userClass;
	
	public static long fileId;
    
	/*///////////////////////////////////////////////////////////////*/
	/*                        List of Enumerations                   */
	/*///////////////////////////////////////////////////////////////*/
	
	public enum NamingSystem {
        Snake_Case, Upper, Lower, Camel_Up, Camel_Low, Constructor, NOT_KNOWN, Anonymous
    }

    public enum Visibility {
        Public, Private, Protected, Package
    }
    
    //Binary: AND CONDITIONAL_AND CONDITIONAL_OR DIVIDE EQUAL_TO GREATER_THAN
    //GREATER_THAN_EQUAL LEFT_SHIFT LESS_THAN LESS_THAN_EQUAL MINUS MULTIPLY
    //NOT_EQUAL_TO NULL_LITERAL PLUS REMAINDER RIGHT_SHIFT UNSIGNED_RIGHT_SHIFT XOR
    
    //Arithmetic (+ - * ...), Comparison (< > <= ...), Logical (&&,|| ...) y Bitwise (>> << ^ ...)
    
    public static ExpressionCategory getBinaryKind(String kind) {
    	switch(kind) {
			case "AND":
				return ExpressionCategory.BitwiseBinary;
			case "CONDITIONAL_AND":
				return ExpressionCategory.LogicalBinary;
			case "CONDITIONAL_OR":
				return ExpressionCategory.LogicalBinary;
			case "OR":
				return ExpressionCategory.BitwiseBinary;
			case "DIVIDE":
				return ExpressionCategory.ArithmeticBinary;
			case "EQUAL_TO":
				return ExpressionCategory.ComparisonBinary;
			case "GREATER_THAN":
				return ExpressionCategory.ComparisonBinary;
			case "GREATER_THAN_EQUAL":
				return ExpressionCategory.ComparisonBinary;
			case "LEFT_SHIFT":
				return ExpressionCategory.BitwiseBinary;
			case "LESS_THAN":
				return ExpressionCategory.ComparisonBinary;
			case "LESS_THAN_EQUAL":
				return ExpressionCategory.ComparisonBinary;
			case "MINUS":
				return ExpressionCategory.ArithmeticBinary;
			case "MULTIPLY":
				return ExpressionCategory.ArithmeticBinary;
			case "NOT_EQUAL_TO":
				return ExpressionCategory.ComparisonBinary;
			case "PLUS":
				return ExpressionCategory.ArithmeticBinary;
			case "REMAINDER":
				return ExpressionCategory.ArithmeticBinary;
			case "RIGHT_SHIFT":
				return ExpressionCategory.BitwiseBinary;
			case "UNSIGNED_RIGHT_SHIFT":
				return ExpressionCategory.BitwiseBinary;
			case "CONDITIONAL_XOR":
				return ExpressionCategory.LogicalBinary;
			case "XOR":
				return ExpressionCategory.BitwiseBinary;
		}
    	return ExpressionCategory.None;
    }
    
    
    //Unary: BITWISE_COMPLEMENT LOGICAL_COMPLEMENT POSTFIX_DECREMENT POSTFIX_INCREMENT
    //PREFIX_DECREMENT PREFIX_INCREMENT UNARY_MINUS UNARY_PLUS
 
    //Arithmetic, PrefixIncrement, PostIncrement, PrefixDecrement, PostfixDecrement, Bitwise y Logical
    
    
    public static String getUnaryKind(String kind) {
		switch(kind) {
			case "POSTFIX_DECREMENT":
				return "PostfixDecrementUnary";
			case "PREFIX_DECREMENT":
				return "PrefixDecrementUnary";
			case "POSTFIX_INCREMENT":
				return "PostfixIncrementUnary";
			case "PREFIX_INCREMENT":
				return "PrefixIncrementUnary";
			case "LOGICAL_COMPLEMENT":
				return "LogicalUnary";
			case "BITWISE_COMPLEMENT":
				return "BitwiseUnary";
			case "UNARY_MINUS":
				return "ArithmeticUnary";
			case "UNARY_PLUS":
				return "ArithmeticUnary";
		}
		return "NONE";
    	
    }
    
    public enum NodeType{
    	Class, Interface, Enum
    }
    
    
    /*///////////////////////////////////////////////////////////////*/
	/*                   		Literal Tree                         */
	/*///////////////////////////////////////////////////////////////*/
    
    public static ExpressionCategory getLiteralKind (String kind) {
    		switch(kind) {
    			case "NULL_LITERAL":
    				return ExpressionCategory.NullLiteral;
    			case "INT_LITERAL":
    				return ExpressionCategory.IntLiteral;
    			case "STRING_LITERAL":
    				return ExpressionCategory.StringLiteral;
    			case "DOUBLE_LITERAL":
    				return ExpressionCategory.DoubleLiteral;
    			case "CHAR_LITERAL":
    				return ExpressionCategory.CharLiteral;
    			case "LONG_LITERAL":
    				return ExpressionCategory.LongLiteral;
    			case "FLOAT_LITERAL":
    				return ExpressionCategory.FloatLiteral;
    			case "SHORT_LITERAL":
    				return ExpressionCategory.ShortLiteral;
    			case "BOOLEAN_LITERAL":
    				return ExpressionCategory.BooleanLiteral;
    		}
		return ExpressionCategory.None;
    	
    }
    
	
	/*///////////////////////////////////////////////////////////////*/
	/*                       Returns Naming Type:					 */ 
	/* 				lower, UPPER, camelLow, CamelUp, snake_case      */
	/*///////////////////////////////////////////////////////////////*/
	

    public static NamingSystem getNamingCovention(String name) { 
    	if ("".equals(name)) return NamingSystem.Anonymous;
        if (name.matches("[A-Z0-9ÁÉÍÓÚÑ_]+$")) return NamingSystem.Upper;
        if (name.matches("[a-z0-9áéíóúñ_]+$")) return NamingSystem.Lower;
        if (name.matches("[A-ZÁÉÍÓÚÑ][A-Za-z0-9áéíóúñÁÉÍÓÚÑ]+$")) return NamingSystem.Camel_Up;
        if (name.matches("[a-záéíóúñ][A-Za-z0-9áéíóúñÁÉÍÓÚÑ]+$")) return NamingSystem.Camel_Low;
        if (name.matches("[A-Za-z0-9_áéíóúñÁÉÍÓÚÑ]+$")) return NamingSystem.Snake_Case;
        return NamingSystem.NOT_KNOWN;
        
    }
    
    /*
     public static NamingSystem getNamingCovention(String name) {
        if (name.matches("[A-Za-z0-9_]+$")) return NamingSystem.SNAKE_CASE;
        if (name.matches("[A-Z0-9]+$")) return NamingSystem.UPPER;
        if (name.matches("[a-z0-9]+$")) return NamingSystem.LOWER;
        if (name.matches("[A-Z][A-Za-z0-9]+$")) return NamingSystem.CAMEL_UP;
        if (name.matches("[a-z][A-Za-z0-9]+$")) return NamingSystem.CAMEL_LOW;
        return NamingSystem.NOT_KNOWN;
    }*/
    
    /*///////////////////////////////////////////////////////////////*/
	/*                   Returns the method visibility               */
	/*///////////////////////////////////////////////////////////////*/

    public static Visibility getVisibility(ModifiersTree mods) {
        if (mods.getFlags().contains(Modifier.PUBLIC)) return Visibility.Public;
        if (mods.getFlags().contains(Modifier.PRIVATE)) return Visibility.Private;
        if (mods.getFlags().contains(Modifier.PROTECTED)) return Visibility.Protected;
        return Visibility.Package;
    }
    
    /*///////////////////////////////////////////////////////////////*/
	/*                 		Get the type_category		             */ 
	/*///////////////////////////////////////////////////////////////*/
    
    public static JavaType getTypeCategory(String type) {
    	if(type.equals("INT")) return JavaType.Int;
    	else if(type.equals("DOUBLE")) return JavaType.Double;
    	else if(type.equals("BOOLEAN")) return JavaType.Boolean;
    	else if(type.equals("String")) return JavaType.String;
    	else if(type.equals("BYTE")) return JavaType.Byte;
    	else if(type.equals("CHAR")) return JavaType.Char;
    	else if(type.equals("SHORT")) return JavaType.Short;
    	else if(type.equals("LONG")) return JavaType.Long;
    	else if(type.equals("FLOAT")) return JavaType.Float;
    	else return JavaType.Reference;
    }
    
    public static TypeCategory getTypeFromCategory(JavaType type) {
    	if(type.equals(JavaType.Int)) return TypeCategory.Int;
    	else if(type.equals(JavaType.Double)) return TypeCategory.Double;
    	else if(type.equals(JavaType.Boolean)) return TypeCategory.Boolean;
    	else if(type.equals(JavaType.String)) return TypeCategory.String;
    	else if(type.equals(JavaType.Byte)) return TypeCategory.Byte;
    	else if(type.equals(JavaType.Char)) return TypeCategory.Char;
    	else if(type.equals(JavaType.Short)) return TypeCategory.Short;
    	else if(type.equals(JavaType.Long)) return TypeCategory.Long;
    	else if(type.equals(JavaType.Float)) return TypeCategory.Float;
    	else return TypeCategory.Reference;
    }

    
    /*///////////////////////////////////////////////////////////////*/
	/*             Database access to get NodeType IDs               */
	/*///////////////////////////////////////////////////////////////*/
    
    
    
    public synchronized static long getNextNodeId() { // ?synchronized
    	return databaseService.getNextNodeId();
    }
    
    public synchronized static long getNextFileId() { // ?synchronized
    	return databaseService.getNextFileId();
    }
    
    public synchronized static long getNextProgramId() { // ?synchronized
    	return databaseService.getNextProgramId();
    }
    
    /*///////////////////////////////////////////////////////////////*/
	/*             Statement child features update                   */
	/*///////////////////////////////////////////////////////////////*/
    
    public static StatementFeatures setStatementChildFeatures(StatementFeatures statementParentFeatures, StatementRole statementRole) {
        
    	StatementFeatures statementFeatures = new StatementFeatures();
    	
        statementFeatures.setParentId(statementParentFeatures.getId());
        statementFeatures.setParentNode(statementParentFeatures.getStatementCategory());
        statementFeatures.setParentChild(statementRole);
        statementFeatures.setPackageName(statementParentFeatures.getPackageName());
   
        statementFeatures.setHeight(statementParentFeatures.getHeight() + 1);
        
        return statementFeatures;
    }
    
    public static StatementFeatures setStatementChildFeatures(ExpressionFeatures expressionParentFeatures, StatementRole statementRole) {
        
    	StatementFeatures statementFeatures = new StatementFeatures();
    	
        statementFeatures.setParentId(expressionParentFeatures.getId());
        statementFeatures.setParentNode(expressionParentFeatures.getExpressionCategory());
        statementFeatures.setParentChild(statementRole);
        statementFeatures.setPackageName(expressionParentFeatures.getPackageName());
   
        statementFeatures.setHeight(expressionParentFeatures.getHeight() + 1);
        
        return statementFeatures;
    }
    
    /*///////////////////////////////////////////////////////////////*/
	/*             Expression child features update                  */
	/*///////////////////////////////////////////////////////////////*/
    
    public static ExpressionFeatures setExpressionChildFeatures(ExpressionFeatures expressionParentFeatures, ExpressionRole expressionRole) {
        
    	ExpressionFeatures expressionFeatures = new ExpressionFeatures();
    	
        expressionFeatures.setParentId(expressionParentFeatures.getId());
        expressionFeatures.setParentNode(expressionParentFeatures.getExpressionCategory());
        expressionFeatures.setParentChild(expressionRole);
        expressionFeatures.setPackageName(expressionParentFeatures.getPackageName());
        
        expressionFeatures.setHeight(expressionParentFeatures.getHeight() + 1);
        
        return expressionFeatures;
    }
    
    public static ExpressionFeatures setExpressionChildFeatures(StatementFeatures statementParentFeatures, ExpressionRole expressionRole) {
        
    	ExpressionFeatures expressionFeatures = new ExpressionFeatures();
    	
        expressionFeatures.setParentId(statementParentFeatures.getId());
        expressionFeatures.setParentNode(statementParentFeatures.getStatementCategory());
        expressionFeatures.setParentChild(expressionRole);
        expressionFeatures.setPackageName(statementParentFeatures.getPackageName());
       
        expressionFeatures.setHeight(statementParentFeatures.getHeight() + 1);
        
        return expressionFeatures;
    }
    
    /*///////////////////////////////////////////////////////////////*/
	/*                   Expression features update                  */
	/*///////////////////////////////////////////////////////////////*/
    
    public static TypeFeatures setTypeChildFeatures(StatementFeatures statementParentFeatures, TypeParent typeParent, TypeRole typeRole) {
    	
    	TypeFeatures typeFeatures = new TypeFeatures();
        
    	typeFeatures.setId(Util.getNextNodeId());
    	typeFeatures.setParentId(statementParentFeatures.getId());
    	typeFeatures.setParentNode(typeParent);
    	typeFeatures.setParentChild(typeRole);
        
    	typeFeatures.setHeight(statementParentFeatures.getHeight() + 1);
    	
    	return typeFeatures;
    }
    
    public static TypeFeatures setTypeChildFeatures(ExpressionFeatures expressionParentFeatures, TypeParent typeParent, TypeRole typeRole) {
    	
    	TypeFeatures typeFeatures = new TypeFeatures();
        
    	typeFeatures.setId(Util.getNextNodeId());
    	typeFeatures.setParentId(expressionParentFeatures.getId());
    	typeFeatures.setParentNode(typeParent);
    	typeFeatures.setParentChild(typeRole);
        
    	typeFeatures.setHeight(expressionParentFeatures.getHeight() + 1);
    	
    	return typeFeatures;
    }
    
    public static void setTypeChildFeatures(TypeFeatures typeParentFeatures, TypeRole typeRole) {
    	
    	TypeFeatures typeFeatures = new TypeFeatures();
        
    	typeFeatures.setId(Util.getNextNodeId());
    	typeFeatures.setParentId(typeParentFeatures.getId());
    	//typeFeatures.setParentNode(typeParentFeatures.getTypeCategory());
    	typeFeatures.setParentChild(typeRole);
        
    	typeFeatures.setHeight(typeParentFeatures.getHeight() + 1);
    }
    
    public static void updateStatementFeatures(StatementFeatures statementFeatures, ReturnFeatures returnFeatures, ReturnFeatures returnAuxFeatures) {
    	if(returnAuxFeatures != null) {
    		//child
        	try {
        		for (StatementChild statementChilds : returnAuxFeatures.getStatementChild()) {
        			if(statementFeatures.getFirstChild() == StatementCategory.None) statementFeatures.setFirstChild(statementChilds);
                    else if(statementFeatures.getSecondChild() == StatementCategory.None) statementFeatures.setSecondChild(statementChilds);
                    else if(statementFeatures.getThirdChild() == StatementCategory.None) statementFeatures.setThirdChild(statementChilds); 
        		}
             	/*for (ExpressionChild expressionChilds : returnAuxFeatures.getExpressionChild()) {
        			if(statementFeatures.getFirstChild() == ExpressionCategory.None) statementFeatures.setFirstChild((StatementChild) expressionChilds);
                    else if(statementFeatures.getSecondChild() == ExpressionCategory.None) statementFeatures.setSecondChild((StatementChild) expressionChilds);
                    else if(statementFeatures.getThirdChild() == ExpressionCategory.None) statementFeatures.setThirdChild((StatementChild) expressionChilds); 
        	    }*/
	        } catch(Exception e) {};
	        
	        try {
        		for (long id : returnAuxFeatures.getStatementChildId()) {
        			if(statementFeatures.getFirstChildId() == 0) statementFeatures.setFirstChildId(id);
                    else if(statementFeatures.getSecondChildId() == 0) statementFeatures.setSecondChildId(id);
                    else if(statementFeatures.getThirdChildId() == 0) statementFeatures.setThirdChildId(id); 
        		}
             	/*for (long id : returnAuxFeatures.getExpressionChildId()) {
        			if(statementFeatures.getFirstChildId() == 0) statementFeatures.setFirstChildId(id);
                    else if(statementFeatures.getSecondChildId() == 0) statementFeatures.setSecondChildId(id);
                    else if(statementFeatures.getThirdChildId() == 0) statementFeatures.setThirdChildId(id); 
        	    }*/
	        } catch(Exception e) {};
	        	
        	//Updating down depth
    		if(returnAuxFeatures.getDownDepth() + 1 > statementFeatures.getDepth()) {
    			statementFeatures.setDepth(returnAuxFeatures.getDownDepth() + 1);
    			returnFeatures.setDepth(returnAuxFeatures.getDownDepth() + 1);
    	    }
    	
        	returnFeatures.setNumberOfStatements(returnFeatures.getNumberOfStatements() + returnAuxFeatures.getNumberOfStatements());
    		returnFeatures.setMethodLocalVars(returnFeatures.getMethodLocalVars() + returnAuxFeatures.getMethodLocalVars());
    		returnFeatures.setMethodTypeId(returnAuxFeatures.getMethodTypeId());
    		returnFeatures.setMethodParameterType(returnAuxFeatures.getMethodParameterType());
    		
    		for (int i = 0; i < returnFeatures.getTotalsArrayVariableNaming().length; i++){
    		    // aqui se puede referir al objeto con arreglo[i];
    			returnFeatures.setTotalsArrayVariableNaming(i, returnFeatures.getTotalsArrayVariableNaming()[i] + returnAuxFeatures.getTotalsArrayVariableNaming()[i]);
    		}
    		
    		returnFeatures.setNumberOfClasses(returnFeatures.getNumberOfClasses() + returnAuxFeatures.getNumberOfClasses());
    		returnFeatures.setNumberOfInnerTypes(returnFeatures.getNumberOfInnerTypes() + returnAuxFeatures.getNumberOfInnerTypes());
        	returnFeatures.setNumberOfStaticNestedTypes(returnFeatures.getNumberOfStaticNestedTypes() + returnAuxFeatures.getNumberOfStaticNestedTypes());
    	}

    }
    
    public static void updateBlockStatementFeatures(StatementFeatures statementFeatures, ReturnFeatures returnFeatures, ReturnFeatures returnAuxFeatures) {
        
    	if(returnAuxFeatures != null) {
    		//child
        	try {
        		for (StatementChild statementChilds : returnAuxFeatures.getStatementChild()) {
        			if(statementFeatures.getFirstChild() == StatementCategory.None) statementFeatures.setFirstChild(statementChilds);
                    else if(statementFeatures.getSecondChild() == StatementCategory.None) statementFeatures.setSecondChild(statementChilds);
                    else if(statementFeatures.getThirdChild() == StatementCategory.None) statementFeatures.setThirdChild(statementChilds); 
        		}
	        } catch(Exception e) {};
	        
	        try {
        		for (long id : returnAuxFeatures.getStatementChildId()) {
        			if(statementFeatures.getFirstChildId() == 0) statementFeatures.setFirstChildId(id);
                    else if(statementFeatures.getSecondChildId() == 0) statementFeatures.setSecondChildId(id);
                    else if(statementFeatures.getThirdChildId() == 0) statementFeatures.setThirdChildId(id); 
        		}
	        } catch(Exception e) {};
	        
	        statementFeatures.setDepth(returnAuxFeatures.getDownDepth());
	        returnFeatures.setDepth(returnAuxFeatures.getDownDepth());
    	
        	returnFeatures.setNumberOfStatements(returnFeatures.getNumberOfStatements() + returnAuxFeatures.getNumberOfStatements());
    		returnFeatures.setMethodLocalVars(returnFeatures.getMethodLocalVars() + returnAuxFeatures.getMethodLocalVars());

    		for (int i = 0; i < returnFeatures.getTotalsArrayVariableNaming().length; i++){
    		    // aqui se puede referir al objeto con arreglo[i];
    			returnFeatures.setTotalsArrayVariableNaming(i, returnFeatures.getTotalsArrayVariableNaming()[i] + returnAuxFeatures.getTotalsArrayVariableNaming()[i]);
    		}
    		
    		returnFeatures.setNumberOfClasses(returnFeatures.getNumberOfClasses() + returnAuxFeatures.getNumberOfClasses());
    		returnFeatures.setNumberOfInnerTypes(returnFeatures.getNumberOfInnerTypes() + returnAuxFeatures.getNumberOfInnerTypes());
        	returnFeatures.setNumberOfStaticNestedTypes(returnFeatures.getNumberOfStaticNestedTypes() + returnAuxFeatures.getNumberOfStaticNestedTypes());
    	}

    }


	/*///////////////////////////////////////////////////////////////*/
	/*             Expression child features update                  */
	/*///////////////////////////////////////////////////////////////*/
    
    public static void updateExpressionFeatures(ExpressionFeatures expressionFeatures, ReturnFeatures returnFeatures, ReturnFeatures returnAuxFeatures) {
    	
    	if(returnAuxFeatures != null) {
    		//child
            try {
            	for (ExpressionChild expressionChilds : returnAuxFeatures.getExpressionChild()) {
        			if(expressionFeatures.getFirstChild() == ExpressionCategory.None) expressionFeatures.setFirstChild(expressionChilds);
                    else if(expressionFeatures.getSecondChild() == ExpressionCategory.None) expressionFeatures.setSecondChild(expressionChilds);
                    else if(expressionFeatures.getThirdChild() == ExpressionCategory.None) expressionFeatures.setThirdChild(expressionChilds); 
        	    }
	         } catch(Exception e) {}
            
            try {
            	for (long id : returnAuxFeatures.getExpressionChildId()) {
        			if(expressionFeatures.getFirstChildId() == 0) expressionFeatures.setFirstChildId(id);
                    else if(expressionFeatures.getSecondChildId() == 0) expressionFeatures.setSecondChildId(id);
                    else if(expressionFeatures.getThirdChildId() == 0) expressionFeatures.setThirdChildId(id); 
        	    }
	         } catch(Exception e) {}
            
        	if(returnAuxFeatures.getDownDepth() + 1 > expressionFeatures.getDepth()) {
        		expressionFeatures.setDepth(returnAuxFeatures.getDownDepth() + 1);
        		returnFeatures.setDepth(returnAuxFeatures.getDownDepth() + 1);
    	    }
            
            returnFeatures.setNumberOfStatements(returnAuxFeatures.getNumberOfStatements());
    		returnFeatures.setMethodLocalVars(returnAuxFeatures.getMethodLocalVars());

    		for (int i = 0; i < returnFeatures.getTotalsArrayVariableNaming().length; i++){
    		    // aqui se puede referir al objeto con arreglo[i];
    			returnFeatures.setTotalsArrayVariableNaming(i, returnFeatures.getTotalsArrayVariableNaming()[i] + returnAuxFeatures.getTotalsArrayVariableNaming()[i]);
    		}
    		
    		returnFeatures.setNumberOfClasses(returnFeatures.getNumberOfClasses() + returnAuxFeatures.getNumberOfClasses());
    		returnFeatures.setNumberOfInnerTypes(returnFeatures.getNumberOfInnerTypes() + returnAuxFeatures.getNumberOfInnerTypes());
        	returnFeatures.setNumberOfStaticNestedTypes(returnFeatures.getNumberOfStaticNestedTypes() + returnAuxFeatures.getNumberOfStaticNestedTypes());
    	}
    	
    }
    
    /*///////////////////////////////////////////////////////////////*/
	/*                 		Update type parameters                   */
	/*///////////////////////////////////////////////////////////////*/
    
    public static void updateTypeParameterFeatures(MethodFeatures methodFeatures, ReturnFeatures returnAuxFeatures) {
        
    	if(returnAuxFeatures != null) {
        	try {
        		if(methodFeatures.getFirstTypeParameterId() == 0) methodFeatures.setFirstTypeParameterId(returnAuxFeatures.getMethodTypeId());
                else if(methodFeatures.getSecondTypeParameterId() == 0) methodFeatures.setSecondTypeParameterId(returnAuxFeatures.getMethodTypeId());
                else if(methodFeatures.getThirdTypeParameterId() == 0) methodFeatures.setThirdTypeParameterId(returnAuxFeatures.getMethodTypeId()); 	
	        } catch(Exception e) {};
	        
	        try {
        		if(methodFeatures.getFirstParameterType() == Others.None) methodFeatures.setFirstParameterType(returnAuxFeatures.getMethodParameterType());
                else if(methodFeatures.getSecondParameterType() == Others.None) methodFeatures.setSecondParameterType(returnAuxFeatures.getMethodParameterType());
                else if(methodFeatures.getThirdParameterType() == Others.None) methodFeatures.setThirdParameterType(returnAuxFeatures.getMethodParameterType()); 	
	        } catch(Exception e) {};
    	}

    }
    
    /*///////////////////////////////////////////////////////////////*/
	/*                   Expression features update                  */
	/*///////////////////////////////////////////////////////////////*/
    
    public static void updateTypeFeatures(TypeFeatures typeParentFeatures, TypeRole typeRole) {
    	
    	TypeFeatures typeFeatures = new TypeFeatures();
        
    	typeFeatures.setId(Util.getNextNodeId());
    	typeFeatures.setParentId(typeParentFeatures.getId());
    	//typeFeatures.setParentNode(typeParentFeatures.getTypeCategory());
    	//typeFeatures.setParentChild(typeParentFeatures.getParentChild());
        
    	typeFeatures.setHeight(typeParentFeatures.getHeight() + 1);
    }
    
    /*///////////////////////////////////////////////////////////////*/
	/*                 Method return features update                 */
	/*///////////////////////////////////////////////////////////////*/

	public static void updateMethodFeatures(ReturnFeatures returnMethodFeatures,
			ReturnFeatures returnMethodFeaturesAux) {
		try {
			returnMethodFeatures.setNumberOfStatements(returnMethodFeatures.getNumberOfStatements() + returnMethodFeaturesAux.getNumberOfStatements());
			returnMethodFeatures.setMethodLocalVars(returnMethodFeatures.getMethodLocalVars() + returnMethodFeaturesAux.getMethodLocalVars());
			for(int i=0;i<5;i++) {
				//returnMethodFeatures.localVarStat[i] += returnMethodFeaturesAux.localVarStat[i];
			}
		}catch(Exception e) {
			
		}
		
	}
	
	/*///////////////////////////////////////////////////////////////*/
	/*                    	 Number #.##			                 */
	/*///////////////////////////////////////////////////////////////*/
	
	public static double roundOut(double numero,int digitos)
	{
	      int cifras=(int) Math.pow(10,digitos);
	      return Math.rint(numero*cifras)/cifras;
	}
	
	/*///////////////////////////////////////////////////////////////*/
	/*                     Return type by name			             */
	/*///////////////////////////////////////////////////////////////*/

	static Map<String,NodeType> namesMap=new HashMap<String,NodeType>();
	public static List <MethodFeatures> methodsWithoutReturn = new ArrayList<MethodFeatures>();
	
	public static void setReturnName(String typeDefSimpleName, NodeType typeNodeType) {
		namesMap.put(typeDefSimpleName,typeNodeType); 
	}
	
	public static String getNodeSourceCode(String name) {
		if (name.indexOf("{") != -1) {
			return name.substring(0, name.indexOf("{"));
		} 
		return name.substring(0, name.indexOf(";"));
	}
	
	public static String prepareSourceCode(String sourceCode) {
		
    	if (sourceCode == null) {
    		return ""; 
    	}
    	
    	if (sourceCode.length() == 3) {
    		sourceCode = sourceCode.replace('\'', '"');
    	} else {
        	sourceCode = sourceCode.replace("'", "");
        	sourceCode = sourceCode.replaceAll("\"", "");
        	sourceCode = sourceCode.replaceAll("\'", "");
        	
        	if (sourceCode.length() > 30000) {
        		sourceCode = sourceCode.substring(0, 30000);
        	}
    	}
    	
    	return sourceCode;
    }
	
	/*///////////////////////////////////////////////////////////////*/
	/*                      		Childs		                     */
	/*///////////////////////////////////////////////////////////////*/
	
	public static List<StatementChild> setStatementChild(StatementChild statementCategory) {
		List<StatementChild> statementChilds = new ArrayList<StatementChild>(); 
    	statementChilds.add(statementCategory);
    	return statementChilds;
	}
	
	public static List<Long> setStatementChildId(long id) {
		List<Long> statementChildIds = new ArrayList<Long>();  
		statementChildIds.add(id);
    	return statementChildIds;
	}
   
}
