package de.dhbwstuttgart.strucTypes;

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

import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.Field;
import de.dhbwstuttgart.syntaxtree.Method;




public class Algo_Type {



	private Object result_cl_t; 
	private List<TC_Abstract> result_constraint_set; 
		
	
	public Algo_Type(List<AS_Abstract>  ass, ClassOrInterface cl) {
		
		this.result_constraint_set = new ArrayList<TC_Abstract>(); 
		
		// =:fass
		List<AS_Field> fass = make_field_assumptions(cl);
		
		// =: mass
		List<AS_Method> mass = make_method_assumptions(cl); 	
				
		// -> AssAll =  ass + fass + mass 
		List<AS_Abstract> assAll = new ArrayList<AS_Abstract>(); 
		assAll.addAll(fass); 
		assAll.addAll(mass);
		assAll.addAll(ass); 
		// TODO: AssAll + this: A  für die aktuelle Klasse
		
		
		
		// -> AssGlobal = fass + mass + Assumption der Methode
		List<AS_Abstract> assGlobal = new ArrayList<>(); 
		assGlobal.addAll(assAll); 
		
		
				
		// -> For (m_strich) {return e; } Element Methoden 
		//List<AS_Argument> ass_arguments = new ArrayList<AS_Argument>();  
		for (Method m : cl.getMethods()) {
			
			// -> Ass = AssAll u  { .... 
			// Neue Liste sodass die Argumente der Methode nur für diese gelten
			List<AS_Abstract> ass2 = new ArrayList<AS_Abstract>(); 
			ass2.addAll(assAll); 
 			for (int i = 0; i < m.getParameterList().getFormalparalist().size() ; i++ ) { 
			   AS_Argument as_argument = new AS_Argument(m.getParameterList().getFormalparalist().get(i), i , m , cl );
			   ass2.add(as_argument); 
			} 						
 			assGlobal.addAll(ass2); 
			
			// -> (e_typed, C'  = TypeExpre(Ass,e) )
			Algo_TypeExpr algo = new Algo_TypeExpr(ass2, m.get_Block().getStatements());
			System.out.println("getypte expression: "+   algo.res_expression_typed);			
		}
		
		// ASS = AssAll vereinigt mit ass_arguments  (wird oben erledigt) 
		
		
		
		// (Test) Beispielhafte Ausgabe der Assumptions 
	    for (AS_Abstract as : assGlobal ) {
				System.out.println(as.toString()); 
		}
	    
	    
	    // TEST: Ausgabe des Code
	    System.out.println("Code: ");
	    System.out.println(CodeGenerator.generateClass(cl, assGlobal));
		
		
		// TypeExpression muss noch ausgeführt werden
		// TypeExpression (insert Types and collects corrospending constraints) 
	    List<TC_Abstract> constraints  = Algo_TypeExpr.generateConstraint(cl, assGlobal); 
	    System.out.println("Constraints generiert"); 
	    for (TC_Abstract tc  : constraints ) {	    	
	    	System.out.println(tc.toString()); 
	    	// Hier ist ein Fehler -> der Contraint bezieht sich auf die Expression
	    }
	    
			    
	    
	
	}
	
	
	//  =:fass 
	private List<AS_Field> make_field_assumptions(ClassOrInterface cl) {	
		
		List<AS_Field> fass = new ArrayList<AS_Field>();  			
					
			for (Field f : cl.getFieldDecl() ) {				
				AS_Field as_f = new AS_Field(cl, f) ;	
				fass.add(as_f);  				
			}				
		return fass; 
	}
	
	// =:mass 
	private List<AS_Method> make_method_assumptions(ClassOrInterface cl) {
		
		List<AS_Method> mass = new ArrayList<AS_Method>(); 
			
			for(Method m : cl.getMethods() ) {
				AS_Method as_m = new AS_Method(cl,m); 
				mass.add(as_m); 				
			}		
		return mass; 
	}
	
	
	
	
	// Gettermethoden	
	public Object getResult_cl_t() {
		return result_cl_t;
	}


	public List<TC_Abstract> getResult_constraint_set() {
		return result_constraint_set;
	}

	
	
	
	
		
	
	
	
	
	
	
	
	
	
	

}
