package com.interpress_project.modernshare.client.view.wizard;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.Wizard;

import com.interpress_project.modernshare.client.controller.command.SVNCommandFactory;
import com.interpress_project.modernshare.client.controller.command.SVNCommandManager;
import com.interpress_project.modernshare.client.controller.delegate.LocalSVNManager;
import com.interpress_project.modernshare.client.controller.delegate.ORBManager;
import com.interpress_project.modernshare.client.controller.delegate.SVNFolderUtil;
import com.interpress_project.modernshare.client.controller.delegate.exceptions.ConnectionFailException;
import com.interpress_project.modernshare.client.controller.delegate.exceptions.DeleteFailException;
import com.interpress_project.modernshare.client.controller.delegate.exceptions.InternalFailException;
import com.interpress_project.modernshare.client.controller.model.LocalModelManager;
import com.interpress_project.modernshare.client.controller.model.PropertyManager;
import com.interpress_project.modernshare.client.controller.model.RootStatus;
import com.interpress_project.modernshare.client.controller.model.SVNRoot;
import com.interpress_project.modernshare.client.events.LogEvent;
import com.interpress_project.modernshare.client.events.LogEventSource;
import com.interpress_project.modernshare.client.events.LogEventType;
import com.interpress_project.modernshare.client.view.ViewManager;
import com.interpress_project.modernshare.ipcommon.SystemBase;

public class RegisterTargetFolderWizard extends Wizard {
	private final SystemBase sb = SystemBase.getInstance();
	private final ViewManager vmgr = ViewManager.getInstance();
	private final LogEventSource logEventSource = LogEventSource.getInstance();
	private final LocalSVNManager svnmgr = LocalSVNManager.getInstance();
	private final ORBManager orbmgr = ORBManager.getInstance();
	private final SVNCommandManager cmdmgr = SVNCommandManager.getInstance();
	private final SVNCommandFactory factory = SVNCommandFactory.getInstance();

	private final RegWelcomePage regWelcomePage = new RegWelcomePage();
	private final RegWizardPage1 regWizardPage1 = new RegWizardPage1();
	private final RegWizardPage2 regWizardPage2;
	private final RegWizardPage3 regWizardPage3 = new RegWizardPage3();
	private final RegConfirmPage regConfirmPage = new RegConfirmPage();

	/**
	 * RegisterTargetFolderWizard
	 * @param list
	 */
	public RegisterTargetFolderWizard(ArrayList<SVNRoot> list) {
		addPage(regWelcomePage);
		addPage(regWizardPage1);
		regWizardPage2 = new RegWizardPage2(list);
		addPage(regWizardPage2);
		addPage(regWizardPage3);
		addPage(regConfirmPage);

		setNeedsProgressMonitor(true);
		setWindowTitle("ホットショット・フォルダ - 登録ウィザード");
	}

