//------------------------------------------------------------------------------
// Embedded Software Simulation Base Classes
// Copyright (C) 2010-2011 Cores Co., Ltd. Japan
//------------------------------------------------------------------------------
// $Id: ScenarioHost.cs 88 2011-04-05 11:03:57Z nagasima $
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Security.Permissions;
using NU.OJL.MPRTOS.TLV.Base;

namespace SimBase
{
	public class ScenarioHost : IScenarioHost
	{
		class ViewButtonInfo
		{
			private ViewCommandButtonInfo m_Info;
			private ToolStripButton m_Button;

			public ViewButtonInfo(ViewCommandButtonInfo info, ToolStripButton button)
			{
				m_Info = info;
				m_Button = button;
			}

			public string Name { get { return m_Info.Name; } }

			public string Key { get { return m_Info.Key; } }

			public ViewCommandButtonInfo Info { get { return m_Info; } }

			public ToolStripButton Button { get { return m_Button; } }

			public bool IsAdaptable(IUnitSim unit)
			{
				return m_Info.IsAdaptable(unit);
			}
		}

		UnitSimList m_UnitList = new UnitSimList();
		ViewList m_ViewList = new ViewList();
		List<ViewButtonInfo> m_ViewButtonInfos = new List<ViewButtonInfo>();
		ISimEnvironment m_Environment;
		IWindowManager m_WindowManager;
		IUnitSim m_CurrentUnit;
		Form m_Form;

		public ScenarioHost(Form form, ISimEnvironment environment, IWindowManager windowManager)
		{
			m_Form = form;
			m_Environment = environment;
			m_WindowManager = windowManager;
		}

		public event UnitOutputEventHandlear UnitOutput;

		public event UnitSwitchedEventHandlear UnitSwitched;

		public ISimEnvironment Environment
		{
			get { return m_Environment; }
		}

		public IWindowManager WindowManager
		{
			get { return m_WindowManager; }
		}

		public IUnitSim CurrentUnit
		{
			get { return m_CurrentUnit; }
			set { SetCurrentUnit(value); }
		}

		public IViewForm CurrentView
		{
			get { return m_WindowManager.GetSubWindow(m_WindowManager.MainPanel) as IViewForm; }
			set { if (value == null) m_Environment.SwitchDefaultView(); else value.Activate(); }
		}

		public void ShowView(IViewForm view)
		{
			view.Form.FormClosed += new FormClosedEventHandler(form_FormClosed);
			m_ViewList.AddLast(view);
			m_WindowManager.AddSubWindow(view);
			view.OnShown(EventArgs.Empty);
		}

		void form_FormClosed(object sender, FormClosedEventArgs e)
		{
			IViewForm view = (IViewForm)m_WindowManager.GetSubWindow((Form)sender);

			m_ViewList.Remove(view);

			if (view.UnitSim != null)
				CurrentUnit = view.UnitSim;
		}

		public void CloseView(IViewForm view)
		{
			m_WindowManager.RemoveSubWindow(view);
		}

		public ToolStripButton FindViewButton(string key)
		{
			foreach (ViewButtonInfo info in m_ViewButtonInfos)
			{
				if (info.Key == key)
					return info.Button;
			}

			return null;
		}

		public void ViewButtonClick(ToolStripButton btn, string key, params IUnitSim[] units)
		{
			if (m_CurrentUnit == null)
				return;

			if (btn.Checked)
			{
				IViewForm form = CreateView(key, m_CurrentUnit, units);

				if (form == null)
				{
					btn.Checked = false;
					return;
				}
			}
			else
			{
				CloseView(key, m_CurrentUnit);
			}
		}

		private void SetCurrentUnit(IUnitSim unit)
		{
			m_CurrentUnit = unit;

			if (unit != null)
			{
				foreach (ViewButtonInfo info in m_ViewButtonInfos)
				{
					bool Checked = false;
					foreach (IViewForm view in m_ViewList)
					{
						if ((view.UnitSim == unit) && (view.Name == info.Key + unit.UnitName))
						{
							Checked = true;
							break;
						}
					}

					info.Button.Checked = Checked;
					info.Button.Enabled = info.IsAdaptable(unit);
				}
			}
			else
			{
				foreach (ViewButtonInfo info in m_ViewButtonInfos)
				{
					info.Button.Checked = false;
					info.Button.Enabled = false;
				}
			}
		}

		#region IScenarioHost メンバ

		public INamedList<IUnitSim> Units
		{
			get { return m_UnitList; }
		}

		public INamedList<IViewForm> Views
		{
			get { return m_ViewList; }
		}

		class ScenarioTimer : IDisposable
		{
			System.Windows.Forms.Timer m_Timer;
			Delegate m_Method;
			object[] m_Args;

			public ScenarioTimer(int interval, Delegate method, params object[] args)
			{
				m_Timer = new System.Windows.Forms.Timer();
				m_Timer.Interval = interval;
				m_Timer.Tick += new EventHandler(Timer_Tick);
				m_Timer.Enabled = true;
				m_Method = method;
				m_Args = args;
			}

			#region IDisposable メンバ

			public void Dispose()
			{
				m_Timer.Dispose();
			}

			#endregion

			public System.Windows.Forms.Timer Timer
			{
				get { return m_Timer; }
			}

			void Timer_Tick(object sender, EventArgs e)
			{
				try
				{
					m_Method.DynamicInvoke(m_Args);
				}
				catch (TargetInvocationException ex)
				{
					MessageBox.Show(ex.InnerException.Message);
					((Scenario)m_Method.Target).NgEnd();
				}
				catch (ApplicationException ex)
				{
					MessageBox.Show(ex.Message);
				}
			}
		}

		LinkedList<ScenarioTimer> m_ScenarioTimers = new LinkedList<ScenarioTimer>();

		public int SetTimer(int interval, Delegate method, params object[] args)
		{
			if (interval > 0)
			{
				ScenarioTimer timer = new ScenarioTimer(interval, method, args);

				m_ScenarioTimers.AddLast(timer);

				return timer.GetHashCode();
			}

			m_Form.BeginInvoke(method, args);

			return 0;
		}

		public bool KiiTimer(int timerID)
		{
			foreach (ScenarioTimer timer in m_ScenarioTimers)
			{
				if (timer.GetHashCode() == timerID)
				{
					m_ScenarioTimers.Remove(timer);
					timer.Dispose();
					return true;
				}
			}

			return false;
		}

		public IUnitSim CreateUnit(string typeName)
		{
			IUnitSim unit = m_Environment.CreateUnit(typeName);

			m_UnitList.Add(unit);
			unit.UnitOutput += new UnitOutputEventHandler(UnitSim_Log);

			return unit;
		}

		public IViewForm CreateView(string typeName, IUnitSim unit, params IUnitSim[] units)
		{
			IViewForm view = m_Environment.CreateView(typeName, unit, units);

			if (view != null)
				ShowView(view);

			return view;
		}

		public IViewForm OpenView(string typeName, IUnitSim unit, params IUnitSim[] units)
		{
			IViewForm view = m_ViewList[typeName + unit.UnitName];
			if (view == null)
				view = CreateView(typeName, unit, units);
			else
				CurrentView = view;
			return view;
		}

		public void CloseView(string key, IUnitSim unit)
		{
			key += unit.UnitName;

			foreach (ISubWindow doc in m_WindowManager.SubWindows)
			{
				IViewForm view = doc as IViewForm;
				if (view == null)
					continue;

				if (view.Name != key)
					continue;

				CloseView(view);
				break;
			}
		}

		public void SwitchUnit(string unitName)
		{
			foreach (IUnitSim unit in m_UnitList)
			{
				if (unit.UnitName != unitName)
					continue;

				m_CurrentUnit = unit;
				OnSwitchUnit(unit);
				break;
			}
		}

		#endregion

		protected void UnitSim_Log(IUnitSim sender, int kind, byte[] data)
		{
			m_Form.BeginInvoke(new UnitOutputEventHandler(OnUnitOutput), sender, kind, data);
		}

		protected virtual void OnUnitOutput(IUnitSim sender, int kind, byte[] data)
		{
			if (UnitOutput != null)
				UnitOutput(this, new UnitOutputEventArgs(sender, kind, data));
		}

		protected virtual void OnSwitchUnit(IUnitSim unit)
		{
			if (UnitSwitched != null)
				UnitSwitched(this, unit);
		}

		public ToolStripButton[] CreateToolStripButtons(CommandManager manager, CommandButtonInfo[] infos)
		{
			List<ToolStripButton> btns = new List<ToolStripButton>();

			int i = 1;
			foreach (CommandButtonInfo info in infos)
			{
				ToolStripButton btn = info.CreateToolStripButton(manager);
				i++;
				btns.Add(btn);
				ViewCommandButtonInfo vi = info as ViewCommandButtonInfo;
				if (vi != null)
					m_ViewButtonInfos.Add(new ViewButtonInfo(vi, btn));
			}

			return btns.ToArray();
		}

		public void AddUnit(IUnitSim unit)
		{
			m_UnitList.Add(unit);
		}

		public void RemoveUnit(IUnitSim unit)
		{
			m_UnitList.Remove(unit);
		}

		public void AddView(IViewForm view)
		{
			m_ViewList.AddLast(view);
		}

		public void RemoveView(IViewForm view)
		{
			m_ViewList.Remove(view);
		}
	}

	public class UnitSimList : INamedList<IUnitSim>
	{
		private LinkedList<IUnitSim> m_List = new LinkedList<IUnitSim>();

		public UnitSimList()
		{
		}

		#region INamedList<IUnitSim> メンバ

		public int Count
		{
			get { return m_List.Count; }
		}

		public IUnitSim this[string name]
		{
			get
			{
				foreach (IUnitSim unit in m_List)
				{
					if (unit.UnitName == name)
						return unit;
				}

				return null;
			}
		}

		public void Lock()
		{
			Monitor.Enter(m_List);
		}

		public void Unlock()
		{
			Monitor.Exit(m_List);
		}

		public IUnitSim[] ToArray()
		{
			Lock();
			IUnitSim[] result = new IUnitSim[m_List.Count];
			int i = 0;
			foreach (IUnitSim unit in m_List)
			{
				result[i++] = unit;
			}
			Unlock();
			return result;
		}

		#endregion

		#region IEnumerable<IUnitSim> メンバ

		public IEnumerator<IUnitSim> GetEnumerator()
		{
			return m_List.GetEnumerator();
		}

		#endregion

		#region IEnumerable メンバ

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return m_List.GetEnumerator();
		}

		#endregion

		public void Clear()
		{
			Lock();
			m_List.Clear();
			Unlock();
		}

		public void Add(IUnitSim unit)
		{
			Lock();
			m_List.AddLast(unit);
			Unlock();
		}

		public void Remove(IUnitSim unit)
		{
			Lock();
			m_List.Remove(unit);
			Unlock();
		}
	}

	public class ViewList : LinkedList<IViewForm>, INamedList<IViewForm>
	{
		public ViewList()
		{
		}

		#region INamedList<IUnitSim> メンバ

		public IViewForm this[string name]
		{
			get
			{
				foreach (IViewForm view in this)
				{
					if (view.Name == name)
						return view;
				}

				return null;
			}
		}

		public void Lock()
		{
			Monitor.Enter(this);
		}

		public void Unlock()
		{
			Monitor.Exit(this);
		}

		public IViewForm[] ToArray()
		{
			Lock();
			IViewForm[] result = new IViewForm[Count];
			int i = 0;
			foreach (IViewForm view in this)
			{
				result[i++] = view;
			}
			Unlock();
			return result;
		}

		#endregion
	}
}
