package com.interpress_project.modernshare.client.view;

import java.io.File;

import org.eclipse.jface.action.CoolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.StatusLineManager;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

import com.interpress_project.modernshare.client.controller.actions.ExitAction;
import com.interpress_project.modernshare.client.controller.actions.ImageFactory;
import com.interpress_project.modernshare.client.controller.actions.StartupSyncAction;
import com.interpress_project.modernshare.client.controller.command.SVNCommandManager;
import com.interpress_project.modernshare.client.controller.command.TaskManager;
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.secureguard.SVNproxy;
import com.interpress_project.modernshare.client.controller.model.LocalModelManager;
import com.interpress_project.modernshare.client.controller.model.PropertyManager;
import com.interpress_project.modernshare.client.events.GUIEvent;
import com.interpress_project.modernshare.client.events.GUIEventSource;
import com.interpress_project.modernshare.client.events.IGUIEventListener;
import com.interpress_project.modernshare.client.events.ILocalViewEventListener;
import com.interpress_project.modernshare.client.events.ILogEventListener;
import com.interpress_project.modernshare.client.events.IRemoteViewEventListener;
import com.interpress_project.modernshare.client.events.LocalViewEvent;
import com.interpress_project.modernshare.client.events.LocalViewEventSource;
import com.interpress_project.modernshare.client.events.LogEvent;
import com.interpress_project.modernshare.client.events.LogEventSource;
import com.interpress_project.modernshare.client.events.RemoteViewEvent;
import com.interpress_project.modernshare.client.events.RemoteViewEventSource;
import com.interpress_project.modernshare.ipcommon.SystemBase;

/**
 * Represents a singleton.
 * 
 * @stereotype Manager
 */
