context: /*
      Copyright (C) 2014-2019 de4dot@gmail.com
  
      This file is part of dnSpy
  
      dnSpy is free software: you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.
  
      dnSpy is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
  
      You should have received a copy of the GNU General Public License
      along with dnSpy.  If not, see <http://www.gnu.org/licenses/>.
  */
  
  using System;
  using System.ComponentModel;
  using System.Linq;
  using System.Windows.Input;
  using dnlib.DotNet;
  using dnSpy.AsmEditor.DnlibDialogs;
  using dnSpy.AsmEditor.Properties;
  using dnSpy.AsmEditor.ViewHelpers;
  using dnSpy.Contracts.Decompiler;
  using dnSpy.Contracts.MVVM;
  using dnSpy.Contracts.Search;
  
  namespace dnSpy.AsmEditor.Event {
  	sealed class EventOptionsVM : ViewModelBase {
  		readonly EventDefOptions origOptions;
  
  		public IDnlibTypePicker DnlibTypePicker {
  			set => dnlibTypePicker = value;
  		}
  		IDnlibTypePicker? dnlibTypePicker;
  
  		public ICommand ReinitializeCommand => new RelayCommand(a => Reinitialize());
  		public ICommand PickAddMethodCommand => new RelayCommand(a => PickAddMethod());
  		public ICommand PickInvokeMethodCommand => new RelayCommand(a => PickInvokeMethod());
  		public ICommand PickRemoveMethodCommand => new RelayCommand(a => PickRemoveMethod());
  		public ICommand ClearAddMethodCommand => new RelayCommand(a => AddMethod = null, a => !(AddMethod is null));
  		public ICommand ClearInvokeMethodCommand => new RelayCommand(a => InvokeMethod = null, a => !(InvokeMethod is null));
  		public ICommand ClearRemoveMethodCommand => new RelayCommand(a => RemoveMethod = null, a => !(RemoveMethod is null));
  
  		public EventAttributes Attributes {
  			get => attributes;
  			set {
  				if (attributes != value) {
  					attributes = value;
  					OnPropertyChanged(nameof(Attributes));
  					OnPropertyChanged(nameof(SpecialName));
  					OnPropertyChanged(nameof(RTSpecialName));
  				}
  			}
  		}
  		EventAttributes attributes;
  
  		public bool SpecialName {
  			get => GetFlagValue(EventAttributes.SpecialName);
  			set => SetFlagValue(EventAttributes.SpecialName, value);
  		}
  
  		public bool RTSpecialName {
  			get => GetFlagValue(EventAttributes.RTSpecialName);
  			set => SetFlagValue(EventAttributes.RTSpecialName, value);
  		}
  
  		bool GetFlagValue(EventAttributes flag) => (Attributes & flag) != 0;
  
  		void SetFlagValue(EventAttributes flag, bool value) {
  			if (value)
  				Attributes |= flag;
  			else
  				Attributes &= ~flag;
  		}
  
  		public string? Name {
  			get => name;
  			set {
  				if (name != value) {
  					name = value;
  					OnPropertyChanged(nameof(Name));
  				}
  			}
  		}
  		UTF8String? name;
  
  		public TypeSig? EventTypeSig {
  			get => TypeSigCreator.TypeSig;
  			set => TypeSigCreator.TypeSig = value;
  		}
  
  		public string EventTypeHeader => string.Format(dnSpy_AsmEditor_Resources.EventType, TypeSigCreator.TypeSigDnlibFullName);
  		public TypeSigCreatorVM TypeSigCreator { get; }
  		public string AddMethodFullName => GetFullName(AddMethod);
  		public string InvokeMethodFullName => GetFullName(InvokeMethod);
  		public string RemoveMethodFullName => GetFullName(RemoveMethod);
  		static string GetFullName(MethodDef? md) => md is null ? "null" : md.FullName;
  
  		public MethodDef? AddMethod {
  			get => addMethod;
  			set {
  				if (addMethod != value) {
  					addMethod = value;
  					OnPropertyChanged(nameof(AddMethod));
  					OnPropertyChanged(nameof(AddMethodFullName));
  				}
  			}
  		}
  		MethodDef? addMethod;
  
  		public MethodDef? InvokeMethod {
  			get => invokeMethod;
  			set {
  				if (invokeMethod != value) {
  					invokeMethod = value;
  					OnPropertyChanged(nameof(InvokeMethod));
  					OnPropertyChanged(nameof(InvokeMethodFullName));
  				}
  			}
  		}
  		MethodDef? invokeMethod;
  
  		public MethodDef? RemoveMethod {
  			get => removeMethod;
  			set {
  				if (removeMethod != value) {
  					removeMethod = value;
  					OnPropertyChanged(nameof(RemoveMethod));
  					OnPropertyChanged(nameof(RemoveMethodFullName));
  				}
  			}
  		}
  		MethodDef? removeMethod;
  
  		public MethodDefsVM OtherMethodsVM { get; }
  		public CustomAttributesVM CustomAttributesVM { get; }
  
  		readonly ModuleDef ownerModule;
  
  		public EventOptionsVM(EventDefOptions options, ModuleDef ownerModule, IDecompilerService decompilerService, TypeDef ownerType) {
  			this.ownerModule = ownerModule;
  			var typeSigCreatorOptions = new TypeSigCreatorOptions(ownerModule, decompilerService) {
  				IsLocal = false,
  				CanAddGenericTypeVar = true,
  				CanAddGenericMethodVar = true,
  				OwnerType = ownerType,
  			};
  			if (!(ownerType is null) && ownerType.GenericParameters.Count == 0)
  				typeSigCreatorOptions.CanAddGenericTypeVar = false;
  			TypeSigCreator = new TypeSigCreatorVM(typeSigCreatorOptions);
  			TypeSigCreator.PropertyChanged += typeSigCreator_PropertyChanged;
  
  			CustomAttributesVM = new CustomAttributesVM(ownerModule, decompilerService);
  			OtherMethodsVM = new MethodDefsVM(ownerModule, decompilerService);
  
  			origOptions = options;
  
  			TypeSigCreator.CanAddFnPtr = false;
  			Reinitialize();
  		}
  
  		void typeSigCreator_PropertyChanged(object? sender, PropertyChangedEventArgs e) {
  			if (e.PropertyName == nameof(TypeSigCreator.TypeSigDnlibFullName))
  				OnPropertyChanged(nameof(EventTypeHeader));
  			HasErrorUpdated();
  		}
  
  		void Reinitialize() => InitializeFrom(origOptions);
  
  		MethodDef? PickMethod(MethodDef? origMethod) {
  			if (dnlibTypePicker is null)
  				throw new InvalidOperationException();
  			return dnlibTypePicker.GetDnlibType(dnSpy_AsmEditor_Resources.Pick_Method, new SameModuleDocumentTreeNodeFilter(ownerModule, new FlagsDocumentTreeNodeFilter(VisibleMembersFlags.MethodDef)), origMethod, ownerModule);
  		}
  
  		void PickAddMethod() {
  			var method = PickMethod(AddMethod);
  			if (!(method is null))
  				AddMethod = method;
  		}
  
  		void PickInvokeMethod() {
  			var method = PickMethod(InvokeMethod);
  			if (!(method is null))
  				InvokeMethod = method;
  		}
  
  		void PickRemoveMethod() {
  			var method = PickMethod(RemoveMethod);
  			if (!(method is null))
  				RemoveMethod = method;
  		}
  
  		public EventDefOptions CreateEventDefOptions() => CopyTo(new EventDefOptions());
  
  		void InitializeFrom(EventDefOptions options) {
  			Attributes = options.Attributes;
  			Name = options.Name;
  			EventTypeSig = options.EventType.ToTypeSig();
  			AddMethod = options.AddMethod;
  			InvokeMethod = options.InvokeMethod;
  			RemoveMethod = options.RemoveMethod;
  			OtherMethodsVM.InitializeFrom(options.OtherMethods);
  			CustomAttributesVM.InitializeFrom(options.CustomAttributes);
  		}
  
  
gt: 		EventDefOptions CopyTo(EventDefOptions options) {