package org.spbu.benchmark.app;

import java.util.ArrayList;
import java.util.HashMap;
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.Action;
import org.spbu.benchmark.ActionResult;
import org.spbu.benchmark.BenchmarkException;
import org.spbu.benchmark.LoggingSupport;
import org.spbu.benchmark.Scenario;


import com.progress.open4gl.javaproxy.Connection;
import com.progress.open4gl.javaproxy.OpenAppObject;
/**
 * <p>Java class for AppScenario complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="AppScenario">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="url" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="serviceName" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="username" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="password" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="action" type="{}AppAction" maxOccurs="unbounded"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.NONE)
@XmlType(name = "AppScenario", propOrder = {
    "url",
    "serviceName",
    "username",
    "password",
    "actions"
})
public class AppScenario extends LoggingSupport implements Scenario {
    @XmlElement(required = true)
	private List<AppAction> actions;
	@XmlElement(required = true)
	protected String url;
	@XmlElement(required = true)
	protected String serviceName;
	@XmlElement(required = false)	
	protected String username;
	@XmlElement(required = false)	
	protected String password;    
	private OpenAppObject appObject;
	private Connection conn;
	private Map<String, Object> context = new HashMap<String, Object>();
	public AppScenario(String url, String username, String password, String serviceName){
		conn = new Connection(url,username,password,"");
		conn.setWaitIfBusy();
		this.serviceName = serviceName;
		this.url = url;
		this.username = username;
		this.password = password;
		this.actions = new ArrayList<AppAction>();
	}
	public AppScenario(Connection conn, String serviceName){
		this.conn = conn;
		this.serviceName = serviceName;
	}
	public AppScenario(){
		this.conn = null;
	}
	public void addAction(Action action) {
		AppAction appAction = (AppAction)action;
		this.actions.add(appAction);
	}
	private int model = 0;
	public void setSessionModel(int model){
		this.model = model;
	}
	public AppScenarioResult start() throws BenchmarkException {
		AppScenarioResult result;
		this.setContext(context);
		try{
			if(conn==null) {
				conn = new Connection(url,username,password,"");
				conn.setWaitIfBusy();	
			}
			conn.setSessionModel(model);			
			appObject = new OpenAppObject(conn, serviceName);
			List<ActionResult> actionResults = new ArrayList<ActionResult>();
			long time = 0;
			if(actions!=null)
			for(AppAction action : actions){
				if(this.model==1){
					this.conn.releaseConnection();
					appObject._release();
					appObject = new OpenAppObject(conn,serviceName);
				}
				action.setAppObject(appObject);
				ActionResult actionResult = action.invoke();
				
		        time += actionResult.getTime();
		        actionResults.add(actionResult);
			}
			for(AppAction action : actions){
				if(action instanceof PersistentAppAction){
					try{((PersistentAppAction)action).getProcObject()._release();}
					catch(Exception e){}
				}
			}
			conn.releaseConnection();
			result = new AppScenarioResult(actionResults, true, time);			
		}catch(Exception e){
			throw new BenchmarkException("Error in scenario", e);
		}finally{
			if(appObject!=null) try{
				appObject._release();
			}catch(Exception e){}
		}
		return result;
	}
	public void kill(){
		try{
			this.appObject._cancelAllRequests();
			this.appObject._release();
		}catch(Exception e){
			log.error("Error shutting down thread",e);
		}
	}

	    /**
	 * Gets the value of the url property.
	 * 
	 * @return
	 *     possible object is
	 *     {@link String }
	 *     
	 */
	public String getUrl() {
		return url;
	}

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

	/**
	 * Gets the value of the serviceName property.
	 * 
	 * @return
	 *     possible object is
	 *     {@link String }
	 *     
	 */
	public String getServiceName() {
		return serviceName;
	}

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

	/**
	 * Gets the value of the username property.
	 * 
	 * @return
	 *     possible object is
	 *     {@link String }
	 *     
	 */
	public String getUsername() {
		return username;
	}

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

	/**
	 * Gets the value of the password property.
	 * 
	 * @return
	 *     possible object is
	 *     {@link String }
	 *     
	 */
	public String getPassword() {
		return password;
	}

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

	/**
	 * Gets the value of the action 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 action property.
	 * 
	 * <p>
	 * For example, to add a new item, do as follows:
	 * <pre>
	 *    getAction().add(newItem);
	 * </pre>
	 * 
	 * 
	 * <p>
	 * Objects of the following type(s) are allowed in the list
	 * {@link AppAction }
	 * 
	 * 
	 */
	public List<AppAction> getActions() {
		if (actions == null) {
			actions = new ArrayList<AppAction>();
		}
		return this.actions;
	}
	public Map<String, Object> getContext() {
		return context;
	}
	public void setContext(Map<String, Object> context) {
		this.context = context;
		for(AppAction action : this.actions){
			action.setContext(context);
		}
	}
}
