// ino.module.SourceFile.8722.package 
package de.dhbwstuttgart.syntaxtree;
// ino.end

// ino.module.SourceFile.8722.import 
import java.io.IOException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;

import de.dhbwstuttgart.typeinference.Menge;

import java.util.stream.Stream;

import de.dhbwstuttgart.logger.Logger;
import de.dhbwstuttgart.logger.Section;
import de.dhbwstuttgart.core.AClassOrInterface;
import de.dhbwstuttgart.core.MyCompiler;
import de.dhbwstuttgart.myexception.CTypeReconstructionException;
import de.dhbwstuttgart.myexception.JVMCodeException;
import de.dhbwstuttgart.myexception.SCClassException;
import de.dhbwstuttgart.myexception.SCException;
import de.dhbwstuttgart.parser.JavaClassName;
import de.dhbwstuttgart.syntaxtree.misc.DeclId;
import de.dhbwstuttgart.syntaxtree.misc.UsedId;
import de.dhbwstuttgart.syntaxtree.modifier.Modifiers;
import de.dhbwstuttgart.syntaxtree.modifier.Public;
import de.dhbwstuttgart.syntaxtree.type.FunN;
import de.dhbwstuttgart.syntaxtree.type.GenericTypeVar;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.Type;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.syntaxtree.type.Void;
import de.dhbwstuttgart.typeinference.ByteCodeResult;
import de.dhbwstuttgart.typeinference.ConstraintsSet;
import de.dhbwstuttgart.typeinference.FunNInterface;
import de.dhbwstuttgart.typeinference.FunNMethod;
import de.dhbwstuttgart.typeinference.Pair;
import de.dhbwstuttgart.typeinference.ResultSet;
import de.dhbwstuttgart.typeinference.TypeinferenceResultSet;
import de.dhbwstuttgart.typeinference.TypeinferenceResults;
import de.dhbwstuttgart.typeinference.UndConstraint;
import de.dhbwstuttgart.typeinference.assumptions.ClassAssumption;
import de.dhbwstuttgart.typeinference.assumptions.MethodAssumption;
import de.dhbwstuttgart.typeinference.assumptions.ParameterAssumption;
import de.dhbwstuttgart.typeinference.assumptions.TypeAssumptions;
import de.dhbwstuttgart.typeinference.exceptions.DebugException;
import de.dhbwstuttgart.typeinference.exceptions.TypeinferenceException;
import de.dhbwstuttgart.typeinference.unify.FC_TTO;
import de.dhbwstuttgart.typeinference.unify.Unifier;
import de.dhbwstuttgart.typeinference.unify.Unify;




// ino.class.SourceFile.21355.declaration 
public class SourceFile
 extends SyntaxTreeNode
