/*
 * $Id$
 *
 * License Agreement.
 *
 * Rich Faces - Natural Ajax for Java Server Faces (JSF)
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */
package org.richfaces.cdk.templatecompiler;

import java.io.IOException;
import java.io.Writer;
import java.util.Collection;

import org.richfaces.cdk.CdkException;
import org.richfaces.cdk.CdkWriter;
import org.richfaces.cdk.FileManager;
import org.richfaces.cdk.Logger;
import org.richfaces.cdk.Output;
import org.richfaces.cdk.Outputs;
import org.richfaces.cdk.generate.freemarker.FreeMarkerRenderer;
import org.richfaces.cdk.model.ComponentLibrary;
import org.richfaces.cdk.model.ComponentModel;
import org.richfaces.cdk.model.ModelSet;
import org.richfaces.cdk.model.PropertyBase;
import org.richfaces.cdk.model.RenderKitModel;
import org.richfaces.cdk.model.RendererModel;
import org.richfaces.cdk.templatecompiler.builder.model.JavaClass;
import org.richfaces.cdk.templatecompiler.model.Template;

import com.google.inject.Inject;

import freemarker.template.TemplateException;

/**
 * <p class="changed_added_4_0">
 * </p>
 *
 * @author asmirnov@exadel.com
 */
public class RendererClassGenerator implements CdkWriter {
    private FileManager output;
    private Logger log;
    private TemplateVisitorFactory<RendererClassVisitor> visitorFactory;
    private FreeMarkerRenderer renderer;

    /**
     * <p class="changed_added_4_0">
     * </p>
     *
     * @param library
     * @param output
     * @param log
     * @param visitorFactory
     */
    @Inject
    public RendererClassGenerator(@Output(Outputs.JAVA_CLASSES) FileManager output, Logger log,
            TemplateVisitorFactory<RendererClassVisitor> visitorFactory, @TemplateModel FreeMarkerRenderer renderer) {
        this.output = output;
        this.log = log;
        this.visitorFactory = visitorFactory;
        this.renderer = renderer;
    }

    private ComponentModel findComponentByRenderer(RendererModel renderer, ComponentLibrary library) {
        return library.getComponentByRenderer(renderer.getFamily(), renderer.getId());
    }

    /*
     * (non-Javadoc)
     *
     * @see org.richfaces.cdk.CdkWriter#render(org.richfaces.cdk.model.ComponentLibrary )
     */
    @Override
    public void render(ComponentLibrary library) throws CdkException {
        for (RenderKitModel renderKit : library.getRenderKits()) {
            for (RendererModel renderer : renderKit.getRenderers()) {
                Template template = renderer.getTemplate();
                if (null != template) {
                    Collection<PropertyBase> attributes = ModelSet.<PropertyBase>create();

                    ComponentModel component = findComponentByRenderer(renderer, library);
                    if (component != null) {
                        attributes.addAll(component.getAttributes());
                    }

                    attributes.addAll(renderer.getAttributes());
                    RendererClassVisitor visitor = visitorFactory.createVisitor(template.getInterface(), attributes);

                    // TODO - put real parameters.
                    template.getImplementation().visit(visitor);

                    JavaClass javaClass = visitor.getGeneratedClass();
                    String fullName = javaClass.getName();
                    Writer outFile = null;
                    try {
                        outFile = output.createOutput(fullName.replace('.', '/') + ".java", library.lastModified());

                        if (null != outFile) {
                            this.renderer.writeTemplate("class.ftl", javaClass, outFile);
                        }
                    } catch (IOException e) {
                        throw new CdkException(e);
                    } catch (TemplateException e) {
                        throw new CdkException(e);
                    } finally {
                        if (null != outFile) {
                            try {
                                outFile.close();
                            } catch (IOException e) {
                                log.warn("IOException occured when closing writer for renderer-class", e);
                            }
                        }
                    }
                }
            }
        }
    }
}
