//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
// 
using System;
using System.Collections;
using System.Security;
using System.Security.Permissions;
using System.Text;

namespace CLRUnleashed
{
	/// <summary>
	/// Podsumowanie dla DayPermission.
	/// </summary>
	[Serializable()]
	public class DayPermission: CodeAccessPermission , IUnrestrictedPermission
	{
		private bool unrestricted = false;
		private ArrayList dayList = new ArrayList();
		public DayPermission(PermissionState state)
		{
			unrestricted = (state == PermissionState.Unrestricted);
		}
      
		public DayPermission(DayOfWeek day)
		{
			dayList.Add(day);
		}

		public DayPermission(ArrayList days)
		{
			foreach(DayOfWeek day in days)
				dayList.Add(day);
		}

		public bool IsUnrestricted()
		{
			return unrestricted;
		}
		public override IPermission Copy()
		{
			// Utworzenie nowego egzemplarza CustomPermission z wartością
			//  unrestricted.
			DayPermission copy = new DayPermission(PermissionState.None);

			copy.unrestricted = this.unrestricted;
			foreach(DayOfWeek day in this.dayList)
			{
				copy.dayList.Add(day);
			}

			// Zwrócenie kopii.
			return copy;
		}

		public override IPermission Union(IPermission t)
		{
			// Jeśli nic nie przekazano, należy zwrócić aktualny zestaw.
			if(null == t)
			{
				return this.Copy();
			}

			try
			{
				DayPermission target = (DayPermission)t;

				// Utworzenie nowego egzemplarza CustomPermission na podstawie przekazanego obiektu.
				DayPermission result = new DayPermission(PermissionState.None);

				// Skopiowanie całej zawartości aktualnej listy
				// do listy wynikowej.
				foreach(DayOfWeek day in this.dayList)
				{
					result.dayList.Add(day);
				}
				// Dodanie wartości docelowych, które
				// nie zostały jeszcze dodane.
				foreach(DayOfWeek day in target.dayList)
				{
					if(!result.dayList.Contains(day))
						result.dayList.Add(day);
				}

				result.unrestricted = (this.unrestricted == true ||
					                   target.unrestricted == true);
				
				return result;
			}
			catch (InvalidCastException)
			{
				// Przechwycenie wyjątku InvalidCastException.
				// Zgłoszenie wyjątku ArgumentException w celu powiadomienia użytkownika.
				throw new ArgumentException("Argument WrongType", this.GetType().FullName);
			}                
		}
			
