content: package com.comphenix.protocol.reflect.fuzzy;
  
  import com.google.common.collect.Maps;
  import java.lang.reflect.Member;
  import java.lang.reflect.Modifier;
  import java.util.Map;
  import java.util.Objects;
  import java.util.regex.Pattern;
  import javax.annotation.Nonnull;
  
  /**
   * Represents a matcher that matches members.
   *
   * @param <T> - type that it matches.
   * @author Kristian
   */
  public abstract class AbstractFuzzyMember<T extends Member> implements AbstractFuzzyMatcher<T> {
  
  	// Accessibility matchers
  	protected int modifiersRequired;
  	protected int modifiersBanned;
  
  	protected Pattern nameRegex;
  	protected AbstractFuzzyMatcher<Class<?>> declaringMatcher = ClassTypeMatcher.MATCH_ALL;
  
  	/**
  	 * Whether this contract can be modified.
  	 */
  	protected transient boolean sealed;
  
  	protected AbstractFuzzyMember() {
  		// Only allow construction through the builder
  	}
  
  	// Clone a given contract
  	protected AbstractFuzzyMember(AbstractFuzzyMember<T> other) {
  		this.modifiersRequired = other.modifiersRequired;
  		this.modifiersBanned = other.modifiersBanned;
  		this.nameRegex = other.nameRegex;
  		this.declaringMatcher = other.declaringMatcher;
  		this.sealed = true;
  	}
  
  	private static String getBitView(int value, int bits) {
  		if (bits < 0 || bits > 31) {
  			throw new IllegalArgumentException("Bits must be a value between 0 and 32");
  		}
  
  		// Extract our needed bits
  		int snipped = value & ((1 << bits) - 1);
  		return Integer.toBinaryString(snipped);
  	}
  
  	/**
  	 * Called before a builder is building a member and copying its state.
  	 * <p>
  	 * Use this to prepare any special values.
  	 */
  	protected void prepareBuild() {
  		// No need to prepare anything
  	}
  
  	/**
  	 * Retrieve a bit field of every {@link java.lang.reflect.Modifier Modifier} that is required for the member to
  	 * match.
  	 *
  	 * @return A required modifier bit field.
  	 */
  	public int getModifiersRequired() {
  		return this.modifiersRequired;
  	}
  
  	/**
  	 * Retrieve a bit field of every {@link java.lang.reflect.Modifier Modifier} that must not be present for the member
  	 * to match.
  	 *
  	 * @return A banned modifier bit field.
  	 */
  	public int getModifiersBanned() {
  		return this.modifiersBanned;
  	}
  
  	/**
  	 * Retrieve the regular expression pattern that is used to match the name of a member.
  	 *
  	 * @return The regex matching a name, or NULL if everything matches.
  	 */
  	public Pattern getNameRegex() {
  		return this.nameRegex;
  	}
  
  	/**
  	 * Retrieve a class matcher for the declaring class of the member.
  	 *
  	 * @return An object matching the declaring class.
  	 */
  	public AbstractFuzzyMatcher<Class<?>> getDeclaringMatcher() {
  		return this.declaringMatcher;
  	}
  
  	@Override
  	public boolean isMatch(T value, Object parent) {
  		int mods = value.getModifiers();
  
  		// Match accessibility and name
  		return (mods & this.modifiersRequired) == this.modifiersRequired
  				&& (mods & this.modifiersBanned) == 0
  				&& this.declaringMatcher.isMatch(value.getDeclaringClass(), value)
  				&& this.isNameMatch(value.getName());
  	}
  
  	/**
  	 * Determine if a given name matches the current member matcher.
  	 *
  	 * @param name - the name to match.
  	 * @return TRUE if the name matches, FALSE otherwise.
  	 */
  	private boolean isNameMatch(String name) {
  		if (this.nameRegex == null) {
  			return true;
  		} else {
  			return this.nameRegex.matcher(name).matches();
  		}
  	}
  
  	@Override
  	public String toString() {
  		return this.getKeyValueView().toString();
  	}
  
  	/**
  	 * Generate a view of this matcher as a key-value map.
  	 * <p>
  	 * Used by {@link #toString()} to print a representation of this object.
  	 *
  	 * @return A modifiable key-value view.
  	 */
  	protected Map<String, Object> getKeyValueView() {
  		Map<String, Object> map = Maps.newLinkedHashMap();
  
  		// Build our representation
  		if (this.modifiersRequired != Integer.MAX_VALUE || this.modifiersBanned != 0) {
  			map.put("modifiers", String.format(
  					"[required: %s, banned: %s]",
  					getBitView(this.modifiersRequired, 16),
  					getBitView(this.modifiersBanned, 16)));
  		}
  
  		if (this.nameRegex != null) {
  			map.put("name", this.nameRegex.pattern());
  		}
  
  		if (this.declaringMatcher != ClassTypeMatcher.MATCH_ALL) {
  			map.put("declaring", this.declaringMatcher);
  		}
  
  		return map;
  	}
  
  	@Override
  	public boolean equals(Object obj) {
  		if (this == obj) {
  			return true;
  		} else if (obj instanceof AbstractFuzzyMember) {
  			AbstractFuzzyMember<?> other = (AbstractFuzzyMember<?>) obj;
  			return this.modifiersBanned == other.modifiersBanned
  					&& this.modifiersRequired == other.modifiersRequired
  					&& FuzzyMatchers.checkPattern(this.nameRegex, other.nameRegex)
  					&& Objects.equals(this.declaringMatcher, other.declaringMatcher);
  		} else {
  			return false;
  		}
  	}
  
  	@Override
  	public int hashCode() {
  		return Objects.hash(
  				this.modifiersBanned,
  				this.modifiersRequired,
  				this.nameRegex != null ? this.nameRegex.pattern() : null,
  				this.declaringMatcher);
  	}
  
  	/**
  	 * Represents a builder of a fuzzy member contract.
  	 *
  	 * @author Kristian
  	 */
  	public static abstract class Builder<T extends AbstractFuzzyMember<?>> {
  
  		protected T member = this.initialMember();
  
  		/**
  		 * Add a given bit-field of required modifiers for every matching member.
  		 *
  		 * @param modifier - bit-field of modifiers that are required.
  		 * @return This builder, for chaining.
  		 */
  		public Builder<T> requireModifier(int modifier) {
  			this.member.modifiersRequired |= modifier;
  			return this;
  		}
  
  		/**
  		 * Require that every matching member is public.
  		 *
  		 * @return This builder, for chaining.
  		 */
  		public Builder<T> requirePublic() {
  			return this.requireModifier(Modifier.PUBLIC);
  		}
  
  		/**
  		 * Add a given bit-field of modifers that will skip or ignore members.
  		 *
  		 * @param modifier - bit-field of modifiers to skip or ignore.
  		 * @return This builder, for chaining.
  		 */
  		public Builder<T> banModifier(int modifier) {
  			this.member.modifiersBanned |= modifier;
  			return this;
  		}
  
  		/**
  		 * Set the regular expresson that matches a members name.
  		 *
  		 * @param regex - new regular expression of valid names.
  		 * @return This builder, for chaining.
  		 */
  		public Builder<T> nameRegex(String regex) {
  			this.member.nameRegex = Pattern.compile(regex);
  			return this;
  		}
  
  		/**
  		 * Set the regular expression pattern that matches a members name.
  		 *
  		 * @param pattern - regular expression pattern for a valid name.
  		 * @return This builder, for chaining.
  		 */
  		public Builder<T> nameRegex(Pattern pattern) {
  			this.member.nameRegex = pattern;
  			return this;
  		}
  
  		/**
  		 * Set the exact name of the member we are matching.
  		 * <p>
  		 * This will overwrite the regular expression rule.
  		 *
  		 * @param name - exact name.
  		 * @return This builder, for chaining.
  		 */
  		public Builder<T> nameExact(String name) {
  			return this.nameRegex(Pattern.quote(name));
  		}
  
  		/**
  		 * Require that a member is defined by this exact class.
  		 *
  		 * @param declaringClass - the declaring class of any matching member.
  		 * @return This builder, for chaining.
  		 */
  		public Builder<T> declaringClassExactType(Class<?> declaringClass) {
  			this.member.declaringMatcher = FuzzyMatchers.matchExact(declaringClass);
  			return this;
  		}
  
  		/**
  		 * Require that a member is defined by this exact class, or any super class.
  		 *
  		 * @param declaringClass - the declaring class.
  		 * @return This builder, for chaining.
  		 */
  		public Builder<T> declaringClassSuperOf(Class<?> declaringClass) {
  			this.member.declaringMatcher = FuzzyMatchers.matchSuper(declaringClass);
  			return this;
  		}
  
  		/**
  		 * Require that a member is defined by this exact class, or any super class.
  		 *
  		 * @param declaringClass - the declaring class.
  		 * @return This builder, for chaining.
  		 */
  		public Builder<T> declaringClassDerivedOf(Class<?> declaringClass) {
  			this.member.declaringMatcher = FuzzyMatchers.matchDerived(declaringClass);
  			return this;
  		}
  
  		/**
  		 * Require that a member is defined by a class that matches the given matcher.
  		 *
  		 * @param classMatcher - class matcher.
  		 * @return This builder, for chaining.
  		 */
  		public Builder<T> declaringClassMatching(AbstractFuzzyMatcher<Class<?>> classMatcher) {
  			this.member.declaringMatcher = classMatcher;
  			return this;
  		}
  
  		/**
  		 * Construct a new instance of the current type.
  		 *
  		 * @return New instance.
  		 */
  		@Nonnull
  		protected abstract T initialMember();
  
  		/**
  		 * Build a new instance of this type.
  		 * <p>
  		 * Builders should call {@link AbstractFuzzyMember#prepareBuild()} when constructing new objects.
  		 *
  		 * @return New instance of this type.
  		 */
  		public abstract T build();
  	}
  }
  