﻿// Decompiled with JetBrains decompiler
// Type: System.CodeDom.CodeTypeReference
// Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 5ABD58FD-DF31-44FD-A492-63F2B47CC9AF
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.dll

using System;
using System.Collections;
using System.Globalization;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;

namespace System.CodeDom
{
  /// <summary>
  /// Represents a reference to a type.
  /// </summary>
  [ClassInterface(ClassInterfaceType.AutoDispatch)]
  [ComVisible(true)]
  [Serializable]
  public class CodeTypeReference : CodeObject
  {
    private string baseType;
    [OptionalField]
    private bool isInterface;
    private int arrayRank;
    private CodeTypeReference arrayElementType;
    [OptionalField]
    private CodeTypeReferenceCollection typeArguments;
    [OptionalField]
    private CodeTypeReferenceOptions referenceOptions;
    [OptionalField]
    private bool needsFixup;

    /// <summary>
    /// Gets or sets the type of the elements in the array.
    /// </summary>
    /// 
    /// <returns>
    /// A <see cref="T:System.CodeDom.CodeTypeReference"/> that indicates the type of the array elements.
    /// </returns>
    public CodeTypeReference ArrayElementType
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this.arrayElementType;
      }
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set
      {
        this.arrayElementType = value;
      }
    }

    /// <summary>
    /// Gets or sets the array rank of the array.
    /// </summary>
    /// 
    /// <returns>
    /// The number of dimensions of the array.
    /// </returns>
    public int ArrayRank
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this.arrayRank;
      }
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set
      {
        this.arrayRank = value;
      }
    }

    internal int NestedArrayDepth
    {
      get
      {
        if (this.arrayElementType == null)
          return 0;
        return 1 + this.arrayElementType.NestedArrayDepth;
      }
    }

    /// <summary>
    /// Gets or sets the name of the type being referenced.
    /// </summary>
    /// 
    /// <returns>
    /// The name of the type being referenced.
    /// </returns>
    public string BaseType
    {
      get
      {
        if (this.arrayRank > 0 && this.arrayElementType != null)
          return this.arrayElementType.BaseType;
        if (string.IsNullOrEmpty(this.baseType))
          return string.Empty;
        string str = this.baseType;
        if (this.needsFixup && this.TypeArguments.Count > 0)
          str = str + (object) '`' + this.TypeArguments.Count.ToString((IFormatProvider) CultureInfo.InvariantCulture);
        return str;
      }
      set
      {
        this.baseType = value;
        this.Initialize(this.baseType);
      }
    }

    /// <summary>
    /// Gets or sets the code type reference option.
    /// </summary>
    /// 
    /// <returns>
    /// A bitwise combination of the <see cref="T:System.CodeDom.CodeTypeReferenceOptions"/> values.
    /// </returns>
    [ComVisible(false)]
    public CodeTypeReferenceOptions Options
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this.referenceOptions;
      }
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set
      {
        this.referenceOptions = value;
      }
    }

    /// <summary>
    /// Gets the type arguments for the current generic type reference.
    /// </summary>
    /// 
    /// <returns>
    /// A <see cref="T:System.CodeDom.CodeTypeReferenceCollection"/> containing the type arguments for the current <see cref="T:System.CodeDom.CodeTypeReference"/> object.
    /// </returns>
    [ComVisible(false)]
    public CodeTypeReferenceCollection TypeArguments
    {
      get
      {
        if (this.arrayRank > 0 && this.arrayElementType != null)
          return this.arrayElementType.TypeArguments;
        if (this.typeArguments == null)
          this.typeArguments = new CodeTypeReferenceCollection();
        return this.typeArguments;
      }
    }

    internal bool IsInterface
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this.isInterface;
      }
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.CodeDom.CodeTypeReference"/> class.
    /// </summary>
    public CodeTypeReference()
    {
      this.baseType = string.Empty;
      this.arrayRank = 0;
      this.arrayElementType = (CodeTypeReference) null;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.CodeDom.CodeTypeReference"/> class using the specified type.
    /// </summary>
    /// <param name="type">The <see cref="T:System.Type"/> to reference. </param><exception cref="T:System.ArgumentNullException"><paramref name="type "/>is null.</exception>
    public CodeTypeReference(Type type)
    {
      if (type == (Type) null)
        throw new ArgumentNullException("type");
      if (type.IsArray)
      {
        this.arrayRank = type.GetArrayRank();
        this.arrayElementType = new CodeTypeReference(type.GetElementType());
        this.baseType = (string) null;
      }
      else
      {
        this.InitializeFromType(type);
        this.arrayRank = 0;
        this.arrayElementType = (CodeTypeReference) null;
      }
      this.isInterface = type.IsInterface;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.CodeDom.CodeTypeReference"/> class using the specified type and code type reference.
    /// </summary>
    /// <param name="type">The <see cref="T:System.Type"/> to reference.</param><param name="codeTypeReferenceOption">The code type reference option, one of the <see cref="T:System.CodeDom.CodeTypeReferenceOptions"/> values. </param>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public CodeTypeReference(Type type, CodeTypeReferenceOptions codeTypeReferenceOption)
      : this(type)
    {
      this.referenceOptions = codeTypeReferenceOption;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.CodeDom.CodeTypeReference"/> class using the specified type name and code type reference option.
    /// </summary>
    /// <param name="typeName">The name of the type to reference.</param><param name="codeTypeReferenceOption">The code type reference option, one of the <see cref="T:System.CodeDom.CodeTypeReferenceOptions"/> values.</param>
    public CodeTypeReference(string typeName, CodeTypeReferenceOptions codeTypeReferenceOption)
    {
      this.Initialize(typeName, codeTypeReferenceOption);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.CodeDom.CodeTypeReference"/> class using the specified type name.
    /// </summary>
    /// <param name="typeName">The name of the type to reference. </param>
    public CodeTypeReference(string typeName)
    {
      this.Initialize(typeName);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.CodeDom.CodeTypeReference"/> class using the specified type name and type arguments.
    /// </summary>
    /// <param name="typeName">The name of the type to reference.</param><param name="typeArguments">An array of <see cref="T:System.CodeDom.CodeTypeReference"/> values.</param>
    public CodeTypeReference(string typeName, params CodeTypeReference[] typeArguments)
      : this(typeName)
    {
      if (typeArguments == null || typeArguments.Length <= 0)
        return;
      this.TypeArguments.AddRange(typeArguments);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.CodeDom.CodeTypeReference"/> class using the specified code type parameter.
    /// </summary>
    /// <param name="typeParameter">A <see cref="T:System.CodeDom.CodeTypeParameter"/> that represents the type of the type parameter.</param>
    public CodeTypeReference(CodeTypeParameter typeParameter)
      : this(typeParameter == null ? (string) null : typeParameter.Name)
    {
      this.referenceOptions = CodeTypeReferenceOptions.GenericTypeParameter;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.CodeDom.CodeTypeReference"/> class using the specified array type name and rank.
    /// </summary>
    /// <param name="baseType">The name of the type of the elements of the array. </param><param name="rank">The number of dimensions of the array. </param>
    public CodeTypeReference(string baseType, int rank)
    {
      this.baseType = (string) null;
      this.arrayRank = rank;
      this.arrayElementType = new CodeTypeReference(baseType);
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.CodeDom.CodeTypeReference"/> class using the specified array type and rank.
    /// </summary>
    /// <param name="arrayType">A <see cref="T:System.CodeDom.CodeTypeReference"/> that indicates the type of the array. </param><param name="rank">The number of dimensions in the array. </param>
    public CodeTypeReference(CodeTypeReference arrayType, int rank)
    {
      this.baseType = (string) null;
      this.arrayRank = rank;
      this.arrayElementType = arrayType;
    }

    private void InitializeFromType(Type type)
    {
      this.baseType = type.Name;
      if (!type.IsGenericParameter)
      {
        Type type1 = type;
        while (type1.IsNested)
        {
          type1 = type1.DeclaringType;
          this.baseType = type1.Name + "+" + this.baseType;
        }
        if (!string.IsNullOrEmpty(type.Namespace))
          this.baseType = type.Namespace + "." + this.baseType;
      }
      if (type.IsGenericType && !type.ContainsGenericParameters)
      {
        foreach (Type type1 in type.GetGenericArguments())
          this.TypeArguments.Add(new CodeTypeReference(type1));
      }
      else
      {
        if (type.IsGenericTypeDefinition)
          return;
        this.needsFixup = true;
      }
    }

    private void Initialize(string typeName)
    {
      this.Initialize(typeName, this.referenceOptions);
    }

    private void Initialize(string typeName, CodeTypeReferenceOptions options)
    {
      this.Options = options;
      if (typeName == null || typeName.Length == 0)
      {
        typeName = typeof (void).FullName;
        this.baseType = typeName;
        this.arrayRank = 0;
        this.arrayElementType = (CodeTypeReference) null;
      }
      else
      {
        typeName = this.RipOffAssemblyInformationFromTypeName(typeName);
        int num1 = typeName.Length - 1;
        int num2 = num1;
        this.needsFixup = true;
        Queue queue = new Queue();
        while (num2 >= 0)
        {
          int num3 = 1;
          string str = typeName;
          int index1 = num2;
          int num4 = 1;
          int index2 = index1 - num4;
          if ((int) str[index1] == 93)
          {
            for (; index2 >= 0 && (int) typeName[index2] == 44; --index2)
              ++num3;
            if (index2 >= 0 && (int) typeName[index2] == 91)
            {
              queue.Enqueue((object) num3);
              num2 = index2 - 1;
              num1 = num2;
            }
            else
              break;
          }
          else
            break;
        }
        int num5 = num1;
        ArrayList arrayList = new ArrayList();
        Stack stack = new Stack();
        if (num5 > 0)
        {
          string str = typeName;
          int index1 = num5;
          int num3 = 1;
          int index2 = index1 - num3;
          if ((int) str[index1] == 93)
          {
            this.needsFixup = false;
            int num4 = 1;
            int num6 = num1;
            for (; index2 >= 0; --index2)
            {
              if ((int) typeName[index2] == 91)
              {
                if (--num4 == 0)
                  break;
              }
              else if ((int) typeName[index2] == 93)
                ++num4;
              else if ((int) typeName[index2] == 44 && num4 == 1)
              {
                if (index2 + 1 < num6)
                  stack.Push((object) typeName.Substring(index2 + 1, num6 - index2 - 1));
                num6 = index2;
              }
            }
            if (index2 > 0 && num1 - index2 - 1 > 0)
            {
              if (index2 + 1 < num6)
                stack.Push((object) typeName.Substring(index2 + 1, num6 - index2 - 1));
              while (stack.Count > 0)
              {
                string typeName1 = this.RipOffAssemblyInformationFromTypeName((string) stack.Pop());
                arrayList.Add((object) new CodeTypeReference(typeName1));
              }
              num1 = index2 - 1;
            }
          }
        }
        if (num1 < 0)
        {
          this.baseType = typeName;
        }
        else
        {
          if (queue.Count > 0)
          {
            CodeTypeReference arrayType = new CodeTypeReference(typeName.Substring(0, num1 + 1), this.Options);
            for (int index = 0; index < arrayList.Count; ++index)
              arrayType.TypeArguments.Add((CodeTypeReference) arrayList[index]);
            while (queue.Count > 1)
              arrayType = new CodeTypeReference(arrayType, (int) queue.Dequeue());
            this.baseType = (string) null;
            this.arrayRank = (int) queue.Dequeue();
            this.arrayElementType = arrayType;
          }
          else if (arrayList.Count > 0)
          {
            for (int index = 0; index < arrayList.Count; ++index)
              this.TypeArguments.Add((CodeTypeReference) arrayList[index]);
            this.baseType = typeName.Substring(0, num1 + 1);
          }
          else
            this.baseType = typeName;
          if (this.baseType == null || this.baseType.IndexOf('`') == -1)
            return;
          this.needsFixup = false;
        }
      }
    }

    private string RipOffAssemblyInformationFromTypeName(string typeName)
    {
      int startIndex = 0;
      int index1 = typeName.Length - 1;
      string str = typeName;
      while (startIndex < typeName.Length && char.IsWhiteSpace(typeName[startIndex]))
        ++startIndex;
      while (index1 >= 0 && char.IsWhiteSpace(typeName[index1]))
        --index1;
      if (startIndex < index1)
      {
        if ((int) typeName[startIndex] == 91 && (int) typeName[index1] == 93)
        {
          ++startIndex;
          --index1;
        }
        if ((int) typeName[index1] != 93)
        {
          int num = 0;
          for (int index2 = index1; index2 >= startIndex; --index2)
          {
            if ((int) typeName[index2] == 44)
            {
              ++num;
              if (num == 4)
              {
                str = typeName.Substring(startIndex, index2 - startIndex);
                break;
              }
            }
          }
        }
      }
      return str;
    }
  }
}