		public override IPermission Intersect(IPermission t)
		{
			// Jeśli nic nie przekazano, należy zwrócić pustą wartość.
			if(null == t)
			{
				return null;
			}

			try
			{
				DayPermission target = (DayPermission)t;

				// Utworzenie nowego egzemplarza CustomPermission na podstawie przekazanego obiektu.
				DayPermission result = new DayPermission(PermissionState.None);

				foreach(DayOfWeek day in this.dayList)
				{
					if(target.dayList.Contains(day))
						result.dayList.Add(day);
				}

				result.unrestricted = (this.unrestricted == true &&
					                   target.unrestricted == true);
				
				return result;
			}
			catch (InvalidCastException)
			{
				// Przechwycenie wyjątku InvalidCastException.
				// Zgłoszenie wyjątku ArgumentException w celu powiadomienia użytkownika.
				throw new ArgumentException("Argument WrongType", this.GetType().FullName);
			}                
		}
		public override bool IsSubsetOf(IPermission t)
		{
			// Jeśli nic nie przekazano, a unrestricted zawiera fałsz,
			// to należy zwrócić prawdę. 
			if(null == t)
			{
				return false;
			}

			try
			{        
				// Utworzenie nowego egzemplarza CustomPermission na podstawie przekazanego obiektu.
				DayPermission target = (DayPermission)t;

				// Jeśli unrestricted ma tę samą wartość dla obu obiektów,
				// to jeden z nich stanowi podzbiór drugiego.
				bool setCompare = true;
				foreach(DayOfWeek day in this.dayList)
				{
					if(!target.dayList.Contains(day))
						setCompare = false;
				}
				return (this.unrestricted == target.unrestricted &&
					    setCompare &&
					    this.dayList.Contains(DateTime.Now.DayOfWeek));
			}
			catch (InvalidCastException)
			{
				// Przechwycenie wyjątku InvalidCastException.
				// Zgłoszenie wyjątku ArgumentException w celu powiadomienia użytkownika.
				throw new ArgumentException("Argument WrongType", this.GetType().FullName);
			}                    
		}
		public override void FromXml(SecurityElement e)
		{
			// Uzyskanie wartości unrestricted z pliku XML i inicjalizacja
			// aktualnego egzemplarza unrestricted na tę samą wartość.
			string element = e.Attribute("Unrestricted");         
			if(null != element)
			{  
				this.unrestricted = Convert.ToBoolean(element);
			}
			element = e.Attribute("Days");
			if(null != element)
			{
				string [] list = element.Split(new Char[] {','});
				for(int i = 0;i < list.Length; i++)
				{
					if(list[i] == "Niedziela")
						this.dayList.Add(DayOfWeek.Sunday);
					if(list[i] == "Poniedziałek")
						this.dayList.Add(DayOfWeek.Monday);
					if(list[i] == "Wtorek")
						this.dayList.Add(DayOfWeek.Tuesday);
					if(list[i] == "Środa")
						this.dayList.Add(DayOfWeek.Wednesday);
					if(list[i] == "Czwartek")
						this.dayList.Add(DayOfWeek.Thursday);
					if(list[i] == "Piątek")
						this.dayList.Add(DayOfWeek.Friday);
					if(list[i] == "Sobota")
						this.dayList.Add(DayOfWeek.Saturday);
				}
			}
		}
		public override SecurityElement ToXml()
		{
			// Zakodowanie aktualnego uprawnienia do pliku XML przy użyciu
			// klasy elementu zabezpieczeń.
			SecurityElement element = new SecurityElement("IPermission");
			Type type = this.GetType();
			StringBuilder AssemblyName = new StringBuilder(type.Assembly.ToString());
			AssemblyName.Replace('\"', '\'');
			element.AddAttribute("class", type.FullName + ", " + AssemblyName);
			element.AddAttribute("version", "1");
			element.AddAttribute("Unrestricted", unrestricted.ToString());
			StringBuilder days = new StringBuilder();
			for(int i = 0;i < dayList.Count; i++)
			{
				if((DayOfWeek)dayList[i] == DayOfWeek.Sunday)
					days.Append("Niedziela");
				if((DayOfWeek)dayList[i] == DayOfWeek.Monday)
					days.Append("Poniedziałek");
				if((DayOfWeek)dayList[i] == DayOfWeek.Tuesday)
					days.Append("Wtorek");
				if((DayOfWeek)dayList[i] == DayOfWeek.Wednesday)
					days.Append("Środa");
				if((DayOfWeek)dayList[i] == DayOfWeek.Thursday)
					days.Append("Czwartek");
				if((DayOfWeek)dayList[i] == DayOfWeek.Friday)
					days.Append("Piątek");
				if((DayOfWeek)dayList[i] == DayOfWeek.Saturday)
					days.Append("Sobota");
				if(i != dayList.Count - 1)
					days.Append(",");
			}
			element.AddAttribute("Days", days.ToString());
			return element;
		}
	}
	[AttributeUsageAttribute(AttributeTargets.All, AllowMultiple = true)]
	public class DayPermissionAttribute: CodeAccessSecurityAttribute
	{
		private bool unrestricted = false;
		private DayOfWeek day = DayOfWeek.Monday;

		public new bool Unrestricted
		{
			get{ return unrestricted; }
			set{ unrestricted = value; }
		}
		public DayOfWeek Day
		{
			get{ return day; }
			set{ day = value; }
		}

		public DayPermissionAttribute(SecurityAction action): base (action)
		{  
		}
		public override IPermission CreatePermission()
		{
			if(Unrestricted)
			{
				return new DayPermission(PermissionState.Unrestricted);
			}
			else
			{
				return new DayPermission(Day);
			}
		}
	}

}