// ino.end
// ino.class.SourceFile.21355.body
{
    // ino.attribute.LOAD_BASIC_ASSUMPTIONS_FROM_JRE.21358.decldescription type=javadoc
    /**
     * @autor HOTI 
     * Dieses Flag bestimmt, ob die basicAssumptions (Integer, Menge, ...) direkt von
     * der Java-Laufzeitumgebung anhand der Imports oder von den "Fixed Hacks" geladen 
     * werden (Mit Fixed Hacks sind die von Hand eingetragene Basetypes gemeint)
     */
    // ino.end
    // ino.attribute.LOAD_BASIC_ASSUMPTIONS_FROM_JRE.21358.declaration 
    private static final boolean LOAD_BASIC_ASSUMPTIONS_FROM_JRE = true;
    // ino.end
    
    // ino.attribute.READ_OBJECT_SUPERCLASSES_FROM_JRE.21361.decldescription type=javadoc
    /**
     * @autor HOTI
     * Wenn dieses Flag auf <b>true</b> gesetzt ist, wird immer als Superklasse Object 
     * mit rein geladen. Dies hat natürlich zur Folge, dass man in der GUI jeden Typ   
     * auswählen muss, weil ALLES in Java von Object erbt. Sobald die GUI das über eine
     * Checkbox o.ä. ausblendbar macht kann es aktiviert werden. Ebenso beeinflusst es 
     * die superclass von allen Class-Objekten. (Wenn true ist jede Class automatisch  
     * wenn nicht anders eingegeben Subclass von Object (Wie es sein muss))
     */
    // ino.end
    // ino.attribute.READ_OBJECT_SUPERCLASSES_FROM_JRE.21361.declaration 
    public static final boolean READ_OBJECT_SUPERCLASSES_FROM_JRE = false;
    // ino.end
    
    // ino.attribute.READ_BASE_TYPE_SUPERCLASSES_FROM_JRE.21364.decldescription type=javadoc
    /**
     * Wenn dieses Flag auf <b>false</b> ist, werden für alle Basisklassen (definiert  
     * durch die Hashtable baseTypeTranslationTable) KEINE Superklassen geladen. D.h.  
     * Integer hat bspw. nicht die Superklasse Number sondern OBJECT.
     * Dies verursacht bei den Int-Operationen ein Problem
     * (+,-,*,/,<,>,...) 
     */
    // ino.end
    // ino.attribute.READ_BASE_TYPE_SUPERCLASSES_FROM_JRE.21364.declaration 
    private static final boolean READ_BASE_TYPE_SUPERCLASSES_FROM_JRE = false;
    // ino.end
    
    /**
     * @autor PL
     * Wenn dieses Flag auf <b>false</b> ist, werden für alle importierten Klassen
     * KEINE Superklassen geladen.  
     */
    private static final boolean READ_IMPORTED_SUPERCLASSES_FROM_JRE = false;
    
    // ino.attribute.codegenlog.21367.decldescription type=line
    // Logger fuer Code-Gen
    // ino.end
    // ino.attribute.codegenlog.21367.declaration 
    protected static Logger codegenlog = Logger.getLogger("codegen");
    // ino.end
    // ino.attribute.inferencelog.21370.declaration 
    protected static Logger inferencelog = Logger.getLogger("inference");
    // ino.end
    
    // ino.attribute.pkgName.21373.declaration 
    private UsedId pkgName;
    // ino.end
    
    // ino.attribute.KlassenVektor.21376.declaration 
    public Menge<Class> KlassenVektor = new Menge<Class>();
    // ino.end
    
    // ino.attribute.InterfaceVektor.21379.declaration 
    public Menge<Interface> InterfaceVektor = new Menge<Interface>();
    // ino.end
    
    
    /**
     * Die SourceFile repräsntiert eine zu einem Syntaxbaum eingelesene Java-Datei.
     * SourceFile stellt dabei den Wurzelknoten des Syntaxbaumes dar.
     */
    public SourceFile(){
    	// HOTI 4.5.06
        // Base-Type-Translations anlegen (siehe kommentar BaseTypeTranslationTable)
        baseTypeTranslationTable=new Hashtable<String,String>();
        baseTypeTranslationTable.put("int","java.lang.Integer");
        baseTypeTranslationTable.put("char","java.lang.Character");
        baseTypeTranslationTable.put("boolean","java.lang.Boolean");
        baseTypeTranslationTable.put("double","java.lang.Double");
        baseTypeTranslationTable.put("long","java.lang.Long");
        baseTypeTranslationTable.put("float","java.lang.Float");
        //baseTypeTranslationTable.put("this.is.a.temporary.entry","de.dhbwstuttgart.typeinference.Menge"); auskommentiert PL 07-08-11
        
        
        this.imports=new ImportDeclarations();
        
        this.imports.add(UsedId.createFromQualifiedName("java.lang.Integer",-1));
        this.imports.add(UsedId.createFromQualifiedName("java.lang.String",-1));
        this.imports.add(UsedId.createFromQualifiedName("java.lang.Character",-1));
        this.imports.add(UsedId.createFromQualifiedName("java.lang.Boolean",-1));
        this.imports.add(UsedId.createFromQualifiedName("java.lang.Double",-1));
        this.imports.add(UsedId.createFromQualifiedName("java.lang.Float",-1));
        this.imports.add(UsedId.createFromQualifiedName("java.lang.Long",-1));
        //this.imports.add(UsedId.createFromQualifiedName("java.lang.Byte"));       
        
        // HOTI 4.5.06 Wenn die Klassen immer als "Daddy" Object haben,
        // muss das der JCC auch kennen
        if(READ_OBJECT_SUPERCLASSES_FROM_JRE){
            this.imports.add(UsedId.createFromQualifiedName("java.lang.Object",-1));                    
        }
    }
    
    public SourceFile(Menge<Class> classDefinitions) {
    	this.KlassenVektor = classDefinitions;
	}

	// ino.attribute.imports.21382.decldescription type=javadoc
    /**
     * HOTI 4.5.06
     * Beinhaltet alle Imports des aktuell geparsten Files
     * in Form einer UsedId 
     */
    // ino.end
    // ino.attribute.imports.21382.declaration 
    private ImportDeclarations imports=new ImportDeclarations();
    // ino.end
    // ino.attribute.baseTypeTranslationTable.21385.decldescription type=javadoc
    /**
     * Table zum Übersetzen der nicht implementierten Base-Types:
     * Überall im Compiler wird statt bspw. int Integer verwendet
     * d.h. 1+2 liefert ein Integer
     * Deshalb benötigen wir hier eine Tabelle, mit der man die von
     * der JRE gelieferten Base-Typen (int,char, etc) und die Objekt-
     * Typen umwandeln können 
     */
    // ino.end
    // ino.attribute.baseTypeTranslationTable.21385.declaration 
    private Hashtable<String,String> baseTypeTranslationTable;
    // ino.end
    

    
    
    // ino.method.addElement.21394.defdescription type=javadoc
    /**
     * Fuegt ein neues Element (Interface oder Klasse) hinzu.
     * @param c
     */
    // ino.end
    // ino.method.addElement.21394.definition 
    public void addElement(AClassOrInterface e)
    // ino.end
    // ino.method.addElement.21394.body 
    {
        if (e instanceof Class) {
            KlassenVektor.addElement((Class) e);
        } else if (e instanceof Interface) {
            InterfaceVektor.addElement((Interface) e);
        }
    }
    // ino.end
    
    
    
    // ino.method.codegen.21397.defdescription type=javadoc
    /**
     * Startet die Bytecodegenerierung fuer alle in der Datei
     * enthaltenen Klassen und Interfaces.
     * 
     
    // ino.end
    // ino.method.codegen.21397.definition 
    public Menge<ClassFile> codegen(ResultSet result)
    throws JVMCodeException
    // ino.end
    // ino.method.codegen.21397.body 
    {
    	Menge<ClassFile> ret = new Menge<ClassFile>();
        codegenlog.info("Anzahl der Interfaces: " 
                + Integer.toString(InterfaceVektor.size()));
        for(int i = 0; i < InterfaceVektor.size(); i++) {
            InterfaceVektor.elementAt(i).codegen(result);
        }
    
        codegenlog.info("Anzahl der Klassen: " 
                + Integer.toString(KlassenVektor.size()));
        for(int i = 0; i < KlassenVektor.size(); i++) {
            ret.add(KlassenVektor.elementAt(i).codegen(result));
        }
		return ret;
    }
    // ino.end
     */
    // ino.method.createPairFromClassAndSuperclass.21400.defdescription type=javadoc
    /**
     * Erstellt ein Typ-Paar, welches im 1. Durchlauf in die Menge der Finite Closure  
     * aufgenommen wird Input: Klassenname, Name der Superklasse, ParameterDerKlasse,  
     * Parameter der Superklasse 
     * @return
     */
    // ino.end
    // ino.method.createPairFromClassAndSuperclass.21400.definition 
    private Pair createPairFromClassAndSuperclass(Class baseClass, Type superclass, Menge classParaOrg, Menge superclassParaOrg, TypeAssumptions ass)
    // ino.end
    // ino.method.createPairFromClassAndSuperclass.21400.body 
    {
        // Paar erstellen
        if(classParaOrg!=null && classParaOrg.size()==0){
            classParaOrg=null;
        }
        if(superclassParaOrg!=null && superclassParaOrg.size()==0){
            superclassParaOrg=null;
        }
        /*
        Pair P = new Pair(                  
                new RefType( className.toString(), classParaOrg,-1),
                new RefType( superclassName.toString(), superclassParaOrg,-1) 
                         );
        */
        Pair P = new Pair(baseClass.getType().TYPE(ass, baseClass), superclass.TYPE(ass, baseClass));
        //PL 04-12-29 freshe Variablen ANFANG
        RefType r1 = (RefType)P.getTA1Copy();
        RefType r2 = (RefType)P.getTA2Copy();
        r1 = (RefType) r1.TYPE(ass, baseClass);
        r2 = (RefType) r2.TYPE(ass, baseClass);
        // #JB# 05.04.2005
        // ###########################################################
        Hashtable<JavaClassName,Type> substHash = new Hashtable<JavaClassName,Type>(); //fuer jedes Paar komplett neue Variablen
        Unify.varSubst(r1, substHash);
        Unify.varSubst(r2, substHash);
        // ###########################################################
        P = new Pair(r1, r2);
        //PL 04-12-29 freshe Variablen ENDE
    
        //HIER AUSKOMMENTIERT, SOLLTE MAN AM ENDE WIEDER DAZU NEHMEN PL 04-12-28
        // gleiches Paar aufnehmen
        //vFC.add( new Pair( P.getTA1Copy(), P.getTA1Copy() ) );
        
        return(P);
        
    }
    // ino.end
    // ino.method.makeFC.21403.defdescription type=javadoc
    /**
     * Erstellt die Finite Closure
     * @return FC_TTO-Object, welches die Finite Closure repräsentiert
     */
    public FC_TTO makeFC( TypeAssumptions ass )
    {
        
        // Menge FC bilden
        
        Menge<Pair> vFC = new Menge<Pair>(); // Menge FC
        TypeAssumptions globalAssumptions = this.makeBasicAssumptionsFromJRE(imports, false);
        globalAssumptions.add(this.getPublicFieldAssumptions());
        // 1. Menge <= in FC aufnehmen --> Iteration ueber alle Klassen
        
        Menge<Type> ignoreTypes = new Menge<>(); //Enthält die Typen, welche nicht in der FC als Supertypen enthalten sein sollen.
        ignoreTypes.add(new RefType("Long",null,-1).TYPE(globalAssumptions, parent));
        ignoreTypes.add(new RefType("Float",null,-1).TYPE(globalAssumptions, parent));
        ignoreTypes.add(new RefType("Double",null,-1).TYPE(globalAssumptions, parent));
        ignoreTypes.add(new RefType("String",null,-1).TYPE(globalAssumptions, parent));
        ignoreTypes.add(new RefType("Integer",null,-1).TYPE(globalAssumptions, parent));
        ignoreTypes.add(new RefType("Object",null,-1).TYPE(globalAssumptions, parent));
        
        Menge<Class> basicAssumptionsClassMenge = new Menge<>(); //die Klassen aus den BasicAssumptions und den Importierten Klassen
        for(ClassAssumption cAss : ass.getClassAssumptions()){
        	Type t1 = cAss.getAssumedClass().getType();
        	Type t2 = cAss.getAssumedClass().getSuperClass();
        	if(t2 != null){
        	Pair p = new Pair(t1, t2);
        	//System.out.println("FCPair: "+p);
        	if(! t1.equals(t2)){//Um FC_TTO darf kein T <. T stehen.
        		Type superTypeFromAssumptions = ass.getTypeFor(t2, t2); //In den Assumptions den SuperTyp nachschlagen
        		if(superTypeFromAssumptions != null && ! ignoreTypes.contains(superTypeFromAssumptions)){//Die Superklasse eines Typs nur anfügen, wenn er auch in den Assumptions vorkommt.
        			vFC.add(p);
        		}
        		basicAssumptionsClassMenge.add(cAss.getAssumedClass());//Klasse ohne die Superklasse anfügen
        	}else{
        		//System.out.println("Wurde nicht aufgenommen");
        	}
        	}
        }
        
        for( int i = 0; i < KlassenVektor.size(); i++ )
        {
            Class tempKlasse = KlassenVektor.elementAt(i);
            inferencelog.debug("Verarbeite "+tempKlasse.getName(), Section.TYPEINFERENCE);
            //TODO: SuperKlasse erstellen, dies sollte am besten beim Konstruktoraufruf von Class geschehen. Diese kann dann mit getSuperClass abgefragt werden.
            if( tempKlasse.superclassid != null ) {  // Klasse hat Superklasse
                Pair P=createPairFromClassAndSuperclass(tempKlasse,tempKlasse.getSuperClass(),tempKlasse.get_ParaList(),tempKlasse.superclassid.get_ParaList(), globalAssumptions);
                vFC.add( P );
            }
            if(tempKlasse.getSuperInterfaces()!=null){
                Iterator<Type> interfaceIterator=tempKlasse.getSuperInterfaces().iterator();
                while(interfaceIterator.hasNext()){
                    RefType intf=(RefType) interfaceIterator.next();
                    Pair P=createPairFromClassAndSuperclass(tempKlasse,intf,tempKlasse.get_ParaList(),intf.get_ParaList(),globalAssumptions);
                    vFC.add( P );
                    
                }
            }
        } // Schleifenende durch Klassenvektor
        for(int i=0; i<InterfaceVektor.size();i++){
            Interface intf= InterfaceVektor.get(i);
            if(intf.getSuperInterfaces()!=null){
                Iterator<Type> interfaceIterator=intf.getSuperInterfaces().iterator();
                while(interfaceIterator.hasNext()){
                    RefType superintf=(RefType) interfaceIterator.next();
                    Pair P=createPairFromClassAndSuperclass(intf,superintf,intf.getParaList(), superintf.get_ParaList(),globalAssumptions);
                    vFC.add( P );
                    
                }
            }
        }
        Menge tto = (Menge)vFC.clone(); 
    
        Unify.printMenge( "FC", vFC, 6 );
        /* z.B.
        *******************************
        Menge FC = {
        (Vektor< A >, Vektor< A >),
        (Vektor< A >, AbstractList< A >),
        (Matrix< A >, Matrix< A >),
        (Matrix< A >, Vektor< Vektor< A > >),
        (ExMatrix< A >, ExMatrix< A >),
        (ExMatrix< A >, Matrix< A >) }
        *******************************
    
                ODER 
    
        *******************************
        Menge FC = {
        (BB< A >, BB< A >),
        (BB< A >, CC< A >),
        (AA< A, B >, AA< A, B >),
        (AA< A, B >, BB< DD< B, A > >) }
        *******************************
    
        */        
    
        // 2. Regel 2 der Huellendefinition "eingeschraenkt" anwenden
        // d.h. sinnvolle Substitutionen suchen (nicht alle)
        
        boolean bPaarHinzu = true;
        while( bPaarHinzu )
        {
            bPaarHinzu = false; //PL 04-12-29 nur wenn hinzugefuegt auf true setzen
            // konkret: rechte Seite von FC nach Typkonstruktoren in der Parameterliste durchsuchen
            for( int n = 0; n < vFC.size(); n++ )
            {
                // Elemente in FC k�nnen nur Pair's sein --> Cast ohne Abfrage
                Pair PTypKonst = vFC.elementAt(n);
                
                // Parameter des rechten Typausdrucks des betrachteten Paars extrahieren
                Menge<Type> vPara = ((RefType)(PTypKonst.TA2)).get_ParaList();
                Integer Subst = null; // Substitution
                int nSubstStelle = 0;
                inferencelog.debug("nSubstStelleStart" + nSubstStelle + " " + n, Section.FINITECLOSURE);
                
                // Parameter durchlaufen und nach Typkonstruktor suchen
                // #JB# 17.05.2005
                // ###########################################################
                if(vPara!=null){
                // ###########################################################
                    for( ; nSubstStelle < vPara.size(); nSubstStelle++ )
                    {
                        inferencelog.debug("nSubstStelle" + nSubstStelle, Section.FINITECLOSURE);
                        if( vPara.elementAt(nSubstStelle) instanceof RefType && ((RefType)vPara.elementAt(nSubstStelle)).get_ParaList() != null )
                        {
                            // Typkonstruktor gefunden -> wird nun als Substitution verwendet
                            Subst = 1;//new RefType( (RefType)vPara.elementAt(nSubstStelle) ,-1);
                            inferencelog.debug( "Ausgangstyp:" + ((RefType)PTypKonst.TA2).getName() , Section.FINITECLOSURE);
                            inferencelog.debug( "RefType = " + ((RefType)vPara.elementAt(nSubstStelle)).getName() , Section.FINITECLOSURE);
                        break; // Einschraenkung - nur fuer ein RefType wird eine Substitution gesucht
                        }
                    }
                // ###########################################################
                }
                // ###########################################################
                if( Subst != null )
                {
                    // Rechter Typ hat einen Typkonstruktor --> sinvolles neues Paar bilden
                    // d.h. Rechter Typ auf linker Paarseite suchen
                    // System.out.println("Subststelle = " + nSubstStelle );
    
                    for( int t = 0; t < vFC.size(); t++ )
                    {
                        Pair PSuchen = vFC.elementAt(t);
                        if( ((RefType)(PTypKonst.TA2)).getTypeName().equals( ((RefType)PSuchen.TA1).getTypeName() ) )
                        {
                            inferencelog.debug(" gefundener Typ links: " + ((RefType)(PSuchen.TA1)).getName(), Section.FINITECLOSURE ); 
                            inferencelog.debug(" gefundener Typ rechts: " + ((RefType)(PSuchen.TA2)).getName() , Section.FINITECLOSURE); 
                            // Paar gefunden, das als linken Typ den gleichen Typen enth�lt, der als Parameter einen Typkonstruktor hat
                            // Substitution
                            //Pair P = new Pair( PSuchen.getTA1Copy( ), PSuchen.getTA2Copy( ) );
                //linker Typterm bleibt gleich
                //rechter Typterm wird aussen auf den Supertyp gesetzt.
                //restliches FC erfolgt ueber die Transitivitaet
                //siehe im unteren Teil
                            Pair P = new Pair( PTypKonst.getTA1Copy( ), PSuchen.getTA2Copy( ) );
                            // System.out.println(" Subst " + Subst.getName() );
                            // System.out.println(" Vor: P = " + P.toString() + P.TA1 );
                            // System.out.println(" Vor: PSuchen = " + PSuchen.toString() + PSuchen.TA1 );
                            
                            // Parameter, der substituiert wird, sollte TV sein ???
                            //TypePlaceholder TV = null;
                            // if( ((RefType)P.TA1).isTV( nSubstStelle ) )
    //                                 try
    //                                 {
    //                                     TV = new TypePlaceholder( ((RefType)P.TA1).getParaN( nSubstStelle ) );
    //                                 }
    //                                 catch( Exception E )
    //                                 {
    //                                     continue;
    //                                 }
    //                             else
    //                                 continue;
    
                //es werden alle Parameter in einem Typeterm, der
                //der Argumente hat ersetzt PL 04-12-28
                Hashtable<JavaClassName,Type> hts = new Hashtable<JavaClassName,Type>();
                //for(int u = nSubstStelle; u < vPara.size(); u++) {
                for(int u = 0; u < vPara.size(); u++) {
                try {
                    // #JB# 05.04.2005
                    // ###########################################################
                    //TV = new TypePlaceholder( ((RefType)PSuchen.TA1).getParaN(u) );
                    //System.out.println("TV_Name: " + u + TV.Type2String());
                    // ###########################################################
                    inferencelog.debug("Typterm_Name: " + vPara.elementAt(u), Section.FINITECLOSURE);
                    inferencelog.debug("Typterm_Name: " + ((Type)vPara.elementAt(u)).Type2String(), Section.FINITECLOSURE);
                    hts.put(new JavaClassName(((RefType)PSuchen.TA1).getParaN(u)), vPara.elementAt(u));
                 }
                 catch( Exception E ) {
                     inferencelog.error(E.getMessage(), Section.FINITECLOSURE);
                     //FIXME Throw Exception or Error instead of exiting!
                     System.exit(0);
                 }
                    
            //  Subst( P, 
    //                     2, 
    //                     TV,
    //                     new RefType( (RefType)vPara.elementAt(u) ), 
    //                     false ); // rechte Seite substituieren
                //Es genuegt die rechte Seite zu substituieren, da
                //die linke Seite ein Typterm ausschlie�lich mit 
                //Typvariablen ist
                }
                //Unify.SubstHashtableGeneric(((RefType)P.TA1), hts); //funktioniert nicht
                Unify.SubstHashtableGeneric(((RefType)P.TA2), hts); //funktioniert nicht
                            // System.out.println(" TV!!!= " + TV.getName() );
                            //Subst( P, 1, TV, Subst, false ); // linke Seite substituieren
                            //Subst( P, 2, TV, Subst, false ); // rechte Seite substituieren
                            // System.out.println(" nach Subst: P = " + P.toString() );
                            // System.out.println(" Nach: PSuchen = " + PSuchen.toString() );
                            // System.out.println(" Nach: " + P.toString() );
    
                            // Paar einfuegen, falls noch nicht vorhanden
                            // System.out.println("Paar alt:" + PSuchen.toString() );
                            // System.out.println("Paar neu:" + P.toString() );
                            if( !P.isInMenge( vFC ) )
                            {
                                vFC.add( P );
                 Unify.printMenge( "FC", vFC, 6 );
                                bPaarHinzu = true;
                            }
                //PL 04-12-29
                            // else   //unnoetig, da am Anfang bereits false gesetzt
    //                             {
    //                                 bPaarHinzu = false;
    //                             }
                            
                        }
                    }                
                } // end if: Substitution gefunden???
            } // end for: Typkonstruktor suchen
            
    
            // Transitivitaet berechnen      
            for( int u = 0; u < vFC.size(); u++ )
            {
                Pair PTemp = vFC.elementAt(u);
                
                // falls rechtes Paar = RefType
                if( PTemp.TA2 instanceof RefType )
                {
                    RefType R = (RefType)PTemp.TA2;
                    
                    // rechte Seite auf linker Seite suchen
                    for( int e = 0; e < vFC.size(); e++ )
                    {
                        Pair PSuch = vFC.elementAt(e);
                        // als linke Paarseite theortisch nur RefType's moeglich --> Cast
                        RefType RSuch = (RefType)PSuch.TA1;
                        
                        //if( R.getName().equals(RSuch.getName()) ) 
            if (R.is_Equiv(RSuch, new Hashtable<JavaClassName,Type>()))   //eingefuegt PL 05-01-07
                {
                // Paar einfuegen, falls noch nicht vorhanden
                RefType L1 = (RefType)PTemp.getTA1Copy();
                RefType L2 = (RefType)PTemp.getTA2Copy();
                RefType R1 = (RefType)PSuch.getTA1Copy();
                RefType R2 = (RefType)PSuch.getTA2Copy();
    
                //zunaechst Variablen disjunkt machen ANFANG
                // #JB# 05.04.2005
                // ###########################################################
                Hashtable<JavaClassName,Type> substHash1 = new Hashtable<JavaClassName,Type>();
                Unify.varSubst(L1, substHash1);
                Unify.varSubst(L2, substHash1);
                Hashtable<JavaClassName,Type> substHash2 = new Hashtable<JavaClassName,Type>();
                Unify.varSubst(R1, substHash2);
                Unify.varSubst(R2, substHash2);
                // ###########################################################
                //zunaechst Variablen disjunkt machen ENDE
    
                //Variablen so umbennen, dass transitiver Abschluss richtige
                //Namen hat ANFANG
                
                // #JB# 05.04.2005
                // ###########################################################
                Hashtable<JavaClassName,Type> h = new Hashtable<JavaClassName,Type>();
                L2.Equiv2Equal(R1, h);
                Hashtable<JavaClassName,Type> substHash3 = h;
                Unify.varSubst(L1, substHash3);
                Unify.varSubst(R2, substHash3);
                // ###########################################################
                //Variablen so umbennen, dass transitiver Abschluss richitge
                //Namen hat ENDE
    
                //Pair P = new Pair( (RefType)PTemp.TA1, (RefType)PSuch.TA2 );
                Pair P = new Pair(L1, R2);
                if( !P.isInMenge( vFC ) )
                    {
                    vFC.add( P );
                    bPaarHinzu = true;
                    }
                else
                    {
                    bPaarHinzu = false;
                    }
                }
                    } // end for: linke Seite suchen
                } // end if: Element ist RefType
            } // end for: Transitivit�ten berechnen
        //PL HIER REFLEXIVE HUELLE EINFUEGEN
        // 05-01-07
            
        } // Ende WHILE
    
        /* z.B.
        *******************************
        Menge nach trans: FC = {
        (Vektor< A >, Vektor< A >),
        (Vektor< A >, AbstractList< A >),
        (Matrix< A >, Matrix< A >),
        (Matrix< A >, Vektor< Vektor< A > >),
        (ExMatrix< A >, ExMatrix< A >),
        (ExMatrix< A >, Matrix< A >),
        (Vektor< Vektor< A > >, Vektor< Vektor< A > >),
        (Vektor< Vektor< A > >, AbstractList< Vektor< A > >),
        (Matrix< A >, AbstractList< Vektor< A > >),
        (ExMatrix< A >, Vektor< Vektor< A > >),
        (ExMatrix< A >, AbstractList< Vektor< A > >) }
        
            ODER
            
        *******************************
        Menge nach trans: FC = {
        (BB< A >, BB< A >),
        (BB< A >, CC< A >),
        (AA< A, B >, AA< A, B >),
        (AA< A, B >, BB< DD< B, A > >),
        (BB< DD< B, A > >, BB< DD< B, A > >),
        (BB< DD< B, A > >, CC< DD< B, A > >),
        (AA< A, B >, CC< DD< B, A > >) }
        *******************************
    
        *******************************        */
        
        
        // printMenge( "nach trans: FC", vFC, 6 );
        
        Menge<Class> KlassenVektorunImportierteKlassen = new Menge<>();
        KlassenVektorunImportierteKlassen.addAll(basicAssumptionsClassMenge);
        KlassenVektorunImportierteKlassen.addAll(KlassenVektor);
        
    FC_TTO fctto = new FC_TTO(vFC, tto, KlassenVektorunImportierteKlassen);
    return fctto;
    }
    
    public TypeAssumptions getPublicFieldAssumptions(){
    	TypeAssumptions publicAssumptions = new TypeAssumptions(null);
    	//Alle PublicAssumptions der in dieser SourceFile enthaltenen Klassen sammeln:
    	for(Class klasse : KlassenVektor){
    		publicAssumptions.add(klasse.getPublicFieldAssumptions());
        }
    	return publicAssumptions;
    }
    
    /////////////////////////////////////////////////////////////////////////
    // TypeReconstructionAlgorithmus
    /////////////////////////////////////////////////////////////////////////
    // ino.method.typeReconstruction.21406.defdescription type=javadoc
    /**
     * Tyrekonstruktionsalgorithmus: ruft f�r jede Klasse den Algorithmus TRProg auf.
     * Dessen Ergebnismenge A, die Menge aller Typannahmen, f�r eine Klasse dient als
     * Eingabe f�r TRProg der n�chsten Klasse. Am Ende enth�lt A alle m�glichen
     * Typkombinationen f�r alle Klassen zusammen.
     * <br>Author: J�rg B�uerle
     * @return Liste aller m�glichen Typkombinationen
     * @throws CTypeReconstructionException Wenn was schief l�uft
     */
    // ino.end
    // ino.method.typeReconstruction.21406.definition 
    public Menge<TypeinferenceResultSet> typeReconstruction(TypeAssumptions globalAssumptions)
    throws CTypeReconstructionException
    // ino.end
// ino.method.typeReconstruction.21406.body 
{
    	Menge<TypeinferenceResultSet> ret = new Menge<TypeinferenceResultSet>();
    	
    	//Logger initialisieren:
    	Logger typinferenzLog = Logger.getLogger("Typeinference");
    	
    	//Alle Assumptions für diese SourceFile sammeln:
    	for(Class klasse : this.KlassenVektor){
    		globalAssumptions.add(klasse.getPublicFieldAssumptions());
    	}
    	
    	//Assumptions der importierten Klassen sammeln:
    	TypeAssumptions importAssumptions = this.makeBasicAssumptionsFromJRE(imports, true);
    	globalAssumptions.add(importAssumptions);
    	typinferenzLog.debug("Von JRE erstellte Assumptions: "+importAssumptions, Section.TYPEINFERENCE);
    	
    	//FiniteClosure generieren:
    	FC_TTO finiteClosure = this.makeFC(globalAssumptions);
    	
    	typinferenzLog.debug("FiniteClosure: \n"+finiteClosure, Section.TYPEINFERENCE);
    	
    	ConstraintsSet oderConstraints = new ConstraintsSet();
    	//Alle Constraints der in dieser SourceFile enthaltenen Klassen sammeln:
        for(Class klasse : KlassenVektor){
        	oderConstraints.add(klasse.typeReconstruction(finiteClosure, globalAssumptions));
        }
        
        ////////////////
        //Karthesisches Produkt bilden:
        ////////////////
        
        //Unmögliche ConstraintsSets aussortieren durch Unifizierung
        Unifier unifier = (pairs)->{
        	Menge<Menge<Pair>> retValue = new Menge<>();
        	retValue = Unify.unify(pairs, finiteClosure);
        	return retValue;};
        //oderConstraints.filterWrongConstraints(unifier);
        	
        //oderConstraints.unifyUndConstraints(unifier); //rausgeworfen für Tests (08.12.2015)
        
        typinferenzLog.debug("Übriggebliebene Konstraints:\n"+oderConstraints+"\n", Section.TYPEINFERENCE);
        //Die Constraints in Pair's umwandeln (Karthesisches Produkt bilden):
        Menge<Menge<Pair>> xConstraints = oderConstraints.cartesianProduct();
   
        typinferenzLog.debug("Karthesisches Produkt der Constraints: "+xConstraints, Section.TYPEINFERENCE);
        
        finiteClosure.generateFullyNamedTypes(globalAssumptions);
        
        //////////////////////////////
        // Unifizierung der Constraints:
        //////////////////////////////
    	boolean unifyFail = true;
        for(Menge<Pair> constraints : xConstraints){
        	//Alle durch das Karthesische Produkt entstandenen Möglichkeiten durchgehen:
            Menge<Menge<Pair>> result = new Menge<Menge<Pair>>();
            
            //Alle FunN-Typen werden per clone-methode in RefTypes verwandelt. (Die clone Methode in FunN darf nicht überschrieben werden.
            for(Pair p : constraints){
            	if(p.TA1 instanceof FunN){
            		p.TA1 = p.TA1.clone();
            	}
            	if(p.TA2 instanceof FunN){
            		p.TA2 = p.TA2.clone();
            	}
            }
            
            //Erst die Unifizierung erstellen:
            Menge<Pair> constraintsClone = (Menge<Pair>)constraints.clone();
            
          //IDEE: Man bildet Zusammenhangskomponenten von Paaren, die gemeinsame Variablen haben
          //      und unifizert nur die Zusammenhangskomponenten in Schritten 1 - 5
            
          //Schritt 1: Alle Variablen in den Paaren von Elementen einsammeln
          Menge<Menge<TypePlaceholder>> constraintsclonevars = constraintsClone.stream().map(p -> {Menge<TypePlaceholder> TPHs = new Menge<>(); 
            TPHs.addAll(p.TA1.getInvolvedTypePlaceholder());
            TPHs.addAll(p.TA2.getInvolvedTypePlaceholder());
            return TPHs;}
            ).collect(Menge::new, Menge::add, Menge::addAll);    	

          //Schritt 2: Schnittmengen jedes Elements mit jedem Elememt von vars bilden und dann index zusammenfassen
          //in indexset sind dann die Mengen von Indizes enthalten, die gemeisam unifiziert wreden müssen
        	Menge<Menge<Integer>> indexeset = new Menge<>();
        	if (constraintsclonevars != null && constraintsclonevars.size()>0) { 
        		indexeset = Unify.schnitt(constraintsclonevars);
        	}
        	
        	//Schritt 3: Umwandlung der Indizes in die zugehoerigen Elemente
        	//           In streamconstraintsclone sind die Mengen von Paar enthalten die unifiziert werden muessen
        	Stream<Menge<Pair>> streamconstraintsclone = indexeset.stream().map(x -> x.stream()
        			                                                           .map(i -> constraintsClone.elementAt(i))
        			                                                               .<Menge<Pair>>collect(Menge::new, Menge::add, Menge::addAll));
       	//Menge<Menge<Pair>> vecconstraintsclone = streamconstraintsclone.collect(Menge::new, Menge::add, Menge::addAll);
            //System.out.println();
        	//Schritt 4: Unifikation  
        	Menge<Menge<Menge<Pair>>> vecunifyResult =
        			//streamconstraintsclone.map(x -> Unify.unify(x, finiteClosure)).collect(Menge::new, Menge::add, Menge::addAll);
        			//DEBUG-Variante
        			streamconstraintsclone.map(x -> 
        			  	{ 	Menge<Menge<Pair>> z = Unify.unify(x, finiteClosure);
        					return z;
        			  	}
        					).collect(Menge::new, Menge::add, Menge::addAll);
        			  	
        	
        	//card gibt die Cardinalitaet der unifizierten Mengen an
        	Menge<Integer> card = vecunifyResult.stream().map(x -> x.size()).collect(Menge::new, Menge::add, Menge::addAll);
        			;//.reduce(1,(a,b) -> { if ((a > 0) && (b > 0)) return (a * b); else return 1; });
        			
            //Schritt 5: Bildung des cartesischen Produkts
            //sollte wieder entfernt werden: Weiterarbeit mit: 
        	//[[x_1 -> t_1, x_2 -> t2], [x_1 -> t'_1, x_2 -> t'_2]] x ... x [[x_n -> t_1n], [x_n -> t2n], [x_n -> t3n]] 
        	Menge<Menge<Pair>> cardprodret_start = new Menge<>();
        	cardprodret_start.add(new Menge<Pair>());
        	
        	//cart. Produkt mit Linkverschiebung
        	Menge<Menge<Pair>> unifyResult = vecunifyResult.stream().reduce(cardprodret_start, (x, y) -> {
        		Menge<Menge<Pair>> cardprodret= new Menge<>();
        		if (y.size() > 0) {
        			//System.out.println(y);
        			//Menge<Menge<Pair>> cardprodretold = x;
					//cardprodret = new Menge<>();
					for(int j = 0; j < x.size(); j++) {
						for (int k = 0; k < y.size(); k++){
							Menge<Pair> help = new Menge<>(); 
							help.addAll(y.elementAt(k));
							help.addAll(x.elementAt(j));
							cardprodret.add(help);
						}
					}
        		}
        		else 
        			return new Menge<>(); //kein unifiziertes Ergebnis, damit wird das Geseamtergebnis []
        		return cardprodret;
        	});
        	
        	//Dann den Ergebnissen anfügen
        	typinferenzLog.debug("\nErgebnis der Unifizierung:\n"+unifyResult, Section.TYPEINFERENCE);
            result.addAll(unifyResult);
        
	        typinferenzLog.debug("\nJavaFiles:\n", Section.TYPEINFERENCE);
	        
	        //typinferenzLog.debug(this.printJavaCode(new ResultSet(new Menge<Pair>())));
	        
	
	        //Für jede Klasse in diesem SourceFile gilt das selbe ResultSet:
	        for(Class klasse : this.KlassenVektor){
	        	//Der Unifikationsalgorithmus kann wiederum auch mehrere Lösungen errechnen, diese werden im folgenden durchlaufen:
		        for(Menge<Pair> resultSet : result){
		        	unifyFail = false; //Ein Unifiziertes Ergebnis ist entstanden (es kann auch leer sein, das bedeutet nur, dass die Constraints mindestens in einem Fall Sinn ergaben)
		        	//Add Result set as a new ReconstructionResult to ret:
		        	TypeinferenceResultSet reconstructionResult = new TypeinferenceResultSet(klasse, constraints, new ResultSet(resultSet));
		        	ret.add(reconstructionResult);
		        	
		        	//ResultSet res = new ResultSet(resultSet);
		        	typinferenzLog.debug("JavaFile für ResultSet "+reconstructionResult+"\n", Section.TYPEINFERENCE);
		        	typinferenzLog.debug(klasse.printJavaCode(reconstructionResult), Section.TYPEINFERENCE);
		        	
		        }
	        }
        }
        if(unifyFail){
        	if(!this.KlassenVektor.isEmpty())throw new TypeinferenceException("Fehler in Typinferierung", this.KlassenVektor.firstElement());   	
        }
        return ret;
    }
    
    /**
     * Erstellt die Assumptions der standardmäßig importierten Packages (java.lang.) sowie der von imports übergebenen Klassen zusammen.
     * @param imports
     * @param withSuptypes - Gibt an, ob auch die subklassen der Packages den Assumptions angefügt werden sollen.
     * @return
     */
    public TypeAssumptions makeBasicAssumptionsFromJRE(Menge<UsedId> imports, boolean withSubtypes)
    // ino.end
    // ino.method.makeBasicAssumptionsFromJRE.21409.body 
    {
		//return null;
    ///*
        Menge<UsedId> doneImports=new Menge<UsedId>();
        
        //TypeinferenceResultSet basicAssumptions = new TypeinferenceResultSet(null);
        TypeAssumptions basicAssumptions = new TypeAssumptions();
        
        Modifiers mod = new Modifiers();
        mod.addModifier(new Public());      
        
        //Für Object:
        imports.add(new UsedId("java.lang.Object",-1));
        
        // Für jede einzelne Klasse
        while (imports.size()>0) {
            UsedId importDecl = imports.get(0);
            
            // Properties laden
            java.lang.Class<?> x;
            try {
                x = java.lang.Class.forName(importDecl.getQualifiedName().toString());
            } catch (ClassNotFoundException e) {                
                throw new CTypeReconstructionException("Fehlerhafte Import-Declaration: "+e.getMessage(),importDecl);           
            }
            
            java.lang.reflect.Field[] fields=x.getDeclaredFields();
            java.lang.reflect.Method[] methods=x.getDeclaredMethods();
            java.lang.reflect.Constructor[] constructors=x.getConstructors();
            java.lang.reflect.TypeVariable[] tvs=x.getTypeParameters();                                 
            //String className=x.getSimpleName();
            String className=x.getName();           
            
            //Ermittle die Superklasse:
            Class sClass = new Class("Object",0);
            if(withSubtypes)sClass = getSuperClassOfJREClass(x, basicAssumptions);
            
            // Namen von Generische Typen erzeugen
            Hashtable<String,GenericTypeVar> jreSpiderRegistry=new Hashtable<String,GenericTypeVar>();          
            Menge<String> typeGenPara = new Menge<String>();
            for(int j=0;j<tvs.length;j++){                
                //GenericTypeVar gtv=new GenericTypeVar(tvs[j].getName(), parentClass,-1);
                typeGenPara.addElement(tvs[j].getName());
                //jreSpiderRegistry.put(tvs[j].getName(),gtv);
            }
            
            Class parentClass = new Class(className, sClass.getType(),mod, typeGenPara);
            
            //BasicAssumptionClass myCl = new BasicAssumptionClass(className, mod);
            
            for(GenericTypeVar classParam : parentClass.getGenericParameter()){
            	jreSpiderRegistry.put(classParam.getName().toString(),classParam);
            }
            
            if(typeGenPara.size()>0){
                //auskommentiert von Andreas Stadelmeier:
            	//basicAssumptions.addGenericTypeVars(className, typeGenPara);
                //parentClass.set_ParaList((Menge)typeGenPara);//myCl.set_ParaList((Menge)typeGenPara);         
            }
            
            
            if(x.getSuperclass()!=null){
                //boolean isObject=x.getSuperclass().getSimpleName().equalsIgnoreCase("Object");
                boolean isObject=x.getSuperclass().getName().equalsIgnoreCase("java.lang.Object");              
                boolean isBaseType=isBaseType(className);
     
                //if((!isObject || READ_OBJECT_SUPERCLASSES_FROM_JRE) && (!isBaseType|| READ_BASE_TYPE_SUPERCLASSES_FROM_JRE))
                if (((!isObject || READ_OBJECT_SUPERCLASSES_FROM_JRE) && READ_IMPORTED_SUPERCLASSES_FROM_JRE) //eingefuegt 07-08-11
                		|| (isBaseType && READ_BASE_TYPE_SUPERCLASSES_FROM_JRE))
                {
                    String superclassFullyQualifiedName = x.getSuperclass().getCanonicalName();
                    //Andere Methode, da Menge.contains bei Strings nicht richtig vergleicht.
                    if(!containsString(imports,superclassFullyQualifiedName) && !containsString(doneImports,superclassFullyQualifiedName)){
                        imports.addElement(UsedId.createFromQualifiedName(superclassFullyQualifiedName,-1));
                    }
                    //UsedId ui = new UsedId();
                    //ui.set_Name(x.getSuperclass().getSimpleName());
                    UsedId ui=UsedId.createFromQualifiedName(x.getSuperclass().getName(),-1);
                    java.lang.Class superClass=x.getSuperclass();
                    java.lang.reflect.TypeVariable[] superclassTVS=superClass.getTypeParameters();
                    Menge<Type> supertypeGenPara = new Menge<Type>();                 
                    for(int tvi=0;tvi<superclassTVS.length;tvi++){
                        GenericTypeVar newGTV=new GenericTypeVar(superclassTVS[tvi].getName(),parentClass,-1);
                        supertypeGenPara.addElement(newGTV);
                    }
                    
                    if(supertypeGenPara.size()==0){
                        supertypeGenPara=null;
                    }
                    ui.set_ParaList(supertypeGenPara);
                    ui.vParaOrg=supertypeGenPara;
                    parentClass.set_UsedId(ui);
                }
            }            
            
            //auskommentiert von Andreas Stadelmeier
            //this.addElement(myCl);
            //basicAssumptions.addClassName(className);
            
            for(int j=0;j<fields.length;j++){               
                if(java.lang.reflect.Modifier.isPublic(fields[j].getModifiers())){
                   parentClass.addField(new FieldDeclaration(fields[j].getName(),new RefType(fields[j].getType().getName(),parentClass,-1)));
                }
            }
            for(int j=0;j<methods.length;j++){
                if(java.lang.reflect.Modifier.isPublic(methods[j].getModifiers())){
                    String methodName=methods[j].getName();
                    //if(methodName.equals("add")){
                    
                    java.lang.reflect.Type genericReturnType=methods[j].getGenericReturnType();
                    Type returnType=createTypeFromJavaGenericType(genericReturnType,methods[j].getReturnType(),jreSpiderRegistry, parentClass);
                    
                    java.lang.reflect.Type[] gpt=methods[j].getGenericParameterTypes();
                    java.lang.Class[] pt=methods[j].getParameterTypes();
                    
                    //CMethodTypeAssumption method = new CMethodTypeAssumption(new RefType(className, 0), methodName, returnType, pt.length,MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
                    Method method = de.dhbwstuttgart.syntaxtree.Method.createEmptyMethod(methodName, parentClass);
                    method.setType(returnType);
                    ParameterList parameterList = new ParameterList();
                    
                    for(int k=0;k<gpt.length;k++){
                        Type type=createTypeFromJavaGenericType(gpt[k],pt[k],jreSpiderRegistry, parentClass);
                        // Fixme HOTI beachte overloaded id                 
                        //method.addParaAssumption(new CParaTypeAssumption(className, methodName, pt.length,0,type.getName(), type, MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>()));
                        FormalParameter parameter = new FormalParameter(new DeclId(type.get_Name()));
                        parameter.setType(type);
                        parameterList.formalparameter.add(parameter);
                    }
                    method.setParameterList(parameterList);
                    //basicAssumptions.addMethodIntersectionType(new CIntersectionType(method));
                    
                    parentClass.addField(method);
                	
                    //}
                 }
            }
            
            for(int j=0;j<constructors.length;j++){
            	String methodName=className;
            	Method constructorMethod = de.dhbwstuttgart.syntaxtree.Method.createEmptyMethod(methodName, parentClass);
                
                if(java.lang.reflect.Modifier.isPublic(constructors[j].getModifiers())){                
                    ParameterList paraList = new ParameterList();
                    for(int k=0;k<constructors[j].getParameterTypes().length;k++){
                        String paraType=constructors[j].getParameterTypes()[k].getName();
                        //String paraType=constructors[j].getParameterTypes()[k].getSimpleName();
                        // Fixme HOTI beachte overloaded id
                        FormalParameter fpara = new FormalParameter(new DeclId("p"+k));
                        fpara.setType(new RefType(paraType,constructorMethod,-1));
                        paraList.formalparameter.add(fpara);
                    }
                    //basicAssumptions.addMethodIntersectionType(new CIntersectionType(constructor));
                    constructorMethod.parameterlist = paraList;
                    Constructor constructor = new Constructor(constructorMethod, parentClass);
                    constructor.parserPostProcessing(parentClass);
                    parentClass.addField(constructor);
                }
            }

            basicAssumptions.add(parentClass.getPublicFieldAssumptions());
            basicAssumptions.addClassAssumption(new ClassAssumption(parentClass));
            imports.removeElement(importDecl);
            doneImports.addElement(importDecl);
        }
        imports.addAll(doneImports);
        return basicAssumptions;
        //*/
    }
    // ino.end

    private Class getSuperClassOfJREClass(java.lang.Class<?> x, TypeAssumptions ass) {
    	Class ret;
    	java.lang.Class s = x.getSuperclass();
    	if(s == null){
    		return new Class("java.lang.Object",new Modifiers(), 0);
    	}

    	Menge<String> supertypeGenPara = new Menge<>();//Die Generischen Parameter für die Superklasse berechnen:
    	java.lang.reflect.TypeVariable[] superclassTVS=s.getTypeParameters();
    	for(int tvi=0;tvi<superclassTVS.length;tvi++){
            supertypeGenPara.addElement(superclassTVS[tvi].getName());
        }
        
    	Class ss = this.getSuperClassOfJREClass(s, ass);
    	ret = new Class(s.getName(),ss.getType(),new Modifiers(),supertypeGenPara);
    	
        
    	ass.addClassAssumption(new ClassAssumption(ss)); //Die beiden SuperKlassen den Assumptions anfügen...
    	ass.addClassAssumption(new ClassAssumption(ret));
    	
    	return ret;
	}

	// ino.method.isBaseType.21412.definition 
    private boolean isBaseType(String type)
    // ino.end
    // ino.method.isBaseType.21412.body 
    {
        return baseTypeTranslationTable.containsValue(type);
    }
    // ino.end
    
    /*Die contains Methode des Menges vergleicht bei Strings nicht korrekt, 
     * da zwei Strings mit dem gleichen Inhalt unterschiedliche Instanzen sind.
     * Deshalb diese Methode 07-01-20 luar*/
    private boolean containsString(Menge<UsedId> searchMenge, String searchString)
    {
    	boolean found = false;
    	for(UsedId id : searchMenge)
    	{
    		String s = id.getQualifiedName().toString();
    		found |= s.equals(searchString);
    	}
    	return found;
    }


    // ino.method.createTypeFromJavaGenericType.21415.definition 
    private Type createTypeFromJavaGenericType(java.lang.reflect.Type type, java.lang.Class<?> cl, Hashtable<String,GenericTypeVar>jreSpiderRegistry, Class parentClass)
    // ino.end
    // ino.method.createTypeFromJavaGenericType.21415.body 
    {
        /* auskommentiert, da die Klassen von Sun in der Open JDK 1.8 nicht unterstützt werden.
        if(type instanceof TypeVariableImpl){
			TypeVariableImpl tvi=((TypeVariableImpl)type);
            return(new GenericTypeVar(jreSpiderRegistry.get(tvi.getName()).getName().toString(),parentClass,-1));
        }else{
        */
    	GenericTypeVar gtv = jreSpiderRegistry.get(type.getTypeName());
    	if(gtv != null)return gtv;
    	//new GenericTypeVar(jreSpiderRegistry.get(type.getTypeName()).getName().toString(),parentClass,-1));
        //String jccNameForClass=baseTypeTranslationTable.get(cl.getSimpleName());
        String jccNameForClass=baseTypeTranslationTable.get(cl.getName());          
        if(cl.getSimpleName().equalsIgnoreCase("void")){
            return(new Void(parentClass,-1));
        }else if(jccNameForClass!=null){
            RefType rt=new RefType(jccNameForClass,parentClass,-1);
            rt.setPrimitiveFlag(true);
            return(rt);
        }else{              
            //return(new RefType(cl.getSimpleName()));              
            return(new RefType(cl.getName(),parentClass,-1));               
        }
        //}
    }
    // ino.end

     
    // ino.method.makeBasicAssumptions.21418.defdescription type=javadoc
    /**
     * Erzeugt die Anfangsinformationen �ber bereits bekannte Klassen.
     * <br/>Achtung Workaround: Die RefTypes m�ssen sp�ter noch durch BaseTypes
     * ersetzt werden. <br>
     * Author: J�rg B�uerle
     * 
     * @return A priori Typinformationen
     * @throws ClassNotFoundException 
     */
    // ino.end
    // ino.method.makeBasicAssumptions.21418.definition 
    private TypeAssumptions makeBasicAssumptions()
    // ino.end
    // ino.method.makeBasicAssumptions.21418.body 
    {
        /*
        if(LOAD_BASIC_ASSUMPTIONS_FROM_JRE){
            
            Menge<UsedId> strImports=new Menge<UsedId>();
            ImportDeclarations usedIdImports=getImports();
            for(int i=0;i<usedIdImports.size();i++){
                UsedId uid=usedIdImports.get(i);
                if(uid.hasWildCard()){
                    throw new CTypeReconstructionException("Wildcards in den Imports werden bislang nicht unterstuetzt: "+uid.getQualifiedName(),uid);
                    
                    //throw new ClassNotFoundException("Bei den Imports sind momentan keine Wildcards erlaubt!");
                }else{
                    strImports.addElement(uid);             
                }
            }
            TypeinferenceResultSet res=makeBasicAssumptionsFromJRE(strImports);
            
            ImportDeclarations newImports=new ImportDeclarations();
            for(int i=0;i<strImports.size();i++){
                newImports.addElement(strImports.get(i));
            }
            setImports(newImports);
            
            return(res);
        }
    
        
        TypeinferenceResultSet foo = new TypeinferenceResultSet(null);
        CMethodTypeAssumption meth = null;
        CInstVarTypeAssumption instVar = null;
        Class c = null;
        UsedId ui = null;
        //Menge pl = null;
        
        Modifiers mod = new Modifiers();
        mod.addModifier(new Public());
        
        //------------------------
        // Integer bauen:
        //------------------------
        foo.addClassName("java.lang.Integer"); //PL 05-08-01  eingefuegt
        instVar = new CInstVarTypeAssumption("java.lang.Integer", "MAX_VALUE", new RefType("java.lang.Integer",-1), MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>());
        foo.addFieldOrLocalVarAssumption(instVar);
        
        meth = new CMethodTypeAssumption(new RefType("java.lang.Integer", 0), "<init>", new RefType("java.lang.Integer",-1), 0,MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        foo.addMethodIntersectionType(new CIntersectionType(meth));
    
        meth = new CMethodTypeAssumption(new RefType("java.lang.Integer", 0), "<init>", new RefType("java.lang.Integer",-1),1, MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        meth.addParaAssumption(new CParaTypeAssumption("java.lang.Integer", "<init>", 1, 0,"value", new RefType("java.lang.Integer",-1), MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>()));
        foo.addMethodIntersectionType(new CIntersectionType(meth));
        
        meth = new CMethodTypeAssumption(new RefType("java.lang.Integer", 0), "intValue", new RefType("java.lang.Integer",-1), 0,MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        foo.addMethodIntersectionType(new CIntersectionType(meth));
    
    
        
        c = new BasicAssumptionClass("java.lang.Integer", mod);
    
    //        ui = new UsedId();
    //        ui.set_Name("Super-Class-Blub");
    //        c.set_UsedId(ui);
    //        pl = new Menge();
    //        pl.addElement(new GenericTypeVar("bla"));        
    //        c.set_ParaList(pl);
        this.addElement(c);
        
        //------------------------
        // Boolean bauen:
        //------------------------
    foo.addClassName("java.lang.Boolean"); //PL 05-08-01  eingefuegt
        meth = new CMethodTypeAssumption(new RefType("java.lang.Boolean", 0), "<init>", new RefType("java.lang.Boolean",-1),0, MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        foo.addMethodIntersectionType(new CIntersectionType(meth));
    
        meth = new CMethodTypeAssumption(new RefType("java.lang.Boolean", 0), "<init>", new RefType("java.lang.Boolean",-1), 1,MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        meth.addParaAssumption(new CParaTypeAssumption("java.lang.Boolean", "<init>", 1, 0, "value", new RefType("java.lang.Boolean",-1), MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>()));
        foo.addMethodIntersectionType(new CIntersectionType(meth));
        
        meth = new CMethodTypeAssumption(new RefType("java.lang.Boolean", 0), "booleanValue", new RefType("java.lang.Boolean",-1), 0,MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        foo.addMethodIntersectionType(new CIntersectionType(meth));
    
        c = new BasicAssumptionClass("java.lang.Boolean", mod);
    
    //        ui = new UsedId();
    //        ui.set_Name("Super-Class-Blub");
    //        c.set_UsedId(ui);
    //        pl = new Menge();
    //        pl.addElement(new GenericTypeVar("bla"));        
    //        c.set_ParaList(pl);
        this.addElement(c);
        
        //------------------------
        // Character bauen:
        //------------------------
    foo.addClassName("java.lang.Character"); //PL 05-08-01  eingefuegt
        meth = new CMethodTypeAssumption(new RefType("java.lang.Character", 0), "<init>", new RefType("java.lang.Character",-1),0, MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        foo.addMethodIntersectionType(new CIntersectionType(meth));
        
        meth = new CMethodTypeAssumption(new RefType("java.lang.Character", 0), "<init>", new RefType("java.lang.Character",-1),1, MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        meth.addParaAssumption(new CParaTypeAssumption("java.lang.Character", "<init>", 1, 0,"value", new RefType("java.lang.Character",-1), MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>()));
        foo.addMethodIntersectionType(new CIntersectionType(meth));
        
        meth = new CMethodTypeAssumption(new RefType("java.lang.Character", 0), "charValue", new BooleanType(),0, MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        foo.addMethodIntersectionType(new CIntersectionType(meth));
    
        c = new BasicAssumptionClass("java.lang.Character", mod);
    
    //        ui = new UsedId();
    //        ui.set_Name("Super-Class-Blub");
    //        c.set_UsedId(ui);
    //        pl = new Menge();
    //        pl.addElement(new GenericTypeVar("bla"));        
    //        c.set_ParaList(pl);
        this.addElement(c);
        
        //------------------------
        // Menge bauen:
        //------------------------
    foo.addClassName("java.lang.Menge"); //PL 05-08-01  eingefuegt
        TypePlaceholder E = TypePlaceholder.fresh();  // Sp�ter ersetzen durch GenericTypeVar
    Menge<GenericTypeVar> typeGenPara = new Menge<GenericTypeVar>();
    typeGenPara.addElement(new GenericTypeVar(E.getName(),-1));
    foo.addGenericTypeVars("java.lang.Menge", typeGenPara);
        meth = new CMethodTypeAssumption(new RefType("java.lang.Menge", 0), "elementAt", new GenericTypeVar(E.getName(),-1), 1,MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        meth.addParaAssumption(new CParaTypeAssumption("java.lang.Menge", "elementAt", 1, 0, "index", new RefType("java.lang.Integer",-1), MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>()));
        foo.addMethodIntersectionType(new CIntersectionType(meth));
    
        meth = new CMethodTypeAssumption(new RefType("java.lang.Menge", 0), "addElement", new Void(-1),1, MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        meth.addParaAssumption(new CParaTypeAssumption("java.lang.Menge", "addElement", 1, 0,"element", new GenericTypeVar(E.getName(),-1), MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>()));
        foo.addMethodIntersectionType(new CIntersectionType(meth));
    
        meth = new CMethodTypeAssumption(new RefType("java.lang.Menge", 0), "size", new RefType("java.lang.Integer",-1), 0,MyCompiler.NO_LINENUMBER,MyCompiler.NO_LINENUMBER,new Menge<Integer>(),null);
        foo.addMethodIntersectionType(new CIntersectionType(meth));
        
        c = new BasicAssumptionClass("java.lang.Menge", mod);
    
    //      ui = new UsedId();
    //      ui.set_Name("Super-Class-Blub");
    //      c.set_UsedId(ui);
    //        pl = new Menge();
    //        pl.addElement(E);        
    //        c.set_ParaList(pl);
        this.addElement(c);
    
        //------------------------
        // Stack bauen:
        //------------------------
    foo.addClassName("java.lang.Stack"); //PL 05-08-01  eingefuegt
        c = new BasicAssumptionClass("java.lang.Stack", mod);
        ui = new UsedId(-1);
        ui.set_Name("java.lang.Menge");
        c.set_UsedId(ui);
    //        pl = new Menge();
    //        pl.addElement(E);        
    //        c.set_ParaList(pl);
        this.addElement(c);
        
        return foo;
        */
    	TypeAssumptions ret = new TypeAssumptions();
    	
    	//Basic Assumptions für die FunN Interfaces:
    	//TODO: Hier mehr als Fun1-Fun5 implementieren
    	for(int i = 0; i<6; i++){
    		FunNInterface funN = new FunNInterface(i);
    		ret.add(funN.getPublicFieldAssumptions());
    	}
    	
    	
    	return ret; //TODO: Diese TypeAssumptions mit basic-Assumptions füllen
    }
    // ino.end
    
    // ino.method.setImports.21421.definition 
    private void setImports(ImportDeclarations newImports)
    // ino.end
    // ino.method.setImports.21421.body 
    {
        this.imports=newImports;
        
    }
    // ino.end


    // ino.method.removeBasicAssumptions.21424.defdescription type=javadoc
    /**
     * L�scht die Anfangsinformation wieder aus dem Klassenvektor
     * <br/>Author: J�rg B�uerle
     */
    // ino.end
    // ino.method.removeBasicAssumptions.21424.definition 
    private void removeBasicAssumptions()
    // ino.end
    // ino.method.removeBasicAssumptions.21424.body 
    {
        for(int i=0; i<KlassenVektor.size(); i++){
            Class cl = KlassenVektor.elementAt(i);
            if(cl instanceof BasicAssumptionClass){
                KlassenVektor.removeElementAt(i);
                i--;
            }
        }
    }
    // ino.end
    
    // ino.method.getPackageName.21427.defdescription type=javadoc
    /**
     * Erzeugt f�r jede Klasse einen Menge, in den Referenzen auf die GenericTypeVars 
     * dieser Klasse gespeichert werden. Diese Mengeen werden unter den Klassennamen  
     * in der 
     * Ergebnisdatenstruktur abgelegt. Au�erdem werden alle Klassennamen gespeichert.
     * <br/>Author: J�rg B�uerle
     * @param res
     * /
     * /*private void addClassNamesAndGenericsToRR(CTypeReconstructionResult res){
     * Iterator<Class> it = this.getClassIterator();
     * while(it.hasNext()){
     * Class cl = it.next();
     * res.addClassName(cl.get_classname());
     * Menge<GenericTypeVar> genericsList = new Menge<GenericTypeVar>();
     * 
     * for(int i =0; i<cl.get_ParaList().size(); i++){
     * Type para = (Type)cl.get_ParaList().elementAt(i);
     * if(para instanceof GenericTypeVar){
     * genericsList.addElement((GenericTypeVar)para);
     * }
     * }
     * res.addGenericTypeVars(cl.get_classname(), genericsList);
     * }
     * }
     */
    // ino.end
    
    // ino.method.getPackageName.21427.definition 
    public UsedId getPackageName()
    // ino.end
    // ino.method.getPackageName.21427.body 
    {
        return pkgName;
    }
    // ino.end

    // ino.method.setPackageName.21430.definition 
    public void setPackageName(UsedId pkgName)
    // ino.end
    // ino.method.setPackageName.21430.body 
    {
        this.pkgName = pkgName;
        
        // Die Package-Namen fuer alle Klassen und Interfaces
        // im Source-File nachziehen
        for (int i=0; i<KlassenVektor.size(); i++) {
            KlassenVektor.elementAt(i).setPackageName(pkgName);
        }
        
    }
    // ino.end

    // ino.method.addImports.21433.definition 
    public void addImports(ImportDeclarations imports)
    // ino.end
    // ino.method.addImports.21433.body 
    {
        this.imports.addAll(imports);
    }
    // ino.end
    // ino.method.getImports.21436.definition 
    public ImportDeclarations getImports()
    // ino.end
    // ino.method.getImports.21436.body 
    {
        if(imports==null){
            return(new ImportDeclarations());
        }
        return(imports);
    }
    // ino.end
    
    
    // ino.method.getClassIterator.21439.definition 
    public Iterator<Class> getClassIterator()
    // ino.end
    // ino.method.getClassIterator.21439.body 
    {
        return KlassenVektor.iterator();
    }
    // ino.end
 
    // ino.method.getInterfaceIterator.21442.definition 
    public Iterator<Interface> getInterfaceIterator()
    // ino.end
    // ino.method.getInterfaceIterator.21442.body 
    {
        return InterfaceVektor.iterator();
    }
    // ino.end


	@Override
	public void parserPostProcessing(SyntaxTreeNode parent) {
		if(parent!=null)throw new DebugException("Eine SourceFile hat kein Elternelement im Syntaxbaum");
		super.parserPostProcessing(this);
		//for(SyntaxTreeNode node : this.getChildren())node.parserPostProcessing(this);
	}


	@Override
	public SyntaxTreeNode getParent() {
		return null;
	}


	@Override
	public Menge<SyntaxTreeNode> getChildren() {
		Menge<SyntaxTreeNode> ret = new Menge<SyntaxTreeNode>();
		for(Class cl : this.KlassenVektor){
			ret.add(cl);
		}
		return ret;
	}


	/**
	 * SourceFile stellt eine geparste Java-Datei dar. Mit dieser Methode wird der Name der eingelesenen Datei gesetzt.
	 * @param filename - Der Name der eingelesenen JavaDatei
	 */
	@Deprecated
	public void setFileName(String filename) {
		//this.filename = filename;
	}



	@Override
	public int getOffset() {
		// TODO Auto-generated method stub
		return 0;
	}



	@Override
	public int getVariableLength() {
		// TODO Auto-generated method stub
		return 0;
	}

	/**
	 * Bisher wird nur der Bytecode der Klassen generiert. Nicht der Interfaces.
	 * @return
	 */
	public Menge<ByteCodeResult> generateBytecode(TypeinferenceResults results) {
		Menge<ByteCodeResult> ret = new Menge<>();
		for(Class cl : this.KlassenVektor){
			ret.add(cl.genByteCode(results));
		}
		return ret;
	}

}
// ino.end