package jp.co.argo21.nautica.workflow.sample.control;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import jp.co.argo21.nautica.workflow.sample.model.AppKind;
import jp.co.argo21.nautica.workflow.sample.model.OvertimeApp;
import jp.co.argo21.nautica.workflow.sample.model.dao.AppKindDAO;
import jp.co.argo21.nautica.workflow.sample.model.dao.AppTransactionDAO;
import jp.co.argo21.nautica.workflow.sample.model.dao.ApplicationDAO;
import jp.co.argo21.nautica.workflow.sample.model.dao.DAOFactory;
import jp.co.argo21.nautica.workflow.sample.model.dao.OvertimeAppDAO;
import jp.co.argo21.nautica.workflow.soap.OrganizationManager;
import jp.co.argo21.nautica.workflow.soap.RoleManager;
import jp.co.argo21.nautica.workflow.soap.ServiceAccessorException;
import jp.co.argo21.nautica.workflow.soap.WorkflowEngineHandler;
import jp.co.argo21.nautica.workflow.soap.WorkflowException;
import jp.co.argo21.nautica.workflow.sample.util.Constants;
import jp.co.argo21.nautica.workflow.sample.util.ResourceManager;
import jp.co.argo21.nautica.workflow.sample.util.ServiceAccessor;
import jp.co.argo21.nautica.workflow.sample.util.StateConstants;
import jp.co.argo21.nautica.workflow.sample.util.StringUtil;
import jp.co.argo21.nautica.workflow.sample.util.UniqueKeyGenerator;
import jp.co.argo21.nautica.workflow.sample.util.WebServiceUtil;
import jp.co.argo21.nautica.workflow.soap.message.Attribute;
import jp.co.argo21.nautica.workflow.soap.message.Organization;
import jp.co.argo21.nautica.workflow.soap.message.Role;
import jp.co.argo21.nautica.workflow.soap.message.User;

/**
 * 申請の準備をする。。
 * 
 * @author stokin
 *
 */
public class PrepareApply extends HttpServlet{

	/**
	 * doPostに処理を委譲する。
	 * 
	 * @param req リクエスト
	 * @param res レスポンス
	 * @throws ServletException 発生しない
	 * @throws IOException forwardに失敗した場合
	 */
	public void doGet(HttpServletRequest req, HttpServletResponse res)
	throws ServletException, IOException {
		doPost(req, res);
	}

