//$Id: BasicRenderer.java,v 1.12 2002/11/02 15:48:54 oneovthafew Exp $
package cirrus.hibernate.tools.codegen;

import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;

public class BasicRenderer implements Renderer {

    /**
	 * Returns the true name for the given class name. By true name is 
     * that it will return the Proxy for the class name if the class was
     * defined with a proxy attribute.
	 * @param field class name that we use to serach in class2classmap
	 * @param class2classmap a map from classname to classmappings
	 * @return String return either name or the proxy name of the classmap
	 */
	String getTrueTypeName(Field  field, Map class2classmap) {
        String name=field.getClassType()!=null?field.getClassType().getFullyQualifiedName():field.getType();
        ClassMapping cmap = (ClassMapping) class2classmap.get(name);
        
        if(cmap!=null) {
            if (cmap.getProxy()!=null) {
                return cmap.getProxy();
            }   
        } 
        return name;
    }
    public void render(String packageName, String className, ClassMapping classMapping, Map class2classmap, PrintWriter writer) throws Exception {
        if ( classMapping.getPackageName()!=null ) {
        	writer.println("package " + classMapping.getPackageName() + ";");
        }
        else {
        	writer.println("//warning: default package");
        }
        writer.println();

        // imports
        classMapping.getImports().add("java.io.Serializable");
        String item = null;

        for (Iterator imports = classMapping.getImports().iterator(); imports.hasNext();) {
            item = (String) imports.next();
            writer.println("import " + item + ";");
        }
        writer.println();

        // class declaration
        writer.print("public class " + classMapping.getName());

        // subclass
        if (classMapping.getSuperClass() != null) {
            writer.print(" extends " + classMapping.getSuperClass());
        }

        // always implements Serializable
        writer.print(" implements Serializable");
        
		// implement proxy, but NOT if the proxy is the class it self!
		if ( 
			classMapping.getProxy()!=null && 
			( !classMapping.getProxy().equals( classMapping.getCanonicalName() ) )
		) {
        	writer.print(", ");
        	writer.print( classMapping.getProxy() );
        }
        writer.println(" {");

        // fields
        Field field = null;

        for (Iterator fields = classMapping.getFields().iterator(); fields.hasNext();) {
            field = (Field) fields.next();
            writer.println("    private " + field.getType() + ' ' + field.getName() + 
            	( field.isIdentifier() ? "; //identifier" : "; //persistent") 
            );
        }
        writer.println();
        
        // full constructor
        int fullConsArgCount = 0;
        String fullCons = "    public " + classMapping.getName() + "(";
        for(Iterator fields = classMapping.getFields().iterator(); fields.hasNext();) {
            field = (Field) fields.next();
            if(!field.isIdentifier() || (field.isIdentifier() && !field.isGenerated())) {
                fullCons = fullCons + field.getType() + " " + field.getName();
                fullCons = fullCons + ", ";
                fullConsArgCount++;  
            }
        }
        if ( fullCons.endsWith(", ") ) fullCons = fullCons.substring(0, fullCons.length()-2);

        writer.println(fullCons + ") {");
        for(Iterator fields = classMapping.getFields().iterator(); fields.hasNext();) {
            field = (Field) fields.next();
            if(!field.isIdentifier() || (field.isIdentifier() && !field.isGenerated())) {
                writer.println("        this." + field.getName() + " = " + field.getName() + ";");
            }
        }
        writer.println("    }");
        writer.println();

        // no args constructor (if fullconstructor had any arguments!)
        if (fullConsArgCount > 0) {
			writer.println("    public " + classMapping.getName() + "() {");
			writer.println("    }");
			writer.println();
		}
        
        // minimal constructor (only if the fullconstructor had any arguments) 
        if(fullConsArgCount>0) {
        
        if(classMapping.needsMinimalConstructor()) {
            String minCons = "    public " + classMapping.getName() + "(";
            for(Iterator fields = classMapping.getFields().iterator(); fields.hasNext();) {
                field = (Field) fields.next();
                if((!field.isIdentifier() && !field.isNullable()) ||
                    (field.isIdentifier() && !field.isGenerated())) {
                    minCons = minCons + field.getType() + " " + field.getName();
                    minCons = minCons + ", ";
                }
            }
            if ( minCons.endsWith(", ") ) minCons = minCons.substring(0, minCons.length()-2);

            writer.println(minCons + ") {");
            for(Iterator fields = classMapping.getFields().iterator(); fields.hasNext();) {
                field = (Field) fields.next();
                if((!field.isIdentifier() && !field.isNullable()) ||
                    (field.isIdentifier() && !field.isGenerated())) {
                    writer.println("        this." + field.getName() + " = " + field.getName() + ";");
                }
            }
            writer.println("    }");
            writer.println();
        }
        }

        // field accessors
        for (Iterator fields = classMapping.getFields().iterator(); fields.hasNext();) {
            field = (Field) fields.next();

            String getterType = (field.getType().toLowerCase().equals("boolean")) ? " is" : " get";

            // getter
            writer.println("    public " + getTrueTypeName(field, class2classmap) + getterType + field.getAsSuffix() + "() {");
            writer.println("        return this." + field.getName() + ";");
            writer.println("    }");
            writer.println("");

            // setter
            writer.println("    public void set" + field.getAsSuffix() + "(" + getTrueTypeName(field, class2classmap) + " " + field.getName() + ") {");
            writer.println("        this." + field.getName() + " = " + field.getName() + ";");
            writer.println("    }");
        }

        writer.println("}");
    }

}