	/**
	 * performFinish
	 */
	@Override
	public boolean performFinish() {
		/**
		 * スレッドの定義
		 */
		IRunnableWithProgress op = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException {
				registerTargetFolder(monitor);
			}
		};
		/**
		 * 上記スレッドの実行
		 */
		try {
			logEventSource.fireEvent(new LogEvent(this, LogEventType.CLEAR));

			getContainer().run(true, true, op);
		}
		catch (Exception ex) {
			logEventSource.fireEvent(new LogEvent(this, ex.getMessage(), LogEventType.ERROR, ex));
			vmgr.getDialogManager().createErrorMessageDialog(ex.getMessage());
			return false;
		}
		return true;
	}

	/**
	 * registerTargetFolder
	 * 
	 * @param monitor
	 * @throws InvocationTargetException
	 */
	private void registerTargetFolder(IProgressMonitor monitor) throws InvocationTargetException {
		File path = new File(regWizardPage1.getPath());
		String tagName = regWizardPage2.getTagName();
		RootStatus rootStatus = regWizardPage3.getStatus();
		boolean bPc2host = regWizardPage3.getPc2host();
		File[] files = null;
		String msg = null;

		PropertyManager propmgr = PropertyManager.getInstance();

		monitor.beginTask("", 9);

		// Step. 1
		msg = "データセンタからアクセス情報を取得しています...";
		monitor.subTask(msg);
		logEventSource.fireEvent(new LogEvent(this, msg, LogEventType.INFO));
		try {
			orbmgr.updateSVNServerInfo();
		}
		catch (Exception ex) {
			throw new InvocationTargetException(ex, ex.getMessage());
		}
		finally {
			monitor.worked(1);
		}

		// Step.2 
		msg = "ホットショット・フォルダとして登録するフォルダの内容をチェックします。お待ちください...";
		monitor.subTask(msg);
		logEventSource.fireEvent(new LogEvent(this, msg, LogEventType.INFO));
		SVNFolderUtil futil = SVNFolderUtil.getInstance();
		ArrayList<File> svnlist = futil.getSVNDirListInTarget(path);

		if (svnlist.size() > 0) {
			boolean bAnswer = vmgr.getDialogManager().createYesNoMessageDialog("ホットショット・フォルダの確認",
			  "指定されたフォルダ" + path + "は既にHotShotで管理されています。一旦HotShotでの管理を解除しますか?");
			if (bAnswer) {
				msg = "登録するフォルダから.svnフォルダを削除しています...";
				monitor.subTask(msg);
				logEventSource.fireEvent(new LogEvent(this, msg, LogEventType.INFO));
				try {
					futil.deleteFiles(svnlist);
				}
				catch (DeleteFailException ex) {
					throw new InvocationTargetException(ex, ex.getMessage());
				}
			}
			else {
				throw new InvocationTargetException(null, "HotShotで管理されたフォルダを登録することはできません。");
			}
		}
		monitor.worked(1);

		SystemBase.getInstance().gc(); // Sync FS

		// Step.3
		msg = "データセンタに接続しています...";
		monitor.subTask(msg);
		logEventSource.fireEvent(new LogEvent(this, msg, LogEventType.INFO));
		try {
			svnmgr.connect();
		}
		catch (ConnectionFailException ex) {
			throw new InvocationTargetException(ex, ex.getMessage());
		}
		monitor.worked(1);

		// Step.4
		msg = "ホットショット・フォルダ" + path + "を初期化しています...";
		monitor.subTask(msg);
		logEventSource.fireEvent(new LogEvent(this, msg, LogEventType.INFO));
		try {
			checkout(path, tagName);
		}
		catch (InternalFailException ex) {
			throw new InvocationTargetException(ex, ex.getMessage());
		}
		monitor.worked(1);

		// Step.5
		msg = "ホットショット・フォルダにあるデータを登録しています...";
		monitor.subTask(msg);
		logEventSource.fireEvent(new LogEvent(this, msg, LogEventType.INFO));
		try {
			files = registerLocalFiles(path);
		}
		catch (InternalFailException ex) {
			throw new InvocationTargetException(ex, ex.getMessage());
		}
		monitor.worked(1);

		// Step.6
		msg = "データを送信しています...";
		monitor.subTask(msg);
		logEventSource.fireEvent(new LogEvent(this, msg, LogEventType.INFO));
		try {
			commit(path, files);
		}
		catch (InternalFailException ex) {
			throw new InvocationTargetException(ex, ex.getMessage());
		}
		monitor.worked(1);

		// Step.7
		msg = "Readmeファイルを作成しています...";
		monitor.subTask(msg);
		logEventSource.fireEvent(new LogEvent(this, msg, LogEventType.INFO));
		if (bPc2host) {
			new NoticeFile(path.getAbsolutePath(), propmgr.getIgnoreFilterList(), false).create();
		}
		else {
			new NoticeFile(path.getAbsolutePath(), propmgr.getIgnoreFilterList(), true).create();
		}
		monitor.worked(1);

		// Step.8
		msg = "設定ファイルを保存しています...";
		monitor.subTask(msg);
		logEventSource.fireEvent(new LogEvent(this, msg, LogEventType.INFO));
		LocalModelManager limgr = LocalModelManager.getInstance();
		limgr.addRoot(path.getAbsolutePath(), tagName, rootStatus, bPc2host);
		monitor.worked(1);

		// Gabage collector
		sb.gc();

		// Step.9
		monitor.subTask("リフレッシュをしています...");
		//		new RefreshAction(vmgr).run();
		cmdmgr.addCommand(factory.createRemoteRefreshCommand());
		monitor.worked(1);

		monitor.done();
	}

	/**
	 * checkout
	 * @param path
	 * @param tagName
	 * @throws InternalFailException
	 */
	private void checkout(File rootpath, String tagName) throws InternalFailException {
		svnmgr.initialCheckoutFolder(rootpath, tagName);
	}

	/**
	 * registerLocalFiles
	 * @param path
	 * @throws InternalFailException
	 */
	private File[] registerLocalFiles(File rootpath) throws InternalFailException {
		return svnmgr.initialRegisterFiles(rootpath);
	}

	/**
	 * commit
	 * @param path
	 * @throws InternalFailException
	 */
	private void commit(File rootpath, File[] pathes) throws InternalFailException {
		svnmgr.commitDirectory(rootpath, pathes);
	}
}
