/*
 * 
 * Created on Jun 9, 2005
 * 
 * Gy�rgy S�veges
 * Etixpert Kft.
 * Copyright(c) 2005
 * 
 */
package com.etixpert.evolution.workflow;

import com.etixpert.evolution.*;
import org.hibernate.*;
import java.sql.*;
import java.util.*;
import org.apache.log4j.*;
import javax.servlet.http.*;

/**
 * @author Suveges Gyorgy
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */

public abstract class Workflow {
    /**
     * @return Returns the failedOrders.
     */
    public Set getFailedOrders() {
        return failedOrders;
    }
    /**
     * @return Returns the passedOrders.
     */
    public Set getPassedOrders() {
        return passedOrders;
    }
    
    protected int statusFrom, statusTo;
    protected Logger logger = Logger.getLogger("mainControl."+getWorkflowName());
    protected Set failedOrders = new HashSet();
    protected Set passedOrders = new HashSet();
    protected HttpServletRequest request;
    protected HttpServletResponse response;
    protected boolean sentToResponse = false; 
    
    public static Workflow getInstance(int statusFrom, int statusTo) throws Exception {
      Logger logger = Logger.getLogger("mainControl.WorkflowFactory");
     try { 
        logger.info("Creating class com.etixpert.evolution.workflow.Status"+statusFrom+"To"+statusTo);  
        Workflow wf = (Workflow) Class.forName("com.etixpert.evolution.workflow.Status"+statusFrom+"To"+statusTo).newInstance();
        return wf;
        
      } catch(Exception e) {
          
          logger.info("There is no built-in processor for changing status from "+statusFrom +" to "+ statusTo+"\n" +
                  		" Creating DefaultWorkflow");
          
          return new DefaultWorkflow(statusFrom, statusTo);
      }
       
    }
    
    protected Workflow() {
        
    }
    /**
     * 
     */
    protected Workflow(int statusFrom, int statusTo) {
        
        
        this.statusFrom = statusFrom;
        this.statusTo = statusTo;
        // TODO Auto-generated constructor stub
    }
    
    protected abstract void before(Connection conn, Set orders) throws Exception;
    
    protected abstract void changeStatus(Connection conn, Set orders) throws Exception;
    
    protected abstract void after(Connection conn, Set orders) throws Exception;
    
    public void performFlow(Connection conn, Set orders) throws Exception {
        failedOrders.clear(); passedOrders.clear();
        Set oldOrders = new HashSet();
        oldOrders.addAll(orders);
        Transaction tx = null;
        Connection oldConn = conn;
        try {
            
            logger.info("Executing action before changing status");
            before(conn, orders);
           // maybe new connection is needed
            Session session = HibernateUtil.currentSession();
            conn = session.connection();
            if (conn!=oldConn) {
            	logger.info("Getting new connection object. Old one expired");
            	tx = session.beginTransaction();
            }
            
            logger.info("Executing of statuschange");
            changeStatus(conn, orders);
            logger.info("Executing action after changin status");
            after(conn, orders);
        
            passedOrders.addAll(orders);
            oldOrders.removeAll(orders);
            failedOrders.addAll(oldOrders);
            
            if (conn!=oldConn) {
            	logger.info("There was new connection in statuschange. Closing it");
            	tx.commit();
            	HibernateUtil.closeSession();
            }
            
        } catch(Exception e ){
            logger.error("Error generating payment files or rising the status", e);
            if (tx!=null && conn==oldConn) tx.rollback();
            HibernateUtil.closeSession();
            for (Iterator it = oldOrders.iterator(); it.hasNext(); ) 
                failedOrders.add(it.next());
            
        }
        
    }
    
    
    
    public String getWorkflowName() {
        String clazz = this.getClass().getName();
        int i = clazz.lastIndexOf('.');
        if (i<0) return clazz;
        else return clazz.substring(i+1);
    }
    
 
    /**
     * @return Returns the statusFrom.
     */
    public int getStatusFrom() {
        return statusFrom;
    }
    /**
     * @param statusFrom The statusFrom to set.
     */
    public void setStatusFrom(int statusFrom) {
        this.statusFrom = statusFrom;
    }
    /**
     * @return Returns the statusTo.
     */
    public int getStatusTo() {
        return statusTo;
    }
    /**
     * @param statusTo The statusTo to set.
     */
    public void setStatusTo(int statusTo) {
        this.statusTo = statusTo;
    }
    /**
     * @return Returns the request.
     */
    public HttpServletRequest getRequest() {
        return request;
    }
    /**
     * @param request The request to set.
     */
    public void setRequest(HttpServletRequest request) {
        this.request = request;
    }
    
    public void setResponse(HttpServletResponse response) {
        this.response = response;
    }
    
    public boolean sentToResponse() {
        return sentToResponse;
    }
}
