//------------------------------------------------------------------------------
// Embedded Software Simulation Base Classes
// Copyright (C) 2010-2011 Cores Co., Ltd. Japan
//------------------------------------------------------------------------------
// $Id: Scenario.cs 88 2011-04-05 11:03:57Z nagasima $
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;

namespace SimBase
{
	public enum ScenarioResult
	{
		NoRunning,
		Running,
		OK,
		NG,
		UserStop,
	}

	public class ScenarioNameAttribute : Attribute
	{
		string m_Name;

		public ScenarioNameAttribute(string name)
		{
			m_Name = name;
		}

		public string Name { get { return m_Name; } }
	}

	public class ErrorAddedEventArgs : EventArgs
	{
		DateTime m_OccuerTime;
		string m_Location;
		string m_Text;

		public ErrorAddedEventArgs(DateTime occuerTime, string location, string text)
		{
			m_OccuerTime = occuerTime;
			m_Location = location;
			m_Text = text;
		}

		public DateTime OccuerTime
		{
			get { return m_OccuerTime; }
		}

		public string Location
		{
			get { return m_Location; }
		}

		public string Text
		{
			get { return m_Text; }
		}
	}

	public delegate void ErrorAddedEventHandler(Scenario sender, ErrorAddedEventArgs e);

	public abstract class Scenario
	{
		private IScenarioHost m_ScenarioHost;
		private string m_Name;
		private bool m_IsRunning;
		private int m_Step;
		private int m_TotalSteps = 1;
		private ScenarioResult m_Result;
		private DateTime m_StartTime;
		private DateTime m_EndTime;

		public Scenario(IScenarioHost scenarioHost)
		{
			m_ScenarioHost = scenarioHost;
			m_Name = GetName(GetType());
		}

		public IScenarioHost Host
		{
			get { return m_ScenarioHost; }
		}

		public string Name
		{
			get { return m_Name; }
			set { m_Name = value; }
		}

		public bool IsRunning
		{
			get { return m_IsRunning; }
		}

		public int Step
		{
			get { return m_Step; }
			protected set
			{
				m_Step = value;

				if (ValueChanged != null)
					ValueChanged(this, EventArgs.Empty);
			}
		}

		public event EventHandler ValueChanged;
		public event ErrorAddedEventHandler ErrorAdded;

		public int TotalSteps
		{
			get { return m_TotalSteps; }
			protected set
			{
				m_TotalSteps = value;

				if (ValueChanged != null)
					ValueChanged(this, EventArgs.Empty);
			}
		}

		public ScenarioResult Result
		{
			get { return m_Result; }
		}

		public DateTime StartTime
		{
			get { return m_StartTime; }
		}

		public DateTime EndTime
		{
			get { return m_EndTime; }
		}

		public void Run()
		{
			m_IsRunning = true;
			m_Step = 0;
			m_Result = ScenarioResult.Running;
			m_StartTime = DateTime.Now;

			DoRun();
		}

		protected abstract void DoRun();

		public void Stop()
		{
			BeginStop();
		}

		protected abstract void BeginStop();

		public event EventHandler EndOrStoped;

		protected void EndStop()
		{
			m_IsRunning = false;
			m_Result = ScenarioResult.UserStop;
			m_EndTime = DateTime.Now;

			if (EndOrStoped != null)
				EndOrStoped(this, EventArgs.Empty);

			if (ValueChanged != null)
				ValueChanged(this, EventArgs.Empty);
		}

		protected void DoEnd(bool result)
		{
			m_IsRunning = false;
			m_Result = result ? ScenarioResult.OK : ScenarioResult.NG;
			m_EndTime = DateTime.Now;

			if (EndOrStoped != null)
				EndOrStoped(this, EventArgs.Empty);

			m_ScenarioHost.CurrentView = null;

			if (ValueChanged != null)
				ValueChanged(this, EventArgs.Empty);
		}

		public void NgEnd()
		{
			DoEnd(false);
		}

		public static string GetName(Type type)
		{
			foreach (object atrb in type.GetCustomAttributes(false))
			{
				ScenarioNameAttribute sa = atrb as ScenarioNameAttribute;
				if (sa == null)
					continue;

				return sa.Name;
			}

			return type.ToString();
		}

		public virtual void DoEvent(object e)
		{
		}

		protected List<ErrorAddedEventArgs> m_Errors = new List<ErrorAddedEventArgs>();

		protected void AddError(string text)
		{
			DateTime occerTime = DateTime.Now;
			string localtion;
			StackTrace st = new StackTrace();
			MethodBase mb = st.GetFrame(1).GetMethod();
			ParameterInfo[] pars = mb.GetParameters();

			localtion = mb.DeclaringType.FullName + "." + mb.Name + "(";
			foreach (ParameterInfo par in pars)
			{
				localtion += par.ParameterType.Name + " " + par.Name + ", ";
			}
			if (pars.Length > 0)
				localtion = localtion.Substring(0, localtion.Length - 2);
			localtion += ")";

			ErrorAddedEventArgs e = new ErrorAddedEventArgs(occerTime, localtion, text);

			m_Errors.Add(e);

			if (ErrorAdded != null)
				ErrorAdded(this, e);
		}
	}
}
