package jp.mosp.common;

import java.sql.Connection;
import java.sql.SQLException;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import jp.mosp.common.CommonConst;
import jp.mosp.common.common.BaseDao;
import jp.mosp.common.common.MospException;
import jp.mosp.common.dto.CmAspUserDto;
import jp.mosp.common.dto.CmUserDto;

/**
 * テーブルロックユーティリティ
 * @author yoshida
 *	@version	0.0.1
 */
public class TableLockUtility {

	private static final String FLD_TABLE = "TABLE";

	private LockTableDao tableLock;
	private List<String> tableList;

	/**
	 * コンストラクタ
	 */
	public TableLockUtility() {

	}

	/**
	 * コンストラクタ(初期化)
	 */
	public TableLockUtility(Properties cfg, String cmd, CmAspUserDto aspUser, CmUserDto user, Connection conn) {
		init(cfg, cmd, aspUser, user, conn);
		setTableList(getTableInitList());
	}

	/**
	 * 初期化
	 * @param cfg
	 * @param cmd
	 * @param aspUser
	 * @param user
	 * @param conn
	 */
	public void init(Properties cfg, String cmd, CmAspUserDto aspUser, CmUserDto user, Connection conn) {
		tableLock = new LockTableDao();
		tableLock.initDao(cfg, cmd, aspUser, user, conn);
	}

	/**
	 * テーブルロック(WRITE)
	 * @throws Exception
	 */
	public void lockTables() throws Exception {
		tableLock.lockTables(tableList);
	}

	/**
	 * テーブルロック
	 * @param tableList		対象テーブルDAO一覧
	 * @throws Exception
	 */
	public void lockTables(List<String> tableList) throws Exception {
		setTableList(tableList);
		lockTables();
	}

	/**
	 * テーブルロック解除
	 * @throws Exception
	 */
	public void unLockTables() throws Exception {
		tableLock.unLockTables();
	}

	/**
	 * 対象テーブルDAO一覧初期化
	 * @return
	 */
	public List<String> getTableInitList() {
		return new ArrayList<String>();
	}

	/**
	 * 対象テーブルDAO一覧設定
	 * @param tableSet
	 */
	public void setTableList(List<String> tableList) {
		this.tableList = tableList;
	}

	/**
	 * 対象テーブルDao追加
	 * @param dao
	 */
	public void addTargetTable(BaseDao dao, boolean isWrite) {
		this.tableList = this.tableList == null ? this.tableList = getTableInitList() : this.tableList;
		StringBuffer sb = new StringBuffer();
		sb.append(getTableName(dao));
		sb.append(CommonConst.STR_UNDER_SEPARATOR);
		sb.append(isWrite);		
		tableList.add(sb.toString());
	}

	/**
	 * 対象テーブルDao追加
	 * @param dao
	 */
	public void addTargetTable(String tableName, boolean isWrite) {
		this.tableList = this.tableList == null ? this.tableList = getTableInitList() : this.tableList;
		StringBuffer sb = new StringBuffer();
		sb.append(tableName);
		sb.append(CommonConst.STR_UNDER_SEPARATOR);
		sb.append(isWrite);		
		tableList.add(sb.toString());
	}

	/**
	 * 対象テーブル名取得
	 * @param dao		対象DAO
	 * @return	対象テーブル名
	 */
	public String getTableName(BaseDao dao) {
		String tableName = "";
		try {
			tableName = (String)dao.getClass().getField(FLD_TABLE).get(null);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		return tableName;
	}

	/**
	 * 対象テーブル名取得
	 * @param dao		対象DAO
	 * @param fieldName
	 * @return
	 */
	public String getTableName(BaseDao dao, String fieldName) {
		String tableName = "";
		try {
			tableName = (String)dao.getClass().getField(fieldName).get(null);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		return tableName;
	}

	/**
	 * テーブルロック用DAO
	 * @author yoshida
	 * @version 0.0.2
	 */
	private static class LockTableDao extends BaseDao {

		/**
		 * コンストラクタ
		 */
		public LockTableDao() {
			super();
		}

		/**
		 * テーブルロック
		 * @param tableList			対象テーブル情報一覧
		 * @throws SQLException
		 * @throws SecurityException
		 * @throws IllegalArgumentException
		 * @throws IllegalAccessException
		 * @throws NoSuchFieldException
		 * @throws MospException
		 */
		public void lockTables(
				List<String> tableList
		) throws SQLException, SecurityException, IllegalArgumentException, IllegalAccessException, NoSuchFieldException, MospException {
			try {
				prepareStatement(getLockTableSQL(tableList));
				executeUpdate();
			} catch (SQLException e) {
				throw e ;
			} finally {
				releaseResultSet();
				releasePreparedStatement();
			}
		}

		/**
		 * テーブルロック解除
		 * @throws SQLException
		 * @throws MospException 
		 */
		public void unLockTables() throws SQLException, MospException{
			if (getRdbmsType() == 1) {
				try {
					prepareStatement("UNLOCK TABLES ");
					executeUpdate();
				} catch (SQLException e) {
					throw e ;
				} finally {
					releaseResultSet();
					releasePreparedStatement();
				}
			}
		}

		/**
		 * テーブルロック用SQL生成
		 * @param tableList		対象テーブル情報一覧
		 * @return
		 * @throws MospException
		 */
		private String getLockTableSQL(List<String> tableList) throws MospException {
			StringBuffer sb = new StringBuffer();
			switch (getRdbmsType()) {
			case 1:
				// MySQLの場合
				sb.append("LOCK TABLES ");
				for (String table : tableList) {
					String[] code = table.split(CommonConst.STR_UNDER_SEPARATOR);
					sb.append(code[0]);
					if (Boolean.parseBoolean(code[1])) {
						sb.append(" WRITE ");
					} else {
						sb.append(" READ ");
					}
					sb.append(CommonConst.STR_UNDER_SEPARATOR);
				}
				sb.delete(sb.lastIndexOf(CommonConst.STR_UNDER_SEPARATOR), sb.length());
				break;
			case 2:
				// PostgreSQLの場合
				sb.append("LOCK TABLE ");
				for (String table : tableList) {
					String[] code = table.split(CommonConst.STR_UNDER_SEPARATOR);
					if (Boolean.parseBoolean(code[1])) {
						sb.append(code[0]);
						sb.append(CommonConst.STR_UNDER_SEPARATOR);
					}
				}
				sb.delete(sb.lastIndexOf(CommonConst.STR_UNDER_SEPARATOR), sb.length());
				break;
			default:
				break;
			}
			return sb.toString();
		}

	}

}
