package org.spbu.benchmark.app;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

import org.spbu.benchmark.LoggingSupport;


import com.progress.open4gl.Open4GLException;
import com.progress.open4gl.RunTime4GLException;
import com.progress.open4gl.SystemErrorException;
import com.progress.open4gl.javaproxy.OpenAppObject;
import com.progress.open4gl.javaproxy.OpenProcObject;
import com.progress.open4gl.javaproxy.ParamArray;
import com.progress.open4gl.javaproxy.ParamArrayMode;

/**
 * <p>
 * Java class for ProcInvocation complex type.
 * 
 * <p>
 * The following schema fragment specifies the expected content contained within
 * this class.
 * 
 * <pre>
 * &lt;complexType name=&quot;ProcInvocation&quot;&gt;
 *   &lt;complexContent&gt;
 *     &lt;restriction base=&quot;{http://www.w3.org/2001/XMLSchema}anyType&quot;&gt;
 *       &lt;sequence&gt;
 *         &lt;element name=&quot;procName&quot; type=&quot;{http://www.w3.org/2001/XMLSchema}string&quot;/&gt;
 *         &lt;element name=&quot;parameter&quot; type=&quot;{}Parameter&quot; maxOccurs=&quot;unbounded&quot; minOccurs=&quot;0&quot;/&gt;
 *       &lt;/sequence&gt;
 *     &lt;/restriction&gt;
 *   &lt;/complexContent&gt;
 * &lt;/complexType&gt;
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.NONE)
@XmlType(name = "ProcInvocation", propOrder = { "procName", "parameter","returnType" })
public class ProcInvocation extends LoggingSupport {
	@XmlElement(required = true)
	protected String procName;
	@XmlElement(required = false)
	protected OEParameter returnType;
	@XmlElement(required = false)	
	protected List<Parameter> parameter;	
	private ParamArray params;
	protected Map<String, Object> context;
	public ProcInvocation(){
		
	}
		public ProcInvocation(String procName, ParamArray params) {
		this.procName = procName;
		this.params = params;
	}
	public void run(OpenAppObject ao) throws SystemErrorException,
			Open4GLException, RunTime4GLException,SQLException {
		mapParams();
		try{
		ao.runProc(procName, params);
		}catch(IndexOutOfBoundsException ie){}
		putReturnValues();
	}

	public void run(OpenProcObject po) throws SystemErrorException,
			Open4GLException, RunTime4GLException,SQLException {
		mapParams();
		po.runProc(procName, params);
		putReturnValues();
	}
	public OpenProcObject createPO(OpenAppObject ao) throws SystemErrorException,
	Open4GLException, RunTime4GLException{
		mapParams();
		return ao.createPO(this.procName, this.params);
	}
	private void mapParams() {
		if(params==null) {
			params = new ParamArray(parameter.size());
			try{
			if(returnType!=null) params.setReturnType(returnType.get());
			}catch(Exception e){log.error("Error setting return type", e);}
		}
		if(parameter!=null)
		for(Parameter p : parameter){
			try{
			params.addParameter(p.getIndex(), p.getParsedValue(), p.getMode(), p.getType().get(), 0, p.getType().getMetaData());
			}catch(Exception e){log.error("Error mapping parameter", e);}
		}
	}
	public void putReturnValues() throws Open4GLException, SQLException {
		if (parameter != null)
			for (Parameter p : parameter) {
				if (p.getMode() != ParamArrayMode.INPUT) {
					Object value = params.getOutputParameter(p.getIndex());
					if (value instanceof com.progress.open4gl.dynamicapi.ResultSet) {
						value = new ProxyResultSet((ResultSet) value);
					}
					if (p.getValue() != null && p.getValue().length() > 3)
						if (p.getValue().startsWith("${")&& p.getValue().endsWith("}")) {
							context.put(p.getValue().substring(2,p.getValue().length() - 1), value);
						}

				}
				if (this.getReturnType() != null)
					context.put(this.procName, params.getReturnValue());
			}
	}
	public ParamArray getParams() {
		if(params==null) mapParams();
		return params;
	}

	public void setParams(ParamArray params) {
		this.params = params;
	}

    /**
     * Gets the value of the returnType property.
     * 
     * @return
     *     possible object is
     *     {@link OEParameter }
     *     
     */
    public OEParameter getReturnType() {
        return returnType;
    }

    public void setReturnType(OEParameter returnType){
    	this.returnType = returnType;
    }
	/**
	 * Gets the value of the procName property.
	 * 
	 * @return possible object is {@link String }
	 * 
	 */
	public String getProcName() {
		return procName;
	}

	/**
	 * Sets the value of the procName property.
	 * 
	 * @param value
	 *            allowed object is {@link String }
	 * 
	 */
	public void setProcName(String value) {
		this.procName = value;
	}

	/**
	 * Gets the value of the parameter property.
	 * 
	 * <p>
	 * This accessor method returns a reference to the live list, not a
	 * snapshot. Therefore any modification you make to the returned list will
	 * be present inside the JAXB object. This is why there is not a
	 * <CODE>set</CODE> method for the parameter property.
	 * 
	 * <p>
	 * For example, to add a new item, do as follows:
	 * 
	 * <pre>
	 * getParameter().add(newItem);
	 * </pre>
	 * 
	 * 
	 * <p>
	 * Objects of the following type(s) are allowed in the list
	 * {@link Parameter }
	 * 
	 * 
	 */
	public List<Parameter> getParameter() {
		if (parameter == null) {
			parameter = new ArrayList<Parameter>();
		}
		return this.parameter;
	}
	public Map<String, Object> getContext() {
		return context;
	}
	public void setContext(Map<String, Object> context) {
		this.context = context;
		if(parameter!=null)
		for(Parameter p : parameter){
			p.setContext(context);
		}
	}
}