	/**
	 * 申請可能一覧を表示し、申請書作成を行う。
	 * 
	 * @param req リクエスト
	 * @param res レスポンス
	 * @throws ServletException 発生しない
	 * @throws IOException forwardに失敗した場合
	 */
	public void doPost(HttpServletRequest req, HttpServletResponse res)
	throws ServletException, IOException {

		HttpSession session = req.getSession(true);
		ResourceManager rm = ResourceManager.getInstance();
		String sessionID = (String)session.getAttribute("sessionID");
		User user = (User)session.getAttribute("user");
		ServletContext context = getServletContext();
		RequestDispatcher dispatcher = null;

		try {
			String path = req.getParameter("screen");

			if(path.equals("Menu")){
				//メニュー画面から来たときは可能申請一覧を表示する
				List<AppKind> appKindList = getAppKindList(user);

				//申請可能な申請種別がないときにはその旨表示する
				if(appKindList.size() == 0){
					req.setAttribute("errMsg", rm.getValue("error.noapp"));
				} else {
					req.setAttribute("appKindList", appKindList);
				}
				
				dispatcher = context.getRequestDispatcher("/AppKindList.jsp");	
			}else if(path.equals("AppKindList")){
				//AppKindListから来たときは申請書を作成する
				String appKindID = req.getParameter("appKindID");

				OvertimeApp application = createApplication(appKindID, sessionID, user);

				req.setAttribute("overtimeApp", application);
				dispatcher = context.getRequestDispatcher("/ApplyInput.jsp");
			}
		} catch (Exception e) {
			// 致命的エラー
			session.invalidate();
			req.setAttribute("errMsg", e.toString());
			req.setAttribute("err", e.getStackTrace());
			dispatcher = context.getRequestDispatcher("/FatalError.jsp");
		}
		dispatcher.forward(req, res);
	}

	
	/**
	 * 可能な申請種別を取得する。
	 * 
	 * @param user ユーザ
	 * @return availableAppKind 可能な申請種別
	 * @throws ServiceAccessorException ロールの取得に失敗した場合
	 * @throws WorkflowException Nauticaでなんらかの処理が失敗した場合
	 * @throws SQLException	 DAOの処理に失敗した場合
	 */
	private List<AppKind> getAppKindList(User user) throws ServiceAccessorException, WorkflowException, SQLException{
		//ユーザに付与されている全てのロールを取得する
		RoleManager roleManager = ServiceAccessor.getInstance().getRoleManager();
		List<Role> roles = roleManager.getAttachedRoles2(user);
		//ユーザに付与されているロールで申請可能な申請種別を取得する
		AppKind[] tempAppKind = null;
		List<AppKind> availableAppKind = new ArrayList<AppKind>();
		AppKindDAO appKindDao = DAOFactory.getAppKindDAO();
		for (Role role : roles) {
			tempAppKind = appKindDao.listAppKindByRole(role.getId());
			if (tempAppKind.length > 0) {
				for (AppKind kind : tempAppKind) {
					availableAppKind.add(kind);
				}
			}
		}
		return availableAppKind;
	}

	
	/**
	 * 申請書を作成する。
	 * 
	 * @param appKindID 申請種別
	 * @param sessionID セッションID
	 * @param user ユーザ
	 * @return application 申請書
	 * @throws Exception 申請書の作成に失敗した場合
	 */
	private OvertimeApp createApplication(String appKindID, String sessionID, User user) throws Exception{

		//申請書番号シーケンスからシーケンス番号を取得し、申請書番号を作成する
		String appID = UniqueKeyGenerator.generate(appKindID);

		//申請トランザクションテーブルにレコードを追加
		String userID = user.getId();
		AppTransactionDAO appTransDao = DAOFactory.getAppTransactionDAO();
		appTransDao.insertForOverTime(appID, appKindID, userID);

		//申請テーブルと時間外労働申請テーブルに空のレコードを追加
		OvertimeAppDAO overtimeDao = (OvertimeAppDAO)DAOFactory.getApplicationDAOFromAppKindID(appKindID);
		overtimeDao.insertAppNo(appID);
		ApplicationDAO appDao = DAOFactory.getApplicationDAO();
		appDao.insert(appID, appKindID, userID);

		//ワークフローのプロセスを作成する
		WorkflowEngineHandler wfEngineHandler = ServiceAccessor.getInstance().getWfEngineHandler();
		String pid = wfEngineHandler.createProcess(sessionID, Constants.PDID, appID);

		// 各プロセス変数を設定
		WebServiceUtil.assignProcessAttribute(sessionID, pid, Constants.STATE, StateConstants.APPLY_WAIT);
		WebServiceUtil.assignProcessAttribute(sessionID, pid, Constants.APPLICATION_NO, appID);
		WebServiceUtil.assignProcessAttribute(sessionID, pid, Constants.APPLICANT_ID, user.getId());
		WebServiceUtil.assignProcessAttribute(sessionID, pid, Constants.APPLICANT_NAME, StringUtil.toFullName(user));
		WebServiceUtil.assignProcessAttribute(sessionID, pid, Constants.APPLICATION_TYPE_CODE, appKindID);

		OrganizationManager orgManager = ServiceAccessor.getInstance().getOrganizationManager();
		List<Organization> org = orgManager.getOrganizationByUser(user);
		//ユーザはひとつの組織にのみ所属するため、0番目を決め打ち
		WebServiceUtil.assignProcessAttribute(sessionID, pid, Constants.ORGANIZATION_CODE, org.get(0).getId());

		AppKindDAO appKindDao = DAOFactory.getAppKindDAO();
		AppKind appkind = appKindDao.getAppKindFromID(appKindID);
		WebServiceUtil.assignProcessAttribute(sessionID, pid, Constants.APPLICATION_TYPE_NAME, appkind.getAppkindName());
		
		//プロセスを開始する
		wfEngineHandler.startProcess(sessionID, pid);
		OvertimeApp application = (OvertimeApp)appDao.getApplicationByID(appID);

		return application;

	}

}