package es.uniovi.reflection.patternmining.dao;

import java.io.PrintStream;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

import es.uniovi.reflection.patternmining.features.ExpressionFeatures;
import es.uniovi.reflection.patternmining.features.FieldFeatures;
import es.uniovi.reflection.patternmining.features.FileFeatures;
import es.uniovi.reflection.patternmining.features.MethodFeatures;
import es.uniovi.reflection.patternmining.features.ProgramFeatures;
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.util.Util;

public class ASTNodesInsertionPrintStream extends AbstractASTNodesInsertion {
	private PrintStream out;	
	private static Map<String,Boolean> shows;
	
    public ASTNodesInsertionPrintStream(PrintStream out) {
    	this.out = out;
    	shows = new HashMap<String, Boolean>();
    	shows.put("program",true);
    	shows.put("file",true);
    	shows.put("nodetype",true);
    	shows.put("typedefinition",true);
    	shows.put("fielddefinition",true);
    	shows.put("methoddefinition",true);
    	shows.put("statement",true);
    	shows.put("expression",true);
    	shows.put("type",true);    
    }
   	
	public void insertProgram(ProgramFeatures programFeatures) throws Exception {
        String sql = "INSERT INTO program (program_id, user_id, user_class, classpercentage, interfacepercentage, enumpercentage,"
        		+ "codeinpackages, defaultpackage) "
                + "VALUES " + "(" + programFeatures.getId() + ",'" + programFeatures.getUserID() + "','"
                + programFeatures.getUserClass() + "'," + programFeatures.getClassPercentage() + "," 
                + programFeatures.getInterfacePercentage() + ","
                + programFeatures.getEnumPercentage() + "," + programFeatures.isCodeInPackages() + ","
                + programFeatures.isDefaultPackage() + ");";
	    if(shows.get("program"))
	    	out.println(sql);	    
	}
	
	public long insertFile(FileFeatures fileFeatures) throws Exception{
		long id=this.getNextFileId();
		String sql = "INSERT INTO file (file_id, program_id) VALUES ("+id+","+fileFeatures.getProgramId()+");";
		if(shows.get("file"))
	    	out.println(sql);
		return id;
	}
		
	//Función sincronizada para obtener el máximo id e insertarlo
	public synchronized void insertNodeType (long id, long parentId) throws Exception{				
		String sql = "INSERT INTO nodetype (nodetype_id,parentnode_id) VALUES("+id+","+parentId+");";
        if(parentId == -1)
        	sql = "INSERT INTO nodetype (nodetype_id) VALUES("+id+");";
        if(shows.get("nodetype"))
	    	out.println(sql);   
	}
	
	public void insertTypeDefinition(TypeDefFeatures typeDefFeatures) throws Exception {
	    insertNodeType(typeDefFeatures.getId(),-1);
	    String sql = "INSERT INTO typedefinition (nodetype_id, user_id, user_class, typenodetype, typepublicvisibility, isfinalclass, hasextends, numberannotations, isindefaultpackage,"
        		+ "isabstract, numberimplements,"
        		+ "numbergenerictypes, numbermethods, percentageoverloadedmethods, "
        		+ "numberconstructors, numberfields, numbernestedclasses,"
        		+ "numberstaticnestedclasses, numberinnerclasses,"
        		+ "typenaming, isinnerclass, isstrictfp, staticfieldpercentage, "
        		+ "staticmethodpercentage, numberstaticblocks, file_id,"
        		+ "isstatic, isnestedclass, sourcecode) "
                + "VALUES " + "("+typeDefFeatures.getId() + ",'" + Util.userID + "','" + Util.userClass
                + "','" + typeDefFeatures.getTypeDefinitionCategory() 
                + "'," + typeDefFeatures.isPublic() + ","
                + typeDefFeatures.isFinalClass()+"," + typeDefFeatures.isHasExtends() 
                + "," + typeDefFeatures.getNumberAnnotations() + "," 
                + typeDefFeatures.isInDefaultPackage() + "," + typeDefFeatures.isAbstract() + ","
                + typeDefFeatures.getNumberImplements() + "," 
                + typeDefFeatures.getNumberGenericTypes() + "," 
                + typeDefFeatures.getNumberMethods() + "," 
                + typeDefFeatures.getPercentageOverloadedMethods() + "," 
                + typeDefFeatures.getNumberConstructors() + "," 
                + typeDefFeatures.getNumberFields() + "," + typeDefFeatures.getNumberNestedTypes() 
                + "," + typeDefFeatures.getNumberStaticNestedTypes() + "," 
                + typeDefFeatures.getNumberInnerTypes() + ",'" + typeDefFeatures.getTypeNaming() + "',"
                + typeDefFeatures.isInnerClass() + "," + typeDefFeatures.isStrictFP() 
                + "," + typeDefFeatures.getStaticFieldPercentage() + ","
                + typeDefFeatures.getStaticMethodPercentage() + "," +
                + typeDefFeatures.getNumberStaticBlocks() + "," + Util.fileId
                + "," + typeDefFeatures.isStatic() + "," + typeDefFeatures.isNestedClass() + 
                ",'" + typeDefFeatures.getSourceCode() +"')";
        if(shows.get("typedefinition"))
	    	out.println(sql);
	}

