/*
 * Copyright (C) 2005 NTT DATA Corporation
 * 
 */
package org.postgresforest.tool.action;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;

import org.postgresforest.tool.db.GSCdata;
import org.postgresforest.tool.db.UserData;
import org.postgresforest.tool.util.MessagesCommandLine;
//Eclipse依存を排除
//import org.postgresforest.tool.util.MsgDialogUtil;
import org.postgresforest.tool.util.Parser;
import org.postgresforest.tool.util.ReWriter;

/**
 * DDL実行アクション
 * 
 * <pre>
 * 入力情報"ddlform"(DynaValidatorForm)の、DDLをユーザデータベースに対して実行する。
 * DDL文は構文解析を行い、各DDLに対し以下のように処理す津。
 * ・CREATE TABLE
 *   GSCへテーブル情報（forest_tablepart,forest_tablepartdtl）を挿入する
 *   DDLを各ユーザデータベースで実行する。
 * ・DROP TABLE
 *   GSCへテーブル情報（forest_tablepart,forest_tablepartdtl）を削除する
 *   DDLを各ユーザデータベースで実行する。
 * ・ALTER TABLE
 *   指定されたテーブルが、パーティション化テーブルならば
 * 　テーブル名を実テーブルに置換し、実テーブル数分DDLを各ユーザデータベースで実行する。
 * ・CREATE INDEX
 *   指定されたテーブルが、パーティション化テーブルならば
 * 　テーブル名を実テーブル、インデックス名をインデックス名_00（パーティションNo）に置換し、
 * 　実テーブル数分DDLを各ユーザデータベースで実行する。
 * ・その他
 *   DDLを各ユーザデータベースで実行する。
 * 
 * </pre>
 * @see org.apache.struts.validator.DynaValidatorForm
 */
public class ExecDdl extends ActionBase {

//	protected StringBuffer m_results;
	private UserData m_userData;

	/**
	 * @param gsc
	 */
	public ExecDdl(GSCdata gsc, String dbName) {
		super(gsc);
		//ユーザーデータクラスを取得
		m_userData = new UserLoginMng(gsc).getUserDb(dbName);
	}
	/**
	 * DDL実行メイン処理
	 * 
	 * @see org.postgresforest.tool.action.UserActionBase#executeMain(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.http.HttpSession, org.postgresforest.tool.db.GSCdata, org.postgresforest.tool.db.UserData)
	 */
	public boolean executeMain(String ddlSql)  {

		boolean statusOk = false;

		
		
		//ユーザーデータベース名を取得
		
		String dbName = m_userData.getDbName();
		

		//DDL分の抽出
		//';'で区切られた複数のDDLを抽出
		ArrayList sqlList = new ArrayList();
		
		StringTokenizer t = new StringTokenizer( ddlSql, ";" ); //$NON-NLS-1$
		while (t.hasMoreTokens()) {
		    String wkSql =t.nextToken();
		    wkSql = wkSql.replaceFirst("\\s*",""); //$NON-NLS-1$ //$NON-NLS-2$
		    if( wkSql.length() != 0){
		        sqlList.add(wkSql);
		    }
		}


		
		//接続
		if (!connect(m_gsc)
			|| !connect(m_userData)) {
			return false; 
		}
		
		try {
			//DDL数分実行
			for (Iterator iter1 = sqlList.iterator(); iter1.hasNext();) {
				ddlSql = (String) iter1.next();

				System.out.println(MessagesCommandLine.getString("message.ddl.header")); //$NON-NLS-1$
				System.out.println(ddlSql);

				statusOk = false;
				
				//入力されたDDLの構文解析
				Parser paser;
				try {
					ddlSql = ReWriter.toLowerSql(ddlSql);
					paser = new Parser(ddlSql);
				} catch (Exception e) {
					//@@リソース
					System.out.println(MessagesCommandLine.getString("message.ddl.error")); //$NON-NLS-1$
					e.printStackTrace();
					System.out.println(MessagesCommandLine.getString("message.ddl.error.detail") ); //$NON-NLS-1$
					System.out.println("\n\n"); //$NON-NLS-1$
					continue;
				}
				String tableName = null; 
				int partitionCount = 0;
				int type = paser.getType();
				switch (type) {
					case Parser.CREATE_VIEW ://CREATE VIEW を多重化テーブルとして登録する
					case Parser.CREATE_TABLE :
	
						//入力されたDDL文がCREATE TABLE文だった場合、forest_tablepartテーブルとforest_tablepartdtlテーブルへレコードを追加します。
	
						//----------------
						//GSC更新
						//----------------
						if (!m_gsc.addTable(dbName, (String)paser.getTables().get(0)) ) {
							m_gsc.rollback();
							setAccessErrs(m_gsc);
							break; 
						}
						
						//----------------
						//DDL実行
						//----------------
						if (!m_userData.execDdl(ddlSql)) {
							m_gsc.rollback();
							m_userData.rollback();
							setAccessErrs(m_userData);
							break; 
						}
						
						//----------------
						//GSC更新
						//----------------
						if (!m_gsc.updateConfigDate()) {
							m_gsc.rollback();
							setAccessErrs(m_gsc);
							break; 
						}
						
						
						
						m_gsc.commit();
						m_userData.commit();
	
						statusOk = true;
						break;
	
					case Parser.DROP_VIEW ://CREATE VIEW を多重化テーブルとして登録する
					case Parser.DROP_TABLE :
						//入力されたDDL文が、DROP TABLE文だった場合、forest_tablepartテーブルとforest_tablepartdtlテーブルよりレコードを削除します。
	
								
						//----------------
						//GSC更新
						//----------------
						for (Iterator iter = paser.getTables().iterator();
								iter.hasNext();
								) {
		
							tableName = (String)iter.next();
							if (!m_gsc.delTable(dbName, tableName)) {
								m_gsc.rollback();
								setAccessErrs(m_gsc);
								break; 
							}
						}
						//----------------
						//DDL実行
						//----------------
						if (!m_userData.execDdl(ddlSql)) {
							m_gsc.rollback();
							m_userData.rollback();
							setAccessErrs(m_userData);
							break; 
						}

						//----------------
						//GSC更新
						//----------------
						if (!m_gsc.updateConfigDate()) {
							m_gsc.rollback();
							setAccessErrs(m_gsc);
							break; 
						}

						m_gsc.commit();
						m_userData.commit();
	
						statusOk = true;
						break;
	
					case Parser.ALTER_TABLE :
	
	
						//含まれるテーブルが、パーティション化されていれば、実テーブルへリライト
						tableName = (String)paser.getTables().get(0);
						try {
							partitionCount =
								m_gsc.getPartitionCount(dbName, tableName);
						} catch (SQLException e) {
							setAccessErrs(m_gsc);
						}
						if (partitionCount > 1) {
							String ddlSqls[] =
								ReWriter.rewrite(
									ddlSql,
									tableName,
									partitionCount);
	
							//----------------
							//DDL実行
							//----------------
							if (!m_userData.execDdl(ddlSqls)) {
								m_userData.rollback();
								setAccessErrs(m_userData);
								break; 
							}
	
						} else {
							//----------------
							//DDL実行
							//----------------
							if (!m_userData.execDdl(ddlSql)) {
								m_userData.rollback();
								setAccessErrs(m_userData);
								break; 
							}
						}
	
						m_userData.commit();
	
						statusOk = true;
						break;
	
					case Parser.CREATE_INDEX :
	
	
						//含まれるテーブルが、パーティション化されていれば、実テーブルへリライト
						tableName = (String)paser.getTables().get(0);
						try {
							partitionCount =
								m_gsc.getPartitionCount(dbName, tableName);
						} catch (SQLException e1) {
							setAccessErrs(m_gsc);
						}
						if (partitionCount > 1) {
							//indexもパーティションナンバーをつけてリライト
							String ddlSqls[] =
								ReWriter.rewrite(
									ddlSql,
									paser.getReplaceWord(),
									tableName,
									partitionCount);
	
							//----------------
							//DDL実行
							//----------------
							if (!m_userData.execDdl(ddlSqls)) {
								m_userData.rollback();
								setAccessErrs(m_userData);
								break; 
							}
	
						} else {
							//----------------
							//DDL実行
							//----------------
							if (!m_userData.execDdl(ddlSql)) {
								m_userData.rollback();
								setAccessErrs(m_userData);
								break; 
							}
						}
	
						m_userData.commit();
	
						statusOk = true;
						break;
	
					case Parser.DML :
						
					    
					    System.out.println(MessagesCommandLine.getString("message.ddl.skip")); //$NON-NLS-1$
						System.out.print(MessagesCommandLine.getString("message.ddl.result")); //$NON-NLS-1$
						System.out.println(MessagesCommandLine.getString("message.ddl.skip") ); //$NON-NLS-1$
						System.out.println();
						continue;
						
					    
					    
					default :
	
	
						//----------------
						//DDL実行
						//----------------
						if (!m_userData.execDdl(ddlSql)) {
							m_userData.rollback();
							setAccessErrs(m_userData);
							break; 
						}
	
					m_userData.commit();
	
						statusOk = true;
						break;
	
				}
				System.out.print(MessagesCommandLine.getString("message.ddl.result")); //$NON-NLS-1$
				if( statusOk ) {
				    System.out.println(MessagesCommandLine.getString("message.ddl.execute") ); //$NON-NLS-1$
				}else{
				    System.out.println(MessagesCommandLine.getString("message.ddl.error.detail") ); //$NON-NLS-1$
				    System.out.println("\n"); //$NON-NLS-1$
					continue;
				}
				System.out.println("\n"); //$NON-NLS-1$

			}
		} finally {
			m_gsc.close();
			m_userData.close();
		}


		return true;

	}

}