public class ViewManager extends ApplicationWindow implements ILocalViewEventListener, IRemoteViewEventListener,
    ILogEventListener, IGUIEventListener {
	/**
	 * @stereotype creates
	 */
	/*#com.interpress_project.modernshare.client.view.MfMenuBar Dependency20*/

	/**
	 * @stereotype creates
	 */
	/*#com.interpress_project.modernshare.client.view.MfCoolBar Dependency201*/

	/**
	 * @stereotype creates
	 */
	/*#com.interpress_project.modernshare.client.view.MfTaskTray Dependency202*/

	/**
	 * @supplierCardinality 0...1
	 */
	private MfCoolBar aCoolBar;

	/*#com.interpress_project.modernshare.client.view.MfContents Dependency203*/

	/**
	 * Holds singleton instance
	 */
	private static ViewManager instance;

	private final SystemBase sb = SystemBase.getInstance();
	private MfContents aContents;
	private DialogManager dlgmgr;
	private SVNproxy proxy = null;

	/**
	 * ViewManager
	 */
	public ViewManager() {
		super(null);

		addMenuBar();
		addCoolBar(SWT.FLAT | SWT.WRAP);
		addStatusLine();
	}

	/**
	 * Returns the singleton instance.
	 * @return the singleton instance
	 */
	static public ViewManager getInstance() {
		if (instance == null) {
			instance = new ViewManager();
		}
		return instance;
	}

	/**
	 * run()
	 */
	public void run() {
		setBlockOnOpen(true);
		open();
		Display.getCurrent().dispose();
	}

	/**
	 * getDialogManager
	 * @return
	 */
	public DialogManager getDialogManager() {
		return dlgmgr;
	}

	/**
	 * createMenuManager (Step.1)
	 */
	protected MenuManager createMenuManager() {
		return new MfMenuBar(this);
	}

	/**
	 * createCoolBarManager (Step.2)
	 */
	protected CoolBarManager createCoolBarManager(int style) {
		aCoolBar = new MfCoolBar(this, style);
		return aCoolBar;
	}

	/**
	 * createStatusLineManager (Step.3)
	 */
	protected StatusLineManager createStatusLineManager() {
		return new StatusLineManager();
	}

	/**
	 * configureShell (Step.4)
	 */
	protected void configureShell(final Shell shell) {
		super.configureShell(shell);

		/**
		 * Windows廃棄時のハンドラ処理実装
		 */
		shell.addDisposeListener(new DisposeListener() {
			/**
			 * アプリケーション終了ハンドラ
			 */
			public void widgetDisposed(DisposeEvent disposeEvent) {
				sb.getLogger().debug("Enter Housekeeping.");

				LogEventSource.getInstance().removeEventListener(ViewManager.getInstance());
				LocalViewEventSource.getInstance().removeEventListener(ViewManager.getInstance());
				RemoteViewEventSource.getInstance().removeEventListener(ViewManager.getInstance());
				GUIEventSource.getInstance().removeEventListener(ViewManager.getInstance());
				
				/**
				 * Storing client XML data to the datacenter.
				 */
				try {
					ORBManager.getInstance().storeClientData();
				}
				catch (Exception ex) {
					sb.getLogger().error("XML設定ファイルをリモート保存中にエラーが発生しました。: " + ex.getCause().getMessage());
				}

				LocalModelManager lmmgr = LocalModelManager.getInstance();
				lmmgr.dispose();

				SVNCommandManager commandManager = SVNCommandManager.getInstance();
				commandManager.dispose();

				TaskManager taskmgr = TaskManager.getInstance();
				taskmgr.dispose();

				ImageFactory.getInstance().dispose();

				Rectangle rectangle = shell.getBounds();
				PropertyManager propmgr = PropertyManager.getInstance();
				propmgr.setFramePosition(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
				propmgr.store();
				proxy.dispose();

				sb.getLogger().debug("Client terminated.");
			}
		});
		shell.addShellListener(new ShellListener() {
			public void shellActivated(ShellEvent arg0) {
			}

			public void shellClosed(ShellEvent arg0) {
			}

			public void shellDeactivated(ShellEvent arg0) {
			}

			public void shellDeiconified(ShellEvent arg0) {
			}

			public void shellIconified(ShellEvent e) {
				((Shell) (e.widget)).setVisible(false);
			}
		});
	}

	/**
	 * createContents (Step.5) 
	 * Contentの生成処理のためのコールバック。ちなみにこの時点で初めてshellが設定される。
	 * @param parent Composite
	 * @return Control
	 */
	protected Control createContents(Composite parent) {
		aContents = new MfContents(this, parent, SWT.NONE);
		return parent;
	}

	/**
	 * initializeBounds (Step.6)
	 * ウィンドウフレーム設定処理。初期化ダイアログなどを表示するならばここ。
	 */
	protected void initializeBounds() {
		super.initializeBounds();

		final Shell shell = getShell();

		dlgmgr = new DialogManager(this);

		/**
		 * プロパティマネージャの設定
		 */
		PropertyManager propmgr = PropertyManager.getInstance();
		String filename = propmgr.getPropFileName();
		if (!new File(filename).exists()) {
			String msg = "HotShotクライアントの設定ファイルが見つかりませんでした。アカウント情報とデータセンタ情報を設定してください。";
			if (!dlgmgr.createYesNoMessageDialog("HotShotクライアントの設定", msg)) {
				System.exit(-1);
				return;
			}
			dlgmgr.createPreferenceDialog();
		}

		/**
		 * フレーム位置の設定
		 */
		int[] framepos = propmgr.getFramePosition();
		shell.setBounds(new Rectangle(framepos[0], framepos[1], framepos[2], framepos[3]));

		/**
		 * タスクトレイ
		 */
		new MfTaskTray(this);

		/**
		 * ウィンドウタイトルにファイル名を表示
		 */
		getShell().setText("InterPress - HotShot");
		getShell().setImage(ImageFactory.getInstance().getImage("sync"));

		/**
		 * Re layout when coolbar is resized.
		 */
		aCoolBar.getControl().addControlListener(new ControlAdapter() {
			public void controlResized(ControlEvent arg0) {
				aCoolBar.getControl().getParent().layout();
			}
		});

		LogEventSource.getInstance().addEventListener(this);
		LocalViewEventSource.getInstance().addEventListener(this);
		RemoteViewEventSource.getInstance().addEventListener(this);
		GUIEventSource.getInstance().addEventListener(this);

		/**
		 * Boot up secure guard.
		 */
		proxy = new SVNproxy();
		proxy.start();

		/**
		 * Initialize ORBManager
		 */
		ORBManager.getInstance();

		/**
		 * File Folder utils.
		 */
		SVNFolderUtil.getInstance();

		/**
		 * Initialize SVN CommandManager
		 */
		SVNCommandManager commandManager = SVNCommandManager.getInstance();
		commandManager.start();

		/**
		 * Initialize Local ModelManager
		 * XMLファイルをダウンロードするため、ここではload()を行わないこと。
		 */
		LocalModelManager.getInstance();

		/**
		 * Check if local target is synched with remote...
		 */
		initialSyncTargets();

		/**
		 * Initialize Task Manager
		 */
		TaskManager taskmgr = TaskManager.getInstance();
		taskmgr.start();
	}

	/**
	 * canHandleShellCloseEvent
	 */
	protected boolean canHandleShellCloseEvent() {
		ExitAction action = new ExitAction(this);
		action.run();
		if (action.isTerminated()) {
			return true;
		}
		return false;
	}

	/**
	 * initialSyncTargets
	 */
	private void initialSyncTargets() {
		final Shell shell = getShell();
		shell.getDisplay().asyncExec(new Runnable() {
			public void run() {
				new StartupSyncAction(ViewManager.getInstance()).run();
				shell.setMinimized(true);
				shell.setVisible(false);
			}
		});
	}

	/**
	 * EventArrived
	 */
	public void EventArrived(LocalViewEvent event) {
		if (aContents != null) {
			aContents.updateLocalViewer(event);
		}
	}

	/**
	 * EventArrived
	 */
	public void EventArrived(RemoteViewEvent event) {
		if (aContents != null) {
			aContents.updateRemoteViewer(event);
		}
	}

	/**
	 * EventArrived
	 * For log message.
	 */
	public void EventArrived(LogEvent event) {
		if (aContents != null) {
			aContents.updateAppLog(event);
		}
	}

	/**
	 * EventArrived
	 */
	public void EventArrived(final GUIEvent event) {
		final Shell shell = getShell();
		if (shell == null) {
			return;
		}

		setStatus(event.getMessage());
		shell.update();

		switch (event.getGUIEventType()) {
			case START: {
				shell.setCursor(new Cursor(null, SWT.CURSOR_WAIT));
				break;
			}
			case FINISH: {
				shell.setCursor(new Cursor(null, SWT.CURSOR_ARROW));
				break;
			}
		}
	}
}