	public void insertFieldDefinition(FieldFeatures fieldFeatures) throws Exception {
		insertNodeType(fieldFeatures.getId(),fieldFeatures.getIdParent());
		String sql = "INSERT INTO fielddefinition (nodetype_id, user_id, "
        		+ "user_class, fieldvisibility, parentnode, isfinal, isstatic, numberannotations,"
        		+ "fieldnaming, initialvalue, type, isvolatile, istransient, sourcecode) "
                + "VALUES " + "("+fieldFeatures.getId() + ",'" + Util.userID + "','" 
        		+ Util.userClass + "','" + fieldFeatures.getFieldVisibility() + "','"
                + fieldFeatures.getParentNode() + "'," + fieldFeatures.isFinal() + ","
                + fieldFeatures.isStatic() + "," + fieldFeatures.getNumberAnnotations() 
                + ",'" + fieldFeatures.getFieldNaming() + "','"
                + fieldFeatures.getInitialValue() + "','"+fieldFeatures.getType() 
                + "',"+fieldFeatures.isVolatile() + ","
                + fieldFeatures.isTransient() + ",'" + fieldFeatures.getSourceCode() +"');";
        if(shows.get("fielddefinition"))
	    	out.println(sql);
	}
	
	public void insertMethodDefinition(MethodFeatures methodFeatures) throws Exception {
        insertNodeType(methodFeatures.getId(),methodFeatures.getIdParent());
        String sql = "INSERT INTO methoddefinition (nodetype_id, user_id, "
        		+ "user_class, methodvisibility, defaultimplementation, isfinal, hasoverride, isstatic,isabstract,isconstructor,numberparameters,numbergenerictypes,"
        		+ "numberthrows, returntype, numberannotations, numberstmts, "
        		+ "methodlocalvars, locvarnaming, methodnaming, numberinnerclasses,"
        		+ "isstrictfp, isnative, issynchronized, numberofoverloaded, "
        		+ "firsttypeparameter_id, secondtypeparameter_id, "
        		+ "thirdtypeparameter_id, returntype_id, sourcecode) "
                + "VALUES (" + methodFeatures.getId() + ",'" + Util.userID + "','" + Util.userClass 
                + "','" + methodFeatures.getMethodVisibility() + "'," 
                + methodFeatures.isDefaultImplementation()+","+methodFeatures.isFinal()+","
        		+ methodFeatures.hasOverride() + "," +methodFeatures.isStatic() 
        		+ ","+methodFeatures.isAbstract() + ","+methodFeatures.isConstructor() + ","
        		+ methodFeatures.getNumberParameters() + "," + methodFeatures.getNumberGenericTypes() 
        		+ "," + methodFeatures.getNumberThrows() + ",'" 
        		+ methodFeatures.getReturnType() + "'," + methodFeatures.getNumberAnnotations() 
        		+ "," + methodFeatures.getNumberStatements() + ","
                + methodFeatures.getMethodLocalVars() + ",'" 
        		+ methodFeatures.getLocVarNaming() + "','"+methodFeatures.getMethodNaming() 
        		+ "'," + methodFeatures.getNumberInnerClasses()
                +","+methodFeatures.isStrictFP() + "," + methodFeatures.isNative() 
                + ","+methodFeatures.isSynchronized() + "," 
                + methodFeatures.getNumberOfOverloaded() + "," + methodFeatures.getFirstTypeParameterId()
                + "," + methodFeatures.getSecondTypeParameterId() + ","
                + methodFeatures.getThirdTypeParameterId() + "," + methodFeatures.getReturnTypeParameterId()
                + ",'" + methodFeatures.getSourceCode() + "');";
        if(shows.get("methoddefinition"))
	    	out.println(sql);
	}
	
