package com.oasisfeng.android.content;

import android.content.IntentFilter;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PatternMatcher;

import java.util.Collection;
import java.util.Iterator;

/**
 * Helpers for building {@link IntentFilter}.
 *
 * Created by Oasis on 2015/12/29.
 */
public class IntentFilters {

	public static class FluentIntentFilter extends IntentFilter {

		public FluentIntentFilter withAction(final String action) { addAction(action); return this; }
		public FluentIntentFilter withActions(final String... actions) { for (final String action : actions) addAction(action); return this; }
		public FluentIntentFilter withDataScheme(final String scheme) { addDataScheme(scheme); return this; }
		public FluentIntentFilter withDataSchemes(final String... schemes) { for (final String scheme : schemes) addDataScheme(scheme); return this; }
		public FluentIntentFilter withData(final String scheme, final String ssp, final int type) {
			addDataScheme(scheme); addDataSchemeSpecificPart(ssp, type); return this;
		}
		public FluentIntentFilter withDataType(final String type) throws MalformedMimeTypeException { addDataType(type); return this; }
		public FluentIntentFilter withCategory(final String category) { addCategory(category); return this; }
		public FluentIntentFilter withCategories(final String... categories) { for (final String category : categories) addCategory(category); return this; }
		public FluentIntentFilter inPriority(final int priority) { setPriority(priority); return this; }

		public FluentIntentFilter(final IntentFilter filter) { super(filter); }
		public FluentIntentFilter() {}

		public static final Parcelable.Creator<FluentIntentFilter> CREATOR = new Parcelable.Creator<FluentIntentFilter>() {
			public FluentIntentFilter createFromParcel(final Parcel source) {
				return new FluentIntentFilter(IntentFilter.CREATOR.createFromParcel(source));
			}
			public FluentIntentFilter[] newArray(final int size) { return new FluentIntentFilter[size]; }
		};
	}

	public static FluentIntentFilter build() { return new FluentIntentFilter(); }

	public static FluentIntentFilter forAction(final String action) {
		return new FluentIntentFilter().withAction(action);
	}

	public static FluentIntentFilter forActions(final String... actions) {
		return new FluentIntentFilter().withActions(actions);
	}

	public static boolean equalIgnoringOrder(final Collection<IntentFilter> ca, final Collection<IntentFilter> cb) {
		if (ca.size() != cb.size()) return false;
		NEXT: for (final IntentFilter a : ca) {
			for (final IntentFilter b : cb)
				if (equal(a, b)) continue NEXT;
			return false;
		}
		return true;
	}

	public static boolean equal(final Iterable<IntentFilter> ia, final Iterable<IntentFilter> ib) {
		final Iterator<IntentFilter> a = ia.iterator(), b = ib.iterator();
		while (a.hasNext()) {
			if (! b.hasNext()) return false;
			if (! equal(a.next(), b.next())) return false;
		}
		return ! b.hasNext();
	}

	public static boolean equal(final IntentFilter a, final IntentFilter b) {
		return equal(a.actionsIterator(), b.actionsIterator())
				&& equal(a.categoriesIterator(), b.categoriesIterator())
				&& equal(a.typesIterator(), b.typesIterator())
				&& equal(a.schemesIterator(), b.schemesIterator())
				&& equal_ssp(a, b)
				&& equal_authorities(a.authoritiesIterator(), b.authoritiesIterator())
				&& equal_patterns(a.pathsIterator(), b.pathsIterator());
	}

	private static boolean equal(final Iterator<String> a, final Iterator<String> b) {
		return a == b || (a != null && b != null && elementsEqual(a, b));
	}

	private static boolean equal_ssp(final IntentFilter a, final IntentFilter b) { //noinspection SimplifiableIfStatement
		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return true;
		return equal_patterns(a.schemeSpecificPartsIterator(), b.schemeSpecificPartsIterator());
	}

	private static boolean equal_patterns(final Iterator<PatternMatcher> a, final Iterator<PatternMatcher> b) {
		if (a == b) return true;
		if (a == null || b == null) return false;
		while (a.hasNext()) {
			if (! b.hasNext()) return false;
			final PatternMatcher o1 = a.next();
			final PatternMatcher o2 = b.next();
			if (! equal(o1, o2)) return false;
		}
		return ! b.hasNext();
	}

	private static boolean equal_authorities(final Iterator<IntentFilter.AuthorityEntry> a, final Iterator<IntentFilter.AuthorityEntry> b) {
		if (a == b) return true;
		if (a == null || b == null) return false;
		while (a.hasNext()) {
			if (! b.hasNext()) return false;
			final IntentFilter.AuthorityEntry o1 = a.next();
			final IntentFilter.AuthorityEntry o2 = b.next();
			if (! equal(o1, o2)) return false;
		}
		return ! b.hasNext();
	}

	private static boolean equal(final PatternMatcher a, final PatternMatcher b) {
		return a == b || (a != null && b != null && a.getType() == b.getType() && equal(a.getPath(), b.getPath()));
	}

	private static boolean equal(final IntentFilter.AuthorityEntry a, final IntentFilter.AuthorityEntry b) {
		return a == b || (a != null && b != null && equal(a.getHost(), b.getHost()) && a.getPort() == b.getPort());
	}

	private static boolean elementsEqual(final Iterator<?> a, final Iterator<?> b) {
		while (a.hasNext()) {
			if (! b.hasNext()) return false;
			if (! equal(a.next(), b.next())) return false;
		}
		return ! b.hasNext();
	}

	private static boolean equal(final Object a, final Object b) { return a == b || (a != null && a.equals(b)); }
}