package com.flozano.metrics;

import static java.util.Objects.requireNonNull;

import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Stream;

public final class Tags {
	private static final Tags EMPTY = new Tags(Collections.emptySet());
	private final Set<Tag> tags;

	public static Tags empty() {
		return EMPTY;
	}

	private Tags(Set<Tag> tags) {
		this.tags = tags;
	}

	public final Tags with(CharSequence name, CharSequence value) {
		Set<Tag> t = new TreeSet<Tag>(tags);
		t.add(new Tag(name, value));
		return new Tags(t);
	}

	public final Stream<Tag> stream() {
		return tags.stream();
	}

	public boolean isEmpty() {
		return tags.isEmpty();
	}

	public static final class Tag implements Comparable<Tag> {
		public final CharSequence name;
		public final CharSequence value;

		public Tag(CharSequence name, CharSequence value) {
			super();
			this.name = requireNonNull(name);
			this.value = requireNonNull(value);
		}

		@Override
		public int compareTo(Tag o) {
			if (o == null) {
				return 1;
			} else {
				int result = name.toString().compareTo(o.name.toString());
				if (result == 0) {
					return value.toString().compareTo(o.value.toString());
				} else {
					return result;
				}
			}
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((name == null) ? 0 : name.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Tag other = (Tag) obj;
			if (name == null) {
				if (other.name != null)
					return false;
			} else if (!name.toString().equals(other.name.toString()))
				return false;
			return true;
		}

	}

	public boolean has(CharSequence name) {
		return tags.stream().anyMatch(x -> x.name.toString().equals(name.toString()));
	}
}

@@ -1410,16 +1410,87 @@
 ode());%0A
+%09%09%09result = prime * result + ((value == null) ? 0 : value.hashCode());%0A
 %09%09%09retur
@@ -1861,16 +1861,683 @@
 false;%0A%09
+%09%09if (value == null) %7B%0A%09%09%09%09if (other.value != null)%0A%09%09%09%09%09return false;%0A%09%09%09%7D else if (!value.toString().equals(other.value.toString()))%0A%09%09%09%09return false;%0A%09%09%09return true;%0A%09%09%7D%0A%0A%09%7D%0A%0A%09@Override%0A%09public int hashCode() %7B%0A%09%09final int prime = 31;%0A%09%09int result = 1;%0A%09%09result = prime * result + ((tags == null) ? 0 : tags.hashCode());%0A%09%09return result;%0A%09%7D%0A%0A%09@Override%0A%09public boolean equals(Object obj) %7B%0A%09%09if (this == obj)%0A%09%09%09return true;%0A%09%09if (obj == null)%0A%09%09%09return false;%0A%09%09if (getClass() != obj.getClass())%0A%09%09%09return false;%0A%09%09Tags other = (Tags) obj;%0A%09%09if (tags == null) %7B%0A%09%09%09if (other.tags != null)%0A%09%09%09%09return false;%0A%09%09%7D else if (!tags.equals(other.tags))%0A%09%09%09return false;%0A
 %09%09return
@@ -2539,29 +2539,24 @@
 eturn true;%0A
-%09%09%7D%0A%0A
 %09%7D%0A%0A%09public 

correct hashCode/equals in Tags (tags can be repeated)