	public void insertStatement(StatementFeatures statementFeatures) throws Exception {        
        insertNodeType(statementFeatures.getId(),statementFeatures.getParentId());
        String sql = "INSERT INTO statement (nodetype_id, user_id, user_class,statement_category, firstchild, "
        		+ "secondchild, thirdchild, parentnode, parentchild, height, depth, sourcecode) "
                + "VALUES " + "(" + statementFeatures.getId() + ",'" 
        		+ Util.userID + "','" + Util.userClass + "','"
        		+ statementFeatures.getStatementCategory() + "','" 
        		+ statementFeatures.getFirstChild() +"','"
                + statementFeatures.getSecondChild() + "','" + statementFeatures.getThirdChild() 
                + "','" + statementFeatures.getParentNode() + "','"
        		+ statementFeatures.getParentChild() + "'," + statementFeatures.getHeight() 
        		+ "," + statementFeatures.getDepth() + ",'" + statementFeatures.getSourceCode() +"');";
        if(shows.get("statement"))
	    	out.println(sql);
	}
	
	public void insertExpression(ExpressionFeatures expressionFeatures) throws Exception {
		insertNodeType(expressionFeatures.getId(),expressionFeatures.getParentId());
		String sql = "INSERT INTO expression (nodetype_id, user_id, user_class, expression_category, "
        		+ "firstchild, secondchild, thirdchild, parentnode, "
        		+ "parentchild, height, depth, sourcecode) "
                + "VALUES " + "(" + expressionFeatures.getId() + ",'" + Util.userID + "','" 
        		+ Util.userClass + "','"
        		+ expressionFeatures.getExpressionCategory() + "','" 
        		+expressionFeatures.getFirstChild() + "','"
                + expressionFeatures.getSecondChild() + "','" + expressionFeatures.getThirdChild( ) + "','" 
        		+ expressionFeatures.getParentNode() + "','" + expressionFeatures.getParentChild() + "',"
                + expressionFeatures.getHeight() + "," + expressionFeatures.getDepth() 
                + ",'" + expressionFeatures.getSourceCode() + "');";
        if(shows.get("expression"))
	    	out.println(sql);
	}
	
	public void insertType(TypeFeatures typeFeatures) throws Exception {
	    insertNodeType(typeFeatures.getId(),typeFeatures.getParentId());
	    String sql = "INSERT INTO type (nodetype_id, user_id, user_class, type_category, "
        		+ "primitive, dimensions, generics, height, "
        		+ "parentnode, parentchild, sourcecode) "
                + "VALUES " + "("+typeFeatures.getId() + ",'" 
        		+ Util.userID + "','" + Util.userClass + "','"
        		+ typeFeatures.getTypeCategory() + "'," + typeFeatures.isPrimitive() + "," 
        		+ typeFeatures.getDimensions() + ","
                + typeFeatures.getGenerics() + "," + typeFeatures.getHeight() + ",'"
                + typeFeatures.getParentNode() + "','" + typeFeatures.getParentChild() 
                + "','" + typeFeatures.getSourceCode() + "');";
	    if(shows.get("type"))
	    	out.println(sql);

	}

	@Override
	public void disconnect() throws SQLException {
		// TODO Auto-generated method stub
		
	}
}
