package org.arefgard.container;

import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.arefgard.container.flow.service.ServiceWorkflowExecutor;
import org.arefgard.container.orm.Session;
import org.arefgard.container.orm.SessionFactory;

public class BusinessService {
	
	private Log log = LogFactory.getLog(BusinessService.class);
	
	private IceryaContainer container;
	private Reference ref;
	private Map<String, Object> input;
	private Map<String, Object> output;
	
	public BusinessService(IceryaContainer container, Reference ref) {
		this.input = new java.util.HashMap<String, Object>();
		this.output = new java.util.HashMap<String, Object>();
		this.container = container;
		this.ref = ref;
	}
	
	public void execute() throws Exception {
		BusinessDef businessDef = container.getBusinessDef(ref.getNameSpace());
		ServiceDef serviceDef = businessDef.getServiceDef(ref.getTarget());
		// DIの実行
		int componentLength = serviceDef.getComponentDefLength();
		Map<String, Object> component = new java.util.HashMap<String, Object>();
		Session session = null;
		try {
			ConnectionDef connectionDef = container.getConnectionDef();
			SessionFactory.initialize(connectionDef.getDriver(), connectionDef.getUrl(), connectionDef.getUser(), connectionDef.getPassword());
			session = SessionFactory.openSession();
			for(int i = 0; i < componentLength; i++) {
				ComponentDef componentDef = serviceDef.getComponentDef(i);
				String name = componentDef.getName();
				log.debug("コンポーネント:" + name + "," + componentDef.getRef());
				Reference ref = new Reference(componentDef.getRef());
				DomainDef domainDef = container.getDomainDef(ref.getNameSpace());
				BeanDef beanDef = domainDef.getBeanDef(ref.getTarget());
				String query = componentDef.getQuery();
				if(query == null) {
					// プロパティによる値の設定
					int propertyLength = componentDef.getPropertyLength();
					Map<String, Object> properties = new java.util.HashMap<String, Object>();			
					for(int j = 0; j < propertyLength; j++) {
						ComponentPropertyDef property = componentDef.getPropertyDef(j);
						log.debug("プロパティ:" + property.getName() +"," + this.input.get(serviceDef.getInputDef(property.getValue()).getName()));
						properties.put(property.getName(), this.input.get(serviceDef.getInputDef(property.getValue()).getName()));
					}
					component.put(name, beanDef.create(properties));
				}else {
					// queryによるオブジェクトの取得
					PropertyDef[] propertyDef = beanDef.getAllProperties();
					int propertyLength = propertyDef.length;
					for(int j = 0; j < propertyLength; j++) {
						session.addMapping(propertyDef[j].getName(), propertyDef[j].getType(), propertyDef[j].getColumn());
					}
					Object obj = session.find(beanDef.getClassName(), beanDef.getTable(), query);
					component.put(name, obj);
				}
				
			}
		}finally {
			session.close();
		}
		// ユースケースフローの実行
		FlowDef flowDef = serviceDef.getFlowDef();
		String path = flowDef.getName();
		ServiceWorkflowExecutor executor = new ServiceWorkflowExecutor(path);
		
		int parameterLength = flowDef.getParameterLength();

		for(int i = 0; i < parameterLength; i++) {
			ParameterDef parameterDef = flowDef.getParameterDef(i);
			String name = parameterDef.getName();
			String ref = parameterDef.getRef();
			log.debug("Parameter:" + name + "," + ref);
			Object obj = component.get(ref);
			executor.setInput(name, obj);
		}
		
		executor.execute();
		
		int outputLength = serviceDef.getOutputLength();
		for(int i = 0; i < outputLength; i++) {
			OutputDef outputDef = serviceDef.getOutputDef(i);
			this.output.put(outputDef.getName(), component.get(outputDef.getRef()));
		}
	}
	
	public void addInput(String name, Object value) {
		this.input.put(name, value);
	}
	
	public Object getOutput(String name) {
		return this.output.get(name);
	}
}
