context: //
  // System.Security.Policy.CodeGroup
  //
  // Authors:
  //	Nick Drochak (ndrochak@gol.com)
  //	Sebastien Pouliot  <sebastien@ximian.com>
  //
  // (C) 2001 Nick Drochak, All rights reserved.
  // Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
  //
  // Permission is hereby granted, free of charge, to any person obtaining
  // a copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to
  // permit persons to whom the Software is furnished to do so, subject to
  // the following conditions:
  // 
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  
  using System.Collections;
  using System.Globalization;
  using System.Reflection;
  using System.Runtime.InteropServices;
  using System.Security.Permissions;
  
  namespace System.Security.Policy {
  
  	[Serializable]
  	[ComVisible (true)]
  	public abstract class CodeGroup {
  		PolicyStatement m_policy;
  		IMembershipCondition m_membershipCondition;
  		string m_description;
  		string m_name;
  		ArrayList m_children = new ArrayList();
  //		PolicyLevel m_level;
  
  		protected CodeGroup (IMembershipCondition membershipCondition, PolicyStatement policy)
  		{
  			if (null == membershipCondition)
  				throw new ArgumentNullException ("membershipCondition");
  
  			if (policy != null)
  				m_policy = policy.Copy ();
  			m_membershipCondition = membershipCondition.Copy ();
  		}
  
  		// for PolicyLevel (to avoid validation duplication)
  		internal CodeGroup (SecurityElement e, PolicyLevel level) 
  		{
  			FromXml (e, level);
  		}
  
  		// abstract
  
  		public abstract CodeGroup Copy ();
  
  		public abstract string MergeLogic { get; }
  
  		public abstract PolicyStatement Resolve (Evidence evidence);
  
  		public abstract CodeGroup ResolveMatchingCodeGroups (Evidence evidence);
  
  		// properties
  
  		public PolicyStatement PolicyStatement {
  			get { return m_policy; }
  			set { m_policy = value; }
  		}
  
  		public string Description {
  			get { return m_description; }
  			set { m_description = value; }
  		}
  
  		public IMembershipCondition MembershipCondition	 {
  			get { return m_membershipCondition; }
  			set {
  				if (null == value)
  					throw new ArgumentException ("value");
  				m_membershipCondition = value;
  			}
  		}
  
  		public string Name {
  			get { return m_name; }
  			set { m_name = value; }
  		}
  
  		public IList Children {
  			get { return m_children; }
  			set {
  				if (null == value)
  					throw new ArgumentNullException ("value");
  				m_children = new ArrayList (value);
  			}
  		}
  
  		public virtual string AttributeString {
  			get {
  				if (null != m_policy)
  					return m_policy.AttributeString;
  				return null;
  			}
  		}
  
  		public virtual string PermissionSetName {
  			get {
  				if (m_policy == null)
  					return null;
  				if (m_policy.PermissionSet is Security.NamedPermissionSet)
  					return ((NamedPermissionSet)(m_policy.PermissionSet)).Name;
  				return null;
  			}
  		}
  
  		public void AddChild (CodeGroup group)
  		{
  			if (null == group)
  				throw new ArgumentNullException ("group");
  
  			m_children.Add (group.Copy ());
  		}
  
  		public override bool Equals (object o)
  		{
  			CodeGroup cg = (o as CodeGroup);
  			if (cg == null)
  				return false;
  
  			return Equals (cg, false);
  		}
  
  		public bool Equals (CodeGroup cg, bool compareChildren)
  		{
  			if (cg.Name != this.Name)
  				return false;
  
  			if (cg.Description != this.Description)
  				return false;
  
  			if (!cg.MembershipCondition.Equals (m_membershipCondition))
  				return false;
  
  			if (compareChildren) {
  				int childCount = cg.Children.Count;
  				if (this.Children.Count != childCount)
  					return false;
  
  				for (int index = 0; index < childCount; index++) {
  					// not a deep compare
  					if (!((CodeGroup)(this.Children [index])).Equals ((CodeGroup)(cg.Children [index]), false))
  						return false;
  				}
  			}
  			return true;
  		}
  
  		public void RemoveChild (CodeGroup group)
  		{
  			if (group != null)
  				m_children.Remove (group);
  		}
  
  		public override int GetHashCode ()
  		{
  			int hashCode = m_membershipCondition.GetHashCode ();
  			if (m_policy != null)
  				hashCode += m_policy.GetHashCode ();
  			return hashCode;
  		}
  
  		public void FromXml (SecurityElement e)
  		{
  			FromXml (e, null);
  		}
  
  		public void FromXml (SecurityElement e, PolicyLevel level)
  		{
  			if (null == e)
  				throw new ArgumentNullException("e");
  
  			PermissionSet ps = null;
  			string psetname = e.Attribute ("PermissionSetName");
  			if ((psetname != null) && (level != null)) {
  				ps = level.GetNamedPermissionSet (psetname);
  			}
  			else {
  				SecurityElement pset = e.SearchForChildByTag ("PermissionSet");
  				if (pset != null) {
  					Type classType = Type.GetType (pset.Attribute ("class"));
  					ps = (PermissionSet) Activator.CreateInstance (classType, true);
  					ps.FromXml (pset);
  				}
  				else {
  					ps = new PermissionSet (new PermissionSet (PermissionState.None));
  				}
  			}
  			m_policy = new PolicyStatement (ps);
  
  			m_children.Clear ();
  			if ((e.Children != null) && (e.Children.Count > 0)) {
  				foreach (SecurityElement se in e.Children) {
  					if (se.Tag == "CodeGroup") {
  						this.AddChild (CodeGroup.CreateFromXml (se, level));
  					}
  				}
  			}
  			
  			m_membershipCondition = null;
  			SecurityElement mc = e.SearchForChildByTag ("IMembershipCondition");
  			if (mc != null) {
  				string className = mc.Attribute ("class");
  				Type classType = Type.GetType (className);
  				if (classType == null)
  					classType = Type.GetType ("System.Security.Policy." + className);
  				m_membershipCondition = (IMembershipCondition) Activator.CreateInstance (classType, true);
  				m_membershipCondition.FromXml (mc, level);
  			}
  
  			m_name = e.Attribute("Name");
  			m_description = e.Attribute("Description");
  
  			// seems like we might need this to Resolve() in subclasses
  			//m_level = level;
  
  			ParseXml (e, level);
  		}
  
  		protected virtual void ParseXml (SecurityElement e, PolicyLevel level)
  		{
  		}
  		
  		public SecurityElement ToXml ()
  		{
  			return ToXml (null);
  		}
  
  		public SecurityElement ToXml (PolicyLevel level)
  		{
  			SecurityElement e = new SecurityElement("CodeGroup");
  			e.AddAttribute("class", this.GetType().AssemblyQualifiedName);
  			e.AddAttribute("version", "1");
  
  			if (null != Name)
  				e.AddAttribute("Name", Name);
  
  			if (null != Description)
  				e.AddAttribute("Description", Description);
  
  			if (null != MembershipCondition)
  				e.AddChild(MembershipCondition.ToXml());
  
  			if ((PolicyStatement != null) && (PolicyStatement.PermissionSet != null))
  				e.AddChild (PolicyStatement.PermissionSet.ToXml ());
  
  			foreach (CodeGroup child in Children)
  				e.AddChild(child.ToXml());
  
  			CreateXml(e, level);
  			return e;
  		}
  		
  		protected virtual void CreateXml (SecurityElement element, PolicyLevel level)
  		{
  		}
  
  		// internal stuff
  
  		internal static CodeGroup CreateFromXml (SecurityElement se, PolicyLevel level) 
  		{
  			string fullClassName = se.Attribute ("class");
  			string className = fullClassName;
  			// many possible formats
  			// a. "FirstMatchCodeGroup"
  			// b. "System.Security.Policy.FirstMatchCodeGroup"
  			// c. "System.Security.Policy.FirstMatchCodeGroup, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"\r\n           version=\"1\">\r\n   <IMembershipCondition class=\"System.Security.Policy.AllMembershipCondition, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
  			int n = className.IndexOf (",");
  			if (n > 0) {
  				className = className.Substring (0, n);
  			}
  
gt: 			n = className.LastIndexOf (".");