//----------------------------BEGIN LICENSE----------------------------
/* 
 * Willow : the Open Source WorkFlow Project
 * Distributable under GNU LGPL license by gun.org
 *
 * Copyright (C) 2004-2010 huihoo.org 
 * Copyright (C) 2004-2010  ZosaTapo <dertyang@hotmail.com> 
 * 
 * ====================================================================
 * Project Homepage : http://www.huihoo.org/willow
 * Source Forge     : http://sourceforge.net/projects/huihoo
 * Mailing list     : willow@lists.sourceforge.net 
 */
//----------------------------END  LICENSE-----------------------------
package org.huihoo.workflow.coreImpl.store;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Date;

import org.huihoo.commons.jdbc.JDBCFactory;
import org.huihoo.commons.jdbc.JDBCUtilities;
import org.huihoo.workflow.WorkflowException;
import org.huihoo.workflow.WorkflowTransaction;
import org.huihoo.workflow.coreImpl.server.PhantomCaseImpl;
import org.huihoo.workflow.event.CaseEvent;
import org.huihoo.workflow.event.WorkflowEventUtilities;
import org.huihoo.workflow.server.WorkflowCase;
import org.huihoo.workflow.server.WorkflowPath;
import org.huihoo.workflow.server.WorkflowPrimaryKey;
import org.huihoo.workflow.server.WorkflowSession;
import org.huihoo.workflow.server.WorkflowWork;
import org.huihoo.workflow.store.WorkflowCaseDatabase;
import org.huihoo.workflow.store.WorkflowDatabaseImpl;
import org.huihoo.workflow.store.WorkflowTemplate;
import org.huihoo.workflow.usermodel.WorkflowParticipant;
import org.huihoo.workflow.xpdl.WorkflowActivity;
import org.huihoo.workflow.xpdl.WorkflowParameter;
import org.huihoo.workflow.xpdl.WorkflowProcess;

public class WorkflowCaseDatabaseImpl extends WorkflowDatabaseImpl implements WorkflowCaseDatabase
{
	protected transient WorkflowTemplate workflowimpl;
	protected transient InternalCaseDatabase gCaseDBImpl;

	//------------------------------------------------------------------

	public WorkflowCaseDatabaseImpl(WorkflowTemplate workflowimpl)
	{
		this.gCaseDBImpl = new InternalCaseDatabase();
		setWorkflowTemplate(workflowimpl);
	}

	public WorkflowTemplate getWorkflowTemplate()
	{
		return workflowimpl;
	}

	public void setWorkflowTemplate(WorkflowTemplate workflowimpl)
	{
		this.workflowimpl = workflowimpl;
	}

	public WorkflowTransaction getWorkflowTransaction() throws WorkflowException
	{
		WorkflowTransaction userTransaction = null;
		Connection conn = null;
		try
		{
			conn = JDBCFactory.getConnection(getStore());
			conn.setAutoCommit(false);
			//conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
			userTransaction = new WorkflowTransactionImpl(this, conn);
		}
		catch (SQLException sqlex)
		{
			JDBCUtilities.cleanupNoThrow(conn);
			WorkflowException ne = new WorkflowException();
			ne.setRootCause(sqlex);
			throw ne;
		}
		return userTransaction;
	}

	//------------------------------------------------------------------
	//------------------------------------------------------------------

	public String createCase(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowParticipant creator,
		Date creationTime,
		String primaryKey,
		String name,
		String description)
		throws WorkflowException
	{

		PhantomCaseImpl phantomCase =
			new PhantomCaseImpl(null, name, description, workflowProcess, null, null, creationTime, creator);

		CaseEvent event = new CaseEvent(phantomCase, CaseEvent.CASE_CREATED);
		WorkflowEventUtilities.enterEvent(workflowProcess.getCaseListeners(), event);

		String caseId = null;
		try
		{
			Connection conn = transaction.getConnection();
			caseId =
				gCaseDBImpl.createCase_impl(
					session,
					this,
					workflowProcess,
					conn,
					false,
					creator,
					creationTime,
					primaryKey,
					name,
					description);
		}
		catch (WorkflowException we)
		{
			WorkflowEventUtilities.enterEvent(workflowProcess.getCaseListeners(), event);

			throw we;
		}

		event = new CaseEvent(this.findCase(session, transaction, workflowProcess, caseId), CaseEvent.CASE_CREATED);
		WorkflowEventUtilities.leaveEvent(workflowProcess.getCaseListeners(), event);

		return caseId;
	}

