/*
 * 作成日: 2008/08/05
 * 著作権: Copyright (c) 2005 ZIGEN
 * ライセンス：Eclipse Public License - v 1.0
 * 原文：http://www.eclipse.org/legal/epl-v10.html
 */
package zigen.plugin.db.ext.s2jdbc.ui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.ide.IDE;

import zigen.plugin.db.core.IDBConfig;
import zigen.plugin.db.core.TableColumn;
import zigen.plugin.db.ext.s2jdbc.Activator;
import zigen.plugin.db.ext.s2jdbc.ICodeGenerator;
import zigen.plugin.db.ui.actions.ITableViewEditorAction;
import zigen.plugin.db.ui.editors.ITableViewEditor;
import zigen.plugin.db.ui.editors.QueryViewEditor2;

public abstract class DefaultGenerateDtoAction extends Action implements ITableViewEditorAction {
	
	protected String project;
	
	protected ITableViewEditor editor;
	
	protected String query;
	
	protected TableColumn[] columns;
	
	protected IDBConfig config;
	
	protected TableViewer structuredViewer;
	
	protected IStructuredSelection selection;
	
	public void selectionChanged(ISelection _selection) {
		if (_selection instanceof IStructuredSelection) {
			this.selection = (IStructuredSelection) _selection;
		} else {
			this.selection = null;
		}
	}
	
	public void setActiveEditor(ITableViewEditor target) {
		this.project = Activator.getDefault().getDefaultProject();
		
		editor = target;
		if (target != null) {
			columns = target.getHeaderTableElement().getColumns();
			structuredViewer = target.getViewer();
			config = target.getDBConfig();
			if (target instanceof QueryViewEditor2) {
				QueryViewEditor2 e = (QueryViewEditor2) target;
				this.query = e.getQuery();
			}
		}
	}
	
	/**
	 * コンストラクタ
	 * 
	 * @param viewer
	 * @param defaultPackage
	 *            ダイアログ表示時の選択しておくプロジェクト
	 */
	public DefaultGenerateDtoAction() {
		super();
	}
	
	
	/**
	 * Action実行時の処理
	 */
	public void run() {
		try {
			// カラムの重複チェック
			checkColumn(columns);
			
			Shell shell = Activator.getDefault().getShell();
			DtoWizard wizard = new DtoWizard();
			WizardDialog dialog = new WizardDialog(shell, wizard);
			int res = dialog.open();
			
			if (res == WizardDialog.OK) {
				PackageFragment pkg = wizard.getPackageFragment();
				this.project = pkg.getJavaProject().getElementName();
				
				Activator.getDefault().setDefaultProject(project);
				
				String queryName = wizard.getName();
				
				invoke(pkg, createDtoGenerator(queryName, columns));
			}
		} catch (Exception e) {
			Activator.getDefault().showErrorDialog(e);
		}
		
	}
	
	abstract public String getTitle();
	
	abstract public String getMessage();
	
	abstract public ICodeGenerator createDtoGenerator(String queryName, TableColumn[] columns) throws Exception;
	
	
	/**
	 * カラムの重複チェック
	 * 
	 * @param columns
	 * @throws Exception
	 */
	public void checkColumn(TableColumn[] columns) throws Exception {
		List multi = new ArrayList();
		
		// 重複したカラム名を取り除く処理
		List list = new ArrayList();
		HashMap map = new HashMap();
		for (int i = 0; i < columns.length; i++) {
			if (!map.containsKey(columns[i].getColumnName())) {
				list.add(columns[i]);
				map.put(columns[i].getColumnName(), columns[i]);
			} else {
				multi.add(columns[i].getColumnName());
			}
			
		}
		if (multi.size() > 0) {
			StringBuffer sb = new StringBuffer();
			sb.append("項目(Column)に、重複したものがありますので、取り除いてください\n");
			for (Iterator iter = multi.iterator(); iter.hasNext();) {
				sb.append((String) iter.next() + "\n");
			}
			
			throw new Exception(sb.toString());
		}
	}
	
	/**
	 * Javaソース作成処理
	 * 
	 * @param pkg
	 *            保存するパッケージ名
	 * @param creator
	 *            対象のコードジェネレータ
	 */
	private void invoke(PackageFragment pkg, ICodeGenerator creator) {
		
		try {
			creator.execute();
			String fileName = creator.getClassName() + ".java";
			if (existFile(pkg, fileName)) {
				Shell shell = Activator.getDefault().getShell();
				MessageBox msg = new MessageBox(shell, SWT.YES | SWT.NO | SWT.ICON_QUESTION);
				msg.setMessage(fileName + "が存在します。上書きしますか？");
				msg.setText("上書き確認");
				int res2 = msg.open();
				if (res2 == SWT.NO)
					return;
			}
			
			// パッケージ名の設定
			creator.setPackageString(pkg.getElementName());
			// Javaファイルの作成
			createFileAndOpen(pkg, fileName, creator.genaratedString());
			
		} catch (Exception e) {
			Activator.getDefault().showErrorDialog(e);
		}
		
	}
	
	protected void createFileAndOpen(PackageFragment pkg, String fileName, String contents) throws JavaModelException, PartInitException {
		pkg.createCompilationUnit(fileName, contents, true, new NullProgressMonitor());
		
		// String javaProjectName = pkg.getJavaProject().getElementName();
		String pkgName = pkg.getElementName().replace('.', '/');
		String srcPath = pkg.getPackageFragmentRoot().getPath().toString(); // これではSRCしか取れない
		
		// 任意のソースフォルダ場所に保存できるように修正
		IContainer container = pkg.getJavaProject().getProject().getParent();
		IPath path = new Path(srcPath + "/" + pkgName + "/" + fileName); //$NON-NLS-1$ //$NON-NLS-2$
		IFile file = container.getFile(path);
		
		IWorkbenchPage page = Activator.getDefault().getPage();
		
		IDE.openEditor(page, file);
	}
	
	// ファイルの存在チェック
	protected boolean existFile(PackageFragment pkg, String checkFile) throws JavaModelException {
		IJavaElement[] javaElems = pkg.getChildren();
		for (int i = 0; i < javaElems.length; i++) {
			IJavaElement element = javaElems[i];
			if (element.getElementName().equals(checkFile)) {
				return true;
			}
		}
		return false;
	}
	
}
