/**
* Copyright 2011-2015 John Ericksen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.androidtransfuse.experiment;
import com.sun.codemodel.*;
import org.androidtransfuse.TransfuseAnalysisException;
import org.androidtransfuse.adapter.ASTMethod;
import org.androidtransfuse.adapter.ASTParameter;
import org.androidtransfuse.adapter.MethodSignature;
import org.androidtransfuse.analysis.AnalysisContext;
import org.androidtransfuse.gen.ClassGenerationUtil;
import org.androidtransfuse.gen.UniqueVariableNamer;
import org.androidtransfuse.model.InjectionNode;
import org.androidtransfuse.model.MethodDescriptor;
import org.androidtransfuse.model.MethodDescriptorBuilder;
import org.androidtransfuse.model.TypedExpression;
import javax.inject.Inject;
import java.util.*;
/**
* @author John Ericksen
*/
public class ComponentBuilder {
private class MethodMetaData{
private final Map<GenerationPhase, List<ComponentMethodGenerator>> generators = new HashMap<GenerationPhase, List<ComponentMethodGenerator>>();
private final Map<GenerationPhase, List<ComponentMethodGenerator>> lazyGenerators = new HashMap<GenerationPhase, List<ComponentMethodGenerator>>();
private final ASTMethod methodDefinition;
private MethodMetaData(ASTMethod methodDefinition) {
this.methodDefinition = methodDefinition;
}
public void putLazy(GenerationPhase phase, ComponentMethodGenerator partGenerator) {
if(!lazyGenerators.containsKey(phase)){
lazyGenerators.put(phase, new ArrayList<ComponentMethodGenerator>());
}
lazyGenerators.get(phase).add(partGenerator);
}
public void put(GenerationPhase phase, ComponentMethodGenerator partGenerator) {
if(!generators.containsKey(phase)){
generators.put(phase, new ArrayList<ComponentMethodGenerator>());
}
generators.get(phase).add(partGenerator);
}
public void build() {
if(!generators.isEmpty()){
MethodDescriptor descriptor = buildMethod();
for (GenerationPhase phase : GenerationPhase.values()) {
if(lazyGenerators.containsKey(phase)){
for (ComponentMethodGenerator componentMethodGenerator : lazyGenerators.get(phase)) {
componentMethodGenerator.generate(descriptor, descriptor.getBody());
}
}
if(generators.containsKey(phase)){
for (ComponentMethodGenerator componentMethodGenerator : generators.get(phase)) {
componentMethodGenerator.generate(descriptor, descriptor.getBody());
}
}
}
}
}
private MethodDescriptor buildMethod() {
JMethod method = getDefinedClass().method(JMod.PUBLIC, generationUtil.ref(methodDefinition.getReturnType()), methodDefinition.getName());
method.annotate(Override.class);
MethodDescriptorBuilder methodDescriptorBuilder = new MethodDescriptorBuilder(method, methodDefinition);
//parameters
for (ASTParameter astParameter : methodDefinition.getParameters()) {
JVar param = method.param(generationUtil.ref(astParameter.getASTType()), variableNamer.generateName(astParameter.getASTType()));
methodDescriptorBuilder.putParameter(astParameter, new TypedExpression(astParameter.getASTType(), param));
}
return methodDescriptorBuilder.build();
}
}
private final Map<InjectionNode, TypedExpression> expressionMap = new HashMap<InjectionNode, TypedExpression>();
private final ClassGenerationUtil generationUtil;
private final ComponentDescriptor descriptor;
private final UniqueVariableNamer variableNamer;
private final Set<ComponentPartGenerator> generators = new HashSet<ComponentPartGenerator>();
private final Map<MethodSignature, MethodMetaData> methodData = new HashMap<MethodSignature, MethodMetaData>();
private JDefinedClass definedClass = null;
private JVar scopes;
@Inject
public ComponentBuilder(ClassGenerationUtil generationUtil,
ComponentDescriptor descriptor,
UniqueVariableNamer variableNamer) {
this.generationUtil = generationUtil;
this.descriptor = descriptor;
this.variableNamer = variableNamer;
}
public void build(){
for (MethodSignature methodSignature : descriptor.getGenerateFirst()) {
if(methodData.containsKey(methodSignature)) {
methodData.get(methodSignature).build();
}
}
for (Map.Entry<MethodSignature, MethodMetaData> entry : methodData.entrySet()) {
if(!descriptor.getGenerateFirst().contains(entry.getKey())){
entry.getValue().build();
}
}
for (ComponentPartGenerator generator : generators) {
generator.generate(descriptor);
}
}
public void add(ComponentPartGenerator partGenerator) {
generators.add(partGenerator);
}
public void addLazy(ASTMethod method, GenerationPhase phase, ComponentMethodGenerator partGenerator){
MethodSignature methodSignature = new MethodSignature(method);
if(!methodData.containsKey(methodSignature)){
methodData.put(methodSignature, new MethodMetaData(method));
}
methodData.get(methodSignature).putLazy(phase, partGenerator);
}
public void add(ASTMethod method, GenerationPhase phase, ComponentMethodGenerator partGenerator){
MethodSignature methodSignature = new MethodSignature(method);
if(!methodData.containsKey(methodSignature)){
methodData.put(methodSignature, new MethodMetaData(method));
}
methodData.get(methodSignature).put(phase, partGenerator);
}
public JDefinedClass getDefinedClass() {
if (definedClass == null && descriptor.getType() != null) {
try {
definedClass = generationUtil.defineClass(descriptor.getPackageClass());
definedClass._extends(generationUtil.ref(descriptor.getType()));
} catch (JClassAlreadyExistsException e) {
throw new TransfuseAnalysisException("Class Already Exists ", e);
}
}
return definedClass;
}
public AnalysisContext getAnalysisContext() {
return descriptor.getAnalysisContext();
}
public void setScopes(JVar scopes) {
this.scopes = scopes;
}
public JVar getScopes() {
return scopes;
}
public Map<InjectionNode, TypedExpression> getExpressionMap() {
return expressionMap;
}
}