//------------------------------------------------------------------------------
// TOPPERS/ASP Sample1 Debuging Environment
// Copyright (C) 2010-2011 Cores Co., Ltd. Japan
//------------------------------------------------------------------------------
// $Id: Test0001.cs 87 2011-04-05 10:30:40Z nagasima $
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.IO;
using System.Diagnostics;
using SimBase;
using System.Windows.Forms;
using NU.OJL.MPRTOS.TLV.Base;
using Sample1Sim.Commands;
using System.Reflection;

namespace Sample1Sim
{
	public class SimEnvironment : IDisposable, ISimEnvironment
	{
		CommandManager m_CommandManager;
		IWindowManager m_WindowManager;
		ScenarioHost m_ScenarioHost;
		Sample1 m_Sample1;
		Thread m_Thread;
		AutoResetEvent m_Event;
		bool m_Terminated;
		List<string> m_TraceLog;
		Sample1View m_Sample1View;
		ScenarioForm m_ScenarioForm;

		public SimEnvironment(CommandManager commandManager, IWindowManager windowManager)
		{
			m_CommandManager = commandManager;
			m_WindowManager = windowManager;
			m_Thread = new Thread(new ThreadStart(TimerProc));
			m_Thread.Name = "TimerProc";
			m_Event = new AutoResetEvent(false);
			m_TraceLog = new List<string>();
		}

		#region IDisposable メンバ

		public void Dispose()
		{
		}

		#endregion

		public event EventHandler Terminated;

		public bool IsRunning { get { return m_Sample1 != null; } }

		public IUnitSim Sample1 { get { return m_Sample1; } }

		public string TraceLogResource { get { return m_Sample1.TraceLogResource; } }

		public List<string> TraceLog { get { return m_TraceLog; } }

		public string[] GetToolStripInfos()
		{
			return new string[] { "toolStripSample1" };
		}

		static CommandButtonInfo[] m_Sample1CommandInfo ={
			new CommandButtonInfo("testCommandButton", typeof(TestCommand), "テスト", false, ToolStripItemDisplayStyle.Text),
		};

		public ToolStripButton[] CreateToolStripButtons(string name)
		{
			switch (name)
			{
				case "toolStripSample1":
					return CreateToolStripButtons(m_CommandManager, m_Sample1CommandInfo);
				default:
					return null;
			}
		}

