context: using System;
  using System.Collections;
  using System.Globalization;
  using System.IO;
  using System.Text;
  
  using Org.BouncyCastle.Utilities;
  using NetUtils = Org.BouncyCastle.Utilities.Net;
  
  namespace Org.BouncyCastle.Asn1.X509
  {
      /**
       * The GeneralName object.
       * <pre>
       * GeneralName ::= CHOICE {
       *      otherName                       [0]     OtherName,
       *      rfc822Name                      [1]     IA5String,
       *      dNSName                         [2]     IA5String,
       *      x400Address                     [3]     ORAddress,
       *      directoryName                   [4]     Name,
       *      ediPartyName                    [5]     EDIPartyName,
       *      uniformResourceIdentifier       [6]     IA5String,
       *      iPAddress                       [7]     OCTET STRING,
       *      registeredID                    [8]     OBJECT IDENTIFIER}
       *
       * OtherName ::= Sequence {
       *      type-id    OBJECT IDENTIFIER,
       *      value      [0] EXPLICIT ANY DEFINED BY type-id }
       *
       * EDIPartyName ::= Sequence {
       *      nameAssigner            [0]     DirectoryString OPTIONAL,
       *      partyName               [1]     DirectoryString }
       * </pre>
       */
      public class GeneralName
          : Asn1Encodable, IAsn1Choice
      {
          public const int OtherName					= 0;
          public const int Rfc822Name					= 1;
          public const int DnsName					= 2;
          public const int X400Address				= 3;
          public const int DirectoryName				= 4;
          public const int EdiPartyName				= 5;
          public const int UniformResourceIdentifier	= 6;
          public const int IPAddress					= 7;
          public const int RegisteredID				= 8;
  
  		internal readonly Asn1Encodable	obj;
          internal readonly int			tag;
  
  		public GeneralName(
              X509Name directoryName)
          {
              this.obj = directoryName;
              this.tag = 4;
          }
  
  		/**
           * When the subjectAltName extension contains an Internet mail address,
           * the address MUST be included as an rfc822Name. The format of an
           * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
           *
           * When the subjectAltName extension contains a domain name service
           * label, the domain name MUST be stored in the dNSName (an IA5String).
           * The name MUST be in the "preferred name syntax," as specified by RFC
           * 1034 [RFC 1034].
           *
           * When the subjectAltName extension contains a URI, the name MUST be
           * stored in the uniformResourceIdentifier (an IA5String). The name MUST
           * be a non-relative URL, and MUST follow the URL syntax and encoding
           * rules specified in [RFC 1738].  The name must include both a scheme
           * (e.g., "http" or "ftp") and a scheme-specific-part.  The scheme-
           * specific-part must include a fully qualified domain name or IP
           * address as the host.
           *
           * When the subjectAltName extension contains a iPAddress, the address
           * MUST be stored in the octet string in "network byte order," as
           * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
           * each octet is the LSB of the corresponding byte in the network
           * address. For IP Version 4, as specified in RFC 791, the octet string
           * MUST contain exactly four octets.  For IP Version 6, as specified in
           * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
           * 1883].
           */
          public GeneralName(
              Asn1Object	name,
  			int			tag)
          {
              this.obj = name;
              this.tag = tag;
          }
  
  		public GeneralName(
              int				tag,
              Asn1Encodable	name)
          {
              this.obj = name;
              this.tag = tag;
          }
  
  		/**
  		 * Create a GeneralName for the given tag from the passed in string.
  		 * <p>
  		 * This constructor can handle:
  		 * <ul>
  		 * <li>rfc822Name</li>
  		 * <li>iPAddress</li>
  		 * <li>directoryName</li>
  		 * <li>dNSName</li>
  		 * <li>uniformResourceIdentifier</li>
  		 * <li>registeredID</li>
  		 * </ul>
  		 * For x400Address, otherName and ediPartyName there is no common string
  		 * format defined.
  		 * </p><p>
  		 * Note: A directory name can be encoded in different ways into a byte
  		 * representation. Be aware of this if the byte representation is used for
  		 * comparing results.
  		 * </p>
  		 *
  		 * @param tag tag number
  		 * @param name string representation of name
  		 * @throws ArgumentException if the string encoding is not correct or
  		 *             not supported.
  		 */
  		public GeneralName(
              int		tag,
              string	name)
          {
  			this.tag = tag;
  
  			if (tag == Rfc822Name || tag == DnsName || tag == UniformResourceIdentifier)
  			{
  				this.obj = new DerIA5String(name);
  			}
  			else if (tag == RegisteredID)
  			{
  				this.obj = new DerObjectIdentifier(name);
  			}
  			else if (tag == DirectoryName)
  			{
  				this.obj = new X509Name(name);
  			}
  			else if (tag == IPAddress)
  			{
  				byte[] enc = toGeneralNameEncoding(name);
  				if (enc == null)
  					throw new ArgumentException("IP Address is invalid", "name");
  
  				this.obj = new DerOctetString(enc);
  			}
  			else
  			{
  				throw new ArgumentException("can't process string for tag: " + tag, "tag");
  			}
  		}
  
  		public static GeneralName GetInstance(
              object obj)
          {
              if (obj == null || obj is GeneralName)
              {
                  return (GeneralName) obj;
              }
  
              if (obj is Asn1TaggedObject)
              {
                  Asn1TaggedObject	tagObj = (Asn1TaggedObject) obj;
                  int					tag = tagObj.TagNo;
  
  				switch (tag)
  				{
  					case OtherName:
  						return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
  					case Rfc822Name:
  						return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
  					case DnsName:
  						return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
  					case X400Address:
  						throw new ArgumentException("unknown tag: " + tag);
  					case DirectoryName:
  						return new GeneralName(tag, X509Name.GetInstance(tagObj, true));
  					case EdiPartyName:
  						return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
  					case UniformResourceIdentifier:
  						return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
  					case IPAddress:
  						return new GeneralName(tag, Asn1OctetString.GetInstance(tagObj, false));
  					case RegisteredID:
  						return new GeneralName(tag, DerObjectIdentifier.GetInstance(tagObj, false));
  				}
  	        }
  
              if (obj is byte[])
  	        {
  	            try
  	            {
  	                return GetInstance(Asn1Object.FromByteArray((byte[])obj));
  	            }
  	            catch (IOException)
  	            {
  	                throw new ArgumentException("unable to parse encoded general name");
  	            }
  	        }
  
  			throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
  		}
  
  		public static GeneralName GetInstance(
              Asn1TaggedObject	tagObj,
              bool				explicitly)
          {
              return GetInstance(Asn1TaggedObject.GetInstance(tagObj, true));
          }
  
  		public int TagNo
  		{
  
gt: 			get { return tag; }