package org.seasar.framework.container.deployer;

import org.seasar.framework.container.ComponentDef;
import org.seasar.framework.container.assembler.AutoConstructorAssembler;
import org.seasar.framework.container.assembler.AutoPropertyAssembler;
import org.seasar.framework.container.assembler.ConstructorAssembler;
import org.seasar.framework.container.assembler.DefaultConstructorAssembler;
import org.seasar.framework.container.assembler.DefaultDestroyMethodAssembler;
import org.seasar.framework.container.assembler.DefaultInitMethodAssembler;
import org.seasar.framework.container.assembler.DefaultPropertyAssembler;
import org.seasar.framework.container.assembler.ExpressionConstructorAssembler;
import org.seasar.framework.container.assembler.MethodAssembler;
import org.seasar.framework.container.assembler.ManualConstructorAssembler;
import org.seasar.framework.container.assembler.ManualPropertyAssembler;
import org.seasar.framework.container.assembler.PropertyAssembler;
import org.seasar.framework.container.util.AutoBindingUtil;

/**
 * @author higa
 *
 */
public abstract class AbstractComponentDeployer implements ComponentDeployer {

	private ComponentDef componentDef_;
	private ConstructorAssembler constructorAssembler_;
	private PropertyAssembler propertyAssembler_;
	private MethodAssembler initMethodAssembler_;
	private MethodAssembler destroyMethodAssembler_;

	public AbstractComponentDeployer(ComponentDef componentDef) {
		componentDef_ = componentDef;
		setupAssembler();
	}

	protected final ComponentDef getComponentDef() {
		return componentDef_;
	}

	protected final ConstructorAssembler getConstructorAssembler() {
		return constructorAssembler_;
	}

	protected final PropertyAssembler getPropertyAssembler() {
		return propertyAssembler_;
	}

	protected final MethodAssembler getInitMethodAssembler() {
		return initMethodAssembler_;
	}

	protected final MethodAssembler getDestroyMethodAssembler() {
		return destroyMethodAssembler_;
	}

	private void setupAssembler() {
		String autoBindingMode = componentDef_.getAutoBindingMode();
		if (AutoBindingUtil.isAuto(autoBindingMode)) {
			setupAssemblerForAuto();
		} else if (AutoBindingUtil.isConstructor(autoBindingMode)) {
			setupAssemblerForConstructor();
		} else if (AutoBindingUtil.isProperty(autoBindingMode)) {
			setupAssemblerForProperty();
		} else if (AutoBindingUtil.isNone(autoBindingMode)) {
			setupAssemblerForNone();
		} else {
			throw new IllegalArgumentException(autoBindingMode);
		}
		initMethodAssembler_ = new DefaultInitMethodAssembler(componentDef_);
		destroyMethodAssembler_ = new DefaultDestroyMethodAssembler(componentDef_);
	}

	private void setupAssemblerForAuto() {
		setupConstructorAssemblerForAuto();
		propertyAssembler_ = new AutoPropertyAssembler(componentDef_);
	}
	
	private void setupConstructorAssemblerForAuto() {
		if (componentDef_.getArgDefSize() > 0) {
			constructorAssembler_ =
				new ManualConstructorAssembler(componentDef_);
		} else if (componentDef_.getExpression() != null) {
			constructorAssembler_ =
				new ExpressionConstructorAssembler(componentDef_);
		} else {
			constructorAssembler_ =
				new AutoConstructorAssembler(componentDef_);
		}
	}

	private void setupAssemblerForConstructor() {
		setupConstructorAssemblerForAuto();
		propertyAssembler_ = new ManualPropertyAssembler(componentDef_);
	}

	private void setupAssemblerForProperty() {
		if (componentDef_.getExpression() != null) {
			constructorAssembler_ =
				new ExpressionConstructorAssembler(componentDef_);
		} else {
			constructorAssembler_ = new ManualConstructorAssembler(componentDef_);
		}
		propertyAssembler_ = new AutoPropertyAssembler(componentDef_);
	}

	private void setupAssemblerForNone() {
		if (componentDef_.getArgDefSize() > 0) {
			constructorAssembler_ =
				new ManualConstructorAssembler(componentDef_);
		} else if (componentDef_.getExpression() != null) {
			constructorAssembler_ =
				new ExpressionConstructorAssembler(componentDef_);
		} else {
			constructorAssembler_ =
				new DefaultConstructorAssembler(componentDef_);
		}
		if (componentDef_.getPropertyDefSize() > 0) {
			propertyAssembler_ = new ManualPropertyAssembler(componentDef_);
		} else {
			propertyAssembler_ = new DefaultPropertyAssembler(componentDef_);
		}
	}
}