		private 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);
			}

			return btns.ToArray();
		}

		public void Initialize()
		{
			m_ScenarioForm = new ScenarioForm();
			m_ScenarioHost = new ScenarioHost(m_ScenarioForm, this, m_WindowManager);
			m_ScenarioForm.UpdateScenarioList(Assembly.GetAssembly(GetType()), m_ScenarioHost);

			m_Sample1 = new Sample1();
			m_Sample1.UnitExit += new UnitEventHandler(UnitSim_UnitExit);
			m_Sample1.UnitOutput += new UnitOutputEventHandler(UnitSim_Log);
			m_Sample1.UnitSetEvent += new UnitEventHandler(Unit_UnitSetEvent);
			m_Sample1.UnitGetSystemTime += new UnitGetSystemTimeEventHandler(Sample1_UnitGetSystemTime);

			m_ScenarioHost.AddUnit(m_Sample1);

			m_Thread.Start();
		}

		public ISubWindow[] CreateInitialViews()
		{
			List<ISubWindow> result = new List<ISubWindow>();
			ISubWindow sw;

			sw = m_WindowManager.CreateSubWindow(m_ScenarioForm);
			result.Add(sw);

			m_ScenarioHost.AddView((IViewForm)sw);

			m_Sample1View = new Sample1View(this);
			m_Sample1View.Text = "Sample1Sim";
			sw = m_WindowManager.CreateSubWindow(m_Sample1View);
			result.Add(sw);

			m_ScenarioHost.AddView((IViewForm)sw);

			return result.ToArray();
		}

		public void InitializeSettings()
		{
		}

		public void Start()
		{
			m_Sample1.Start();
		}

		public void Terminate()
		{
			m_Sample1.Exit();
		}

		public void UnitSim_UnitExit(IUnitSim sender)
		{
			if (m_Sample1 == sender)
			{
				m_Sample1 = null;

				// DLLアンロードは少し遅らせて実行
				UnitEventHandler handler = new UnitEventHandler(delegate(IUnitSim unit)
				{
					IDisposable dsp = unit as IDisposable;
					if (dsp != null)
						dsp.Dispose();

					UnitExit(sender);
				});
				handler.BeginInvoke(sender, null, this);
			}
		}

		public void UnitExit(IUnitSim sender)
		{
			m_ScenarioHost.RemoveUnit(m_Sample1);
			m_Terminated = true;
		}

		public void OnTerminated()
		{
			if (Terminated != null)
				Terminated(this, EventArgs.Empty);
		}

		string m_LastLine;

		public void UnitSim_Log(IUnitSim sender, int kind, byte[] data)
		{
			switch (kind)
			{
				case 1:
					string temp = Encoding.ASCII.GetString(data);
					string[] lines = temp.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
					if (lines.Length > 0)
					{
						if (!String.IsNullOrEmpty(lines[0]))
						{
							lines[0] = m_LastLine + lines[0];
						}
						if (temp.EndsWith("\r") || temp.EndsWith("\n"))
							m_LastLine = null;
						else
							m_LastLine = lines[lines.Length - 1];
						m_TraceLog.AddRange(lines);
						if (m_LastLine != null)
							m_TraceLog.RemoveAt(m_TraceLog.Count - 1);
					}
					break;
			}
		}

		void TimerProc()
		{
			long prev, now, frequency, sim;

			frequency = 10000000/*[100nsec]=1[sec]*/;
			now = DateTime.Now.Ticks;
			sim = now;

			while (!m_Terminated)
			{
				//タイムアウト処理があればを実行する
				m_Sample1.CallTimeOut(frequency);

				// タイマーの最小値を取得
				long timer = m_Sample1.GetTimer();
				bool signal = false;

				if (timer >= 0)
				{
					bool taskSwitch = timer == 0;
					// タイムアウト後の時刻から、タイマー時間を計算
					long target = sim + timer;
					long temp = DateTime.Now.Ticks;
					long diff = target - temp;
					if (diff < 0)
						diff = 0;

					if ((diff > 0) || taskSwitch)
						signal = m_Event.WaitOne(new TimeSpan(diff));
				}
				else
					signal = m_Event.WaitOne();

				prev = now;
				now = DateTime.Now.Ticks;

				// 経過時間の計算、シグナルで起こされた場合、測定値を使用
				long interval = signal ? (now - prev) : timer;

				sim += interval;

				// 時間が進んだことをメッセージ処理に知らせる
				m_Sample1.Progress(interval);

				// イベントを処理する（ここでm_Terminatedがtrueになることがある）
				m_Sample1.ProcessEvent();
			}

			OnTerminated();
		}

		void Unit_UnitSetEvent(IUnitSim sender)
		{
			m_Event.Set();
		}

		static long m_Start = (new DateTime(1970, 1, 1)).Ticks;

		void Sample1_UnitGetSystemTime(IUnitSim sender, ref long now, ref long frequency)
		{
			now = DateTime.Now.Ticks - m_Start;
			frequency = 10000000/*[100nsec]=1[sec]*/;
		}

		#region ISimEnvironment メンバ

		public IUnitSim CreateUnit(string typeName)
		{
			throw new Exception("The method or operation is not implemented.");
		}

		public IViewForm CreateView(string typeName, IUnitSim unit, IUnitSim[] units)
		{
			throw new Exception("The method or operation is not implemented.");
		}

		public void SwitchDefaultView()
		{
			ISubWindow sb = m_WindowManager.GetSubWindow(m_Sample1View);
			((IViewForm)sb).Activate();
		}

		#endregion
	}
}