	public WorkflowCase findCase(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		String caseId)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		return gCaseDBImpl.findCase_impl(session, this, workflowProcess, conn, false, caseId, false);
	}

	public WorkflowCase findCase(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowPrimaryKey primaryKey)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		return gCaseDBImpl.findCase_impl(session, this, workflowProcess, conn, false, primaryKey.getUUID(), true);
	}

	public void updateCase(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		String description)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		gCaseDBImpl.updateCase_impl(session, this, workflowProcess, conn, false, workflowCase, description);
	}

	public void deleteCase(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		String description)
		throws WorkflowException
	{
		CaseEvent event = new CaseEvent(workflowCase, CaseEvent.DELETED);
		WorkflowEventUtilities.enterEvent(workflowProcess.getCaseListeners(), event);

		try
		{
			Connection conn = transaction.getConnection();
			gCaseDBImpl.deleteCase_impl(session, this, workflowProcess, conn, false, workflowCase, description);
		}
		catch (WorkflowException ne)
		{
			WorkflowEventUtilities.notifyEvent(workflowProcess.getCaseListeners(), event, ne);

			throw ne;
		}

		WorkflowEventUtilities.leaveEvent(workflowProcess.getCaseListeners(), event);
	}

	public void cancelCase(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		String description)
		throws WorkflowException
	{

		CaseEvent event = new CaseEvent(workflowCase, CaseEvent.CANCELED);
		WorkflowEventUtilities.enterEvent(workflowProcess.getCaseListeners(), event);

		try
		{
			Connection conn = transaction.getConnection();
			gCaseDBImpl.changeCaseState_impl(
				session,
				this,
				workflowProcess,
				conn,
				false,
				workflowCase,
				WorkflowCase.CANCELLED,
				description);
		}
		catch (WorkflowException ne)
		{
			WorkflowEventUtilities.notifyEvent(workflowProcess.getCaseListeners(), event, ne);

			throw ne;
		}

		WorkflowEventUtilities.leaveEvent(workflowProcess.getCaseListeners(), event);
	}

	public void completeCase(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase)
		throws WorkflowException
	{
		CaseEvent event = new CaseEvent(workflowCase, CaseEvent.COMPLETED);
		WorkflowEventUtilities.enterEvent(workflowProcess.getCaseListeners(), event);

		try
		{
			Connection conn = transaction.getConnection();
			gCaseDBImpl.changeCaseState_impl(
				session,
				this,
				workflowProcess,
				conn,
				false,
				workflowCase,
				WorkflowCase.COMPLETED,
				"");
		}
		catch (WorkflowException ne)
		{
			WorkflowEventUtilities.notifyEvent(workflowProcess.getCaseListeners(), event, ne);

			throw ne;
		}

		WorkflowEventUtilities.leaveEvent(workflowProcess.getCaseListeners(), event);

	}

	public void confirmCase(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase)
		throws WorkflowException
	{
		CaseEvent event = new CaseEvent(workflowCase, CaseEvent.ARCHIVED);
		WorkflowEventUtilities.enterEvent(workflowProcess.getCaseListeners(), event);

		try
		{
			Connection conn = transaction.getConnection();
			gCaseDBImpl.changeCaseState_impl(
				session,
				this,
				workflowProcess,
				conn,
				false,
				workflowCase,
				WorkflowCase.ARCHIVED,
				"");
		}
		catch (WorkflowException ne)
		{
			WorkflowEventUtilities.notifyEvent(workflowProcess.getCaseListeners(), event, ne);

			throw ne;
		}

		WorkflowEventUtilities.leaveEvent(workflowProcess.getCaseListeners(), event);
	}

	public void suspendCase(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		String description)
		throws WorkflowException
	{
		CaseEvent event = new CaseEvent(workflowCase, CaseEvent.SUSPENDED);
		WorkflowEventUtilities.enterEvent(workflowProcess.getCaseListeners(), event);

		try
		{
			Connection conn = transaction.getConnection();
			gCaseDBImpl.changeCaseState_impl(
				session,
				this,
				workflowProcess,
				conn,
				false,
				workflowCase,
				WorkflowCase.SUSPENDED,
				description);
		}
		catch (WorkflowException ne)
		{

			WorkflowEventUtilities.notifyEvent(workflowProcess.getCaseListeners(), event, ne);

			throw ne;
		}

		WorkflowEventUtilities.leaveEvent(workflowProcess.getCaseListeners(), event);

	}

	public void resumeCase(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		String description)
		throws WorkflowException
	{
		CaseEvent event = new CaseEvent(workflowCase, CaseEvent.RESUMED);
		WorkflowEventUtilities.enterEvent(workflowProcess.getCaseListeners(), event);

		try
		{
			Connection conn = transaction.getConnection();
			gCaseDBImpl.changeCaseState_impl(
				session,
				this,
				workflowProcess,
				conn,
				false,
				workflowCase,
				WorkflowCase.RUNNING,
				description);
		}
		catch (WorkflowException ne)
		{

			WorkflowEventUtilities.notifyEvent(workflowProcess.getCaseListeners(), event, ne);
			throw ne;
		}

		WorkflowEventUtilities.leaveEvent(workflowProcess.getCaseListeners(), event);
	}

	public String createWork(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		WorkflowActivity activity,
		WorkflowWork parentWork,
		WorkflowParticipant performer,
		java.util.Date arriveTime,
		int eventType,
		int priority)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		String workId =
			gCaseDBImpl.createWork_impl(
				session,
				this,
				workflowProcess,
				conn,
				false,
				workflowCase,
				activity,
				parentWork,
				performer,
				arriveTime,
				eventType,
				priority);

		return workId;
	}

	public void updateWork(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		String description)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		gCaseDBImpl.updateWork_impl(session, this, workflowProcess, conn, false, workflowWork, description);
	}

	public void deleteWork(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		String description)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		gCaseDBImpl.deleteWork_impl(session, this, workflowProcess, conn, false, workflowWork, description);
	}

	public WorkflowWork findWork(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		String workId)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		return gCaseDBImpl.findWork_impl(session, this, workflowProcess, conn, false, workflowCase, workId);
	}

	public WorkflowWork findWork(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowTransaction userTransaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		String workId)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		return gCaseDBImpl.findWork_impl(session, this, workflowProcess, conn, false, workflowCase, workId);
	}

	public String createPath(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		WorkflowWork fromWork,
		WorkflowWork toWork,
		String batchNo,
		int eventType)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		String pathId =
			gCaseDBImpl.createPath_impl(
				session,
				this,
				workflowProcess,
				conn,
				false,
				workflowCase,
				fromWork,
				toWork,
				batchNo,
				eventType);
		return pathId;
	}

	public WorkflowPath findPath(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		String pathId)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		return gCaseDBImpl.findPath_impl(session, this, workflowProcess, conn, false, workflowCase, pathId);
	}

	public void deletePath(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowPath workflowPath)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		gCaseDBImpl.deletePath_impl(session, this, workflowProcess, conn, false, workflowPath);

	}

	public void createCaseEvent(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		Date opTime,
		int eventType,
		String description)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		gCaseDBImpl.createCaseEvent_impl(
			session,
			this,
			workflowProcess,
			conn,
			false,
			workflowCase,
			opTime,
			eventType,
			description);

	}

	public void createWorkEvent(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		Date opTime,
		int eventType,
		String description)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();

		gCaseDBImpl.createWorkEvent_impl(
			session,
			this,
			workflowProcess,
			conn,
			false,
			workflowWork,
			opTime,
			eventType,
			description);

	}

	public void createParameter(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		WorkflowParameter parameter)
		throws WorkflowException
	{
		Connection conn = transaction.getConnection();
		gCaseDBImpl.createCaseParameter_impl(session, this, workflowProcess, conn, false, workflowCase, parameter);

	}

	public void updateParameter(
		WorkflowSession session,
		WorkflowTransaction transaction,
		WorkflowProcess workflowProcess,
		WorkflowCase workflowCase,
		WorkflowParameter parameter)
		throws WorkflowException
	{

		Connection conn = transaction.getConnection();
		gCaseDBImpl.updateCaseParameter_impl(session, this, workflowProcess, conn, false, workflowCase, parameter);

	}
}
