/*
 *  TLV - Trace Log Visualizer
 *
 *  Copyright (C) 2008-2011 by Nagoya Univ., JAPAN
 *
 *  上記著作権者は，以下の(1)〜(4)の条件を満たす場合に限り，本ソフトウェ
 *  ア（本ソフトウェアを改変したものを含む．以下同じ）を使用・複製・改
 *  変・再配布（以下，利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 *      また，本ソフトウェアのユーザまたはエンドユーザからのいかなる理
 *      由に基づく請求からも，上記著作権者およびTOPPERSプロジェクトを
 *      免責すること．
 *
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，特定の使用目的
 *  に対する適合性も含めて，いかなる保証も行わない．また，本ソフトウェ
 *  アの利用により直接的または間接的に生じたいかなる損害に関しても，そ
 *  の責任を負わない．
 *
 *  @(#) $Id$
 */
using System;
using System.ComponentModel;
using System.IO;
using System.Windows.Forms;
using NU.OJL.MPRTOS.TLV.Base;
using NU.OJL.MPRTOS.TLV.Core.Commands;
using System.Drawing;
using System.Collections.Generic;
using System.Reflection;
using NU.OJL.MPRTOS.TLV.Third;

namespace NU.OJL.MPRTOS.TLV.Core.Controls
{
	public partial class MainForm : Form
	{
		private IWindowManager _windowManager;
		private CommandManager _commandManager;
		private StatusManager _statusManager;
		private ISubWindow[] _subWindows;

		public MainForm()
		{
			ApplicationFactory.SetFileContextEvent = SetFileContextEvent;
			ApplicationFactory.AddToolStripButtons = AddToolStripButtons;

			InitializeComponent();

			settingLoad();

			_windowManager = ApplicationFactory.WindowManager;
			_commandManager = ApplicationFactory.CommandManager;
			Text = ApplicationData.Name + " " + ApplicationData.Version;
		}

		private void invoke(MethodInvoker action)
		{
			if (IsHandleCreated)
				Invoke(action);
			else
				action.Invoke();
		}

		protected override void OnLoad(EventArgs evntArgs)
		{
			base.OnLoad(evntArgs);

			_subWindows = new ISubWindow[]
			{
				CreateSubWindow("macroViewer", CreateControl(typeof(TimeLineMacroViewer), "マクロビューア"), DockState.DockBottom, "マクロビューア") ,
				CreateSubWindow("traceLogViewer", CreateControl(typeof(TraceLogViewer), "トレースログビューア"), DockState.DockRight, "トレースログビューア") ,
				CreateSubWindow("resourceExplorer", CreateControl(typeof(ResourceExplorer), "リソースエクスプローラ"), DockState.DockLeft, "リソースエクスプローラ") ,
				CreateSubWindow("visualizeRuleExplorer", CreateControl(typeof(VisualizeRuleExplorer), "可視化ルールエクスプローラ"), DockState.DockLeft, "可視化ルールエクスプローラ") ,
			};

			#region コマンド管理初期化
			ToolStripItemForTransactionManagerExtensions.SetCommandManagerAsUndo(undoToolStripMenuItem, _commandManager);
			ToolStripItemForTransactionManagerExtensions.SetCommandManagerAsRedo(redoToolStripMenuItem, _commandManager);
			ToolStripItemForTransactionManagerExtensions.SetCommandManagerAsUndo(undoToolStripButton, _commandManager);
			ToolStripItemForTransactionManagerExtensions.SetCommandManagerAsRedo(redoToolStripButton, _commandManager);
			#endregion

			#region サブウィンドウ管理初期化
			_windowManager.Parent = this;
			_windowManager.AddSubWindow(_subWindows);
			_windowManager.Load();
			_windowManager.Show();
			_windowManager.SubWindowDockStateChanged += delegate(object o, GeneralChangedEventArgs<DockState> e) { _commandManager.Done(new ChangeSubWindowDockStateCommand(((ISubWindow)o), e.Old, e.New)); };
			EventHandler<GeneralChangedEventArgs<bool>> v = delegate(object o, GeneralChangedEventArgs<bool> e) { _commandManager.Done(new ChangeSubWindowVisiblityCommand(((ISubWindow)o), e.New)); };
			_windowManager.SubWindowVisibleChanged += v;
			ToolStripMenuItemForWindowManagerExtensions.SetWindowManager(viewToolStripMenuItem, _windowManager);
			_windowManager.ActiveDocumentChanged += new EventHandler<GeneralEventArgs<Control>>(WindowManager_ActiveDocumentChanged);
			#endregion

			#region メニューバーイベント設定

			#region 表示メニュー
			showAllToolStripMenuItem.Click += delegate(object o, EventArgs e)
			{
				// 非表示状態のウィンドウを探しコマンドを生成する
				List<ICommand> cswvc = new List<ICommand>();
				foreach (ISubWindow sw in _subWindows)
				{
					if (!sw.Visible && sw.Enabled)
						cswvc.Add(new ChangeSubWindowVisiblityCommand(sw, true));
				}
				if (cswvc.Count != 0)
				{
					// SubWindowVisibleChangedを無効にしておかないとundoスタックにすべてのウィンドウの表示コマンドが追加されてしまう
					_windowManager.SubWindowVisibleChanged -= v;
					MacroCommand mc = new MacroCommand(cswvc);
					mc.Text = "すべてのウィンドウを表示する";
					_commandManager.Do(mc);
					_windowManager.SubWindowVisibleChanged += v;
				}
			};
			hideAllToolStripMenuItem.Click += delegate(object o, EventArgs e)
			{
				// 表示状態のウィンドウを探しコマンドを生成する
				List<ICommand> cswvc = new List<ICommand>();
				foreach (ISubWindow sw in _subWindows)
				{
					if (sw.Visible && sw.Enabled)
						cswvc.Add(new ChangeSubWindowVisiblityCommand(sw, true));
				}
				if (cswvc.Count != 0)
				{
					// SubWindowVisibleChangedを無効にしておかないとundoスタックにすべてのウィンドウの非表示コマンドが追加されてしまう
					_windowManager.SubWindowVisibleChanged -= v;
					MacroCommand mc = new MacroCommand(cswvc);
					mc.Text = "すべてのウィンドウを非表示にする";
					_commandManager.Do(mc);
					_windowManager.SubWindowVisibleChanged += v;
				}
			};
			#endregion

			#region ファイルメニュー

			newToolStripMenuItem.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new NewCommand());
			};

			openToolStripMenuItem.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new OpenCommand());
			};

			saveSToolStripMenuItem.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new SaveCommand());
			};

			saveAsToolStripMenuItem.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new SaveAsCommand());
			};

			exitToolStripMenuItem.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new ExitCommand(this));
			};

			closeToolStripMenuItem.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new CloseCommand());
			};

			aboutAToolStripMenuItem.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new AboutCommand());
			};

			#endregion

			#endregion

			#region ステータスバー設定

			_statusManager = ApplicationFactory.StatusManager;
			_statusManager.StatusStrip = statusStrip;

			#endregion

			#region ツールバーイベント設定

			newToolStripButton.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new NewCommand());
			};

			openToolStripButton.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new OpenCommand());
			};

			saveToolStripButton.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new SaveCommand());
			};

			reloadToolStripButton.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new ReloadCommand());
			};

			captureToolStripeButton.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new CaptureCommand());
			};

			toolStripButton1.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new Sample1Command());
			};

			playToolStripButton.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new PlayCommand());
			};

			stopToolStripButton.Click += delegate(object o, EventArgs e)
			{
				_commandManager.Do(new StopCommand());
			};

			#endregion
		}

		private static ISubWindow CreateSubWindow(string name, Form form, DockState dockState, string text)
		{
			form.Name = name;
			form.Text = text;
			return WeifenLuoWindowManager.CreateSubWindow(form, dockState);
		}

		private static Form CreateControl(Type type, string text)
		{
			ConstructorInfo ctr = type.GetConstructor(new Type[] { });
			Form ctrl = (Form)ctr.Invoke(new object[] { });
			ctrl.Text = text;
			return ctrl;
		}

		private void SetFileContextEvent(IFileContext fileContext, Form view)
		{
			#region ApplicationDatasイベント設定

			fileContext.PathChanged += delegate(object o, GeneralEventArgs<string> e)
			{
				invoke((MethodInvoker)(delegate()
				{
					textReflesh(view);
					reloadToolStripButton.Enabled = fileContext.Path == string.Empty;
				}
				));
			};

			fileContext.IsSavedChanged += delegate(object o, GeneralEventArgs<bool> e)
			{
				invoke((MethodInvoker)(delegate()
				{
					textReflesh(view);
					saveSToolStripMenuItem.Enabled = !fileContext.IsSaved;
					saveToolStripButton.Enabled = !fileContext.IsSaved;
				}));
			};

			fileContext.IsOpenedChanged += delegate(object o, GeneralEventArgs<bool> e)
			{
				invoke((MethodInvoker)(delegate()
				{
					textReflesh(view);
					closeToolStripMenuItem.Enabled = fileContext.IsOpened;
					saveAsToolStripMenuItem.Enabled = fileContext.IsOpened;
				}));
			};

			fileContext.DataChanged += delegate(object o, GeneralEventArgs<IFileContextData> e)
			{
				invoke((MethodInvoker)(delegate()
				{
					WindowManager_ActiveDocumentChanged(_windowManager, new GeneralEventArgs<Control>(view));
				}));
			};

			fileContext.Saving += delegate(object o, EventArgs e)
			{
				invoke((MethodInvoker)(delegate()
				{
					Cursor.Current = Cursors.WaitCursor;
					_statusManager.ShowProcessing(this.GetType().ToString() + ":saving", "保存中");
				}));
			};

			fileContext.Saved += delegate(object o, EventArgs e)
			{
				invoke((MethodInvoker)(delegate()
				{
					if (Cursor.Current == Cursors.WaitCursor)
						Cursor.Current = Cursors.Default;

					if (_statusManager.IsProcessingShown(this.GetType().ToString() + ":saving"))
						_statusManager.HideProcessing(this.GetType().ToString() + ":saving");
				}));
			};

			#endregion
		}

		void WindowManager_ActiveDocumentChanged(object sender, GeneralEventArgs<Control> e)
		{
			IFileContext fileContext;
			Control control = (Control)e.Arg;
			fileContext = ApplicationFactory.GetFileContext(control);
			if (fileContext == null)
				return;

			if (fileContext.Data == null)
			{
				saveSToolStripMenuItem.Enabled = false;
				saveToolStripButton.Enabled = false;
			}

			TraceLogVisualizerData data = fileContext.Data as TraceLogVisualizerData;

			TraceLogDisplayPanel view = control as TraceLogDisplayPanel;
			if (view != null)
			{
				reloadToolStripButton.Enabled = fileContext.Path == string.Empty;
				textReflesh(view);
				if (data == null)
					view.ClearData();
				else
					view.SetData(data);
			}

			foreach (ISubWindow sw in _subWindows)
			{
				ITraceLogVisualizerControl tlvc = sw.Form as ITraceLogVisualizerControl;
				if (tlvc == null)
					continue;
				if (data == null)
					tlvc.ClearData();
				else
					tlvc.SetData(data);
			}
		}

		protected override void OnClosing(CancelEventArgs e)
		{
			base.OnClosing(e);

			settingSave();

			IFileContext fileContext = ApplicationFactory.GetFileContext();

			if ((fileContext != null) && fileContext.IsOpened
				&& !fileContext.IsSaved)
			{
				e.Cancel = true;
				_commandManager.Do(new ExitCommand(fileContext, this));
			}

			if (Directory.Exists(ApplicationData.Setting.TemporaryDirectoryPath))
			{
				try
				{
					Directory.Delete(ApplicationData.Setting.TemporaryDirectoryPath, true);
				}
				catch (Exception _e)
				{
					MessageBox.Show("エラーが発生しました．\n一時ディレクトリ：[" + ApplicationData.Setting.TemporaryDirectoryPath + "]\n強制終了します．\n----\n" + _e.Message, "エラーが発生しました", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
		}

		protected override void OnDragEnter(DragEventArgs drgevent)
		{
			base.OnDragEnter(drgevent);

			ApplicationFactory.BlackBoard.dragFlag = true;

			string[] s = ((string[])(drgevent.Data.GetData(DataFormats.FileDrop)));

			if ((
				(s.Length == 1
				&& (Path.GetExtension(s[0]).Contains(Properties.Resources.StandardFormatTraceLogFileExtension)
				|| Path.GetExtension(s[0]).Contains(Properties.Resources.TraceLogFileExtension)
				|| Path.GetExtension(s[0]).Contains(Properties.Resources.ResourceFileExtension)))
			|| (s.Length == 2
				&& ((Path.GetExtension(s[0]).Contains(Properties.Resources.ResourceFileExtension) && Path.GetExtension(s[1]).Contains(Properties.Resources.TraceLogFileExtension))
				|| (Path.GetExtension(s[1]).Contains(Properties.Resources.ResourceFileExtension) && Path.GetExtension(s[0]).Contains(Properties.Resources.TraceLogFileExtension)))
			))
				&& drgevent.Data.GetDataPresent(DataFormats.FileDrop))
				drgevent.Effect = DragDropEffects.All;
			else
				drgevent.Effect = DragDropEffects.None;
		}

		protected override void OnDragDrop(DragEventArgs drgevent)
		{
			base.OnDragDrop(drgevent);
			if (drgevent.Data.GetDataPresent(DataFormats.FileDrop))
			{
				string[] s = ((string[])(drgevent.Data.GetData(DataFormats.FileDrop)));

				if (s.Length == 1 && Path.GetExtension(s[0]).Contains(Properties.Resources.StandardFormatTraceLogFileExtension))
				{
					_commandManager.Do(new OpenCommand(s[0]));
				}
				else if (s.Length == 1 && Path.GetExtension(s[0]).Contains(Properties.Resources.TraceLogFileExtension))
				{
					//_commandManager.Do(new NewCommand(null, s[0]));
					MessageBox.Show("リソースファイルを一緒にドロップしてください", "ファイル入力エラー", MessageBoxButtons.OK, MessageBoxIcon.Warning);
				}
				else if (s.Length == 1 && Path.GetExtension(s[0]).Contains(Properties.Resources.ResourceFileExtension))
				{
					//_commandManager.Do(new NewCommand(s[0], null));
					MessageBox.Show("トレースログファイルを一緒にドロップしてください", "ファイル入力エラー", MessageBoxButtons.OK, MessageBoxIcon.Warning);
				}
				else if (s.Length == 2)
				{
					string resFilePath = Path.GetExtension(s[0]).Contains(Properties.Resources.ResourceFileExtension) ? s[0] : s[1];
					string logFilePath = Path.GetExtension(s[1]).Contains(Properties.Resources.TraceLogFileExtension) ? s[1] : s[0];

					_commandManager.Do(new NewCommand(resFilePath, logFilePath));
				}
			}

			ApplicationFactory.BlackBoard.dragFlag = false;
		}

		private void settingLoad()
		{
			ClientSize = Properties.Settings.Default.ClientSize;
			Location = Properties.Settings.Default.Location;
			WindowState = Properties.Settings.Default.WindowState;
		}

		private void settingSave()
		{
			ApplicationData.Setting.Save();

			_windowManager.Save();

			Properties.Settings.Default.Location = Location;
			Properties.Settings.Default.WindowState = WindowState;
			if (WindowState == FormWindowState.Normal)
				Properties.Settings.Default.ClientSize = ClientSize;
			Properties.Settings.Default.Save();
		}

		protected void textReflesh(Control view)
		{
			Text = "";

			IFileContext fileContext = ApplicationFactory.GetFileContext();
			TraceLogVisualizerData data = fileContext.Data as TraceLogVisualizerData;
			if (data != null)
			{
				if (fileContext.Path == string.Empty)
				{
					Text += "新規トレースログ";

					if (data.TraceLogData != null)
					{
						Text += "(" +
							Path.GetFileName(data.TraceLogData.Path) +
							"と" +
							Path.GetFileName(data.ResourceData.Path) +
							"を表示中)";
					}
				}
				else
				{
					Text += Path.GetFileNameWithoutExtension(fileContext.Path);
				}

				if (!fileContext.IsSaved)
					Text += " *";

				view.Text = Text;

				Text += " - ";
			}
			Text += ApplicationData.Name + " " + ApplicationData.Version;
		}

		private void AddToolStripButtons(string[] names, CreateToolStripButtonsHandler CreateToolStripButtons)
		{
			topToolStripPanel.SuspendLayout();

			int i = 1 + topToolStripPanel.Controls.Count;
			foreach (string name in names)
			{
				ToolStrip toolStrip = new ToolStrip();
				toolStrip.Dock = System.Windows.Forms.DockStyle.None;
				toolStrip.Name = name;
				toolStrip.Location = new System.Drawing.Point(
					topToolStripPanel.RowMargin.Left + (toolStrip.Width + 9) * (i % 2),
					topToolStripPanel.RowMargin.Top + toolStrip.Height * (i / 2));

				topToolStripPanel.Controls.Add(toolStrip);

				i++;
			}

			topToolStripPanel.ResumeLayout(false);
			topToolStripPanel.PerformLayout();

			foreach (ToolStrip toolStrip in topToolStripPanel.Controls)
			{
				ToolStripButton[] btns;
				btns = CreateToolStripButtons(toolStrip.Name);
				if (btns != null)
					toolStrip.Items.AddRange(btns);
			}
		}
	}
}
