//
// 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.Security;
using System.Security.Permissions;
using System.Text;

namespace CLRUnleashed
{
	/// <summary>
	/// Podsumowanie dla CustomPermission.
	/// </summary>
	[Serializable()]
	public class CustomPermission: CodeAccessPermission , IUnrestrictedPermission
	{
		private bool unrestricted;

		public CustomPermission(PermissionState state)
		{
			if(state == PermissionState.Unrestricted)
			{
				unrestricted = true;
			}
			else
			{
				unrestricted = false;
			}
		}
      
		public bool IsUnrestricted()
		{
			return unrestricted;
		}

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

			if(this.IsUnrestricted())
			{
				copy.unrestricted = true;
			}
			else
			{
				copy.unrestricted = false;
			}
			//Zwrócenie kopii.
			return copy;
		}

		public override IPermission Intersect(IPermission target)
		{
			//Zwrócenie pustej wartości, jeśli nic nie zostało zwrócone.
			if(null == target)
			{
				return null;
			}
			try
			{
				//Utworzenie nowego egzemplarza CustomPermission na podstawie przekazanego obiektu.
				CustomPermission PassedPermission = (CustomPermission)target;

				//Jeśli dla jednej z klas wartość unrestricted to fałsz, 
				//to przecięcie będzie miało również taką wartość.
				//Zwrócenie przekazanej klasy z unrestricted zawierającym fałsz.
				if(!PassedPermission.unrestricted)
				{
					return target;
				}
				//Zwrócenie kopii bieżącej klasy, jeśli przekazana wartość
				//unrestricted to prawda.
				return this.Copy();
			}
				//Przechwycenie wyjątku InvalidCastException.
				//Zgłoszenie ArgumentException w celu powiadomienia użytkownika.
			catch (InvalidCastException)
			{
				throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
			}                
		}

		public override bool IsSubsetOf(IPermission target)
		{
			//Jeśli nic nie przekazano, a unrestricted ma wartość fałszu,
			//to należy zwrócić prawdę. 
			if(null == target)
			{
				return !this.unrestricted;
			}
			try
			{        
				//Create a new instance of CustomPermission from the passed object.
				CustomPermission passedpermission = (CustomPermission)target;

				//If unrestricted has the same value in both objects, then
				//one is the subset of the other.
				if(this.unrestricted == passedpermission.unrestricted)
				{
					return true;
				}
				else
				{
					return false;
				} 
			}
				//Przechwycenie wyjątku InvalidCastException.
				//Zgłoszenie ArgumentException w celu powiadomienia użytkownika.
			catch (InvalidCastException)
			{
				throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
			}                    
		}

		public override void FromXml(SecurityElement PassedElement)
		{
			//Uzyskanie wartości unrestricted z pliku XML oraz inicjalizacja 
			//bieżącego egzemplarza unrestricted na tę wartość.
			string element = PassedElement.Attribute("Unrestricted");         
 
			if(null != element)
			{  
				this.unrestricted = Convert.ToBoolean(element);
			}
		}

		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());
			return element;
		}
	}
	[AttributeUsageAttribute(AttributeTargets.All, AllowMultiple = true)]
	public class CustomPermissionAttribute: CodeAccessSecurityAttribute
	{
		bool unrestricted = false;

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

		public CustomPermissionAttribute(SecurityAction action): base (action)
		{  
		}
		public override IPermission CreatePermission()
		{
			if(Unrestricted)
			{
				return new CustomPermission(PermissionState.Unrestricted);
			}
			else
			{
				return new CustomPermission(PermissionState.None);
			}
		}
	}
}
