package pair;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Pair<X extends Comparable<X>, Y extends Comparable<Y>> implements
		Comparable<Pair<X, Y>>, Cloneable {

	private X first;

	private Y second;

	public Pair(X first, Y second) {
		this.first = first;
		this.second = second;
	}

	public X getFirst() {
		return this.first;
	}

	public void setFirst(X first) {
		this.first = first;
	}

	public Y getSecond() {
		return this.second;
	}

	public void setSecond(Y second) {
		this.second = second;
	}

	public static <Z extends Comparable<Z>> Z greater(Pair<Z, Z> p) {
		return (p.getFirst().compareTo(p.getSecond()) > 0) ? p.getFirst() : p
				.getSecond();
	}

	public static double sum(Pair<? extends Number, ? extends Number> p) {
		return p.getFirst().doubleValue() + p.getSecond().doubleValue();
	}

	@Override
	public Object clone() {
		return new Pair<X, Y>(this.getFirst(), this.getSecond());

	}

	@Override
	public boolean equals(Object o) {
		return (o instanceof Pair)
				&& ((Pair<?, ?>) o).getFirst().equals(this.getFirst())
				&& ((Pair<?, ?>) o).getSecond().equals(this.getSecond());
	}

	@Override
	public int compareTo(Pair<X, Y> p) {
		return (this.getFirst().compareTo(p.getFirst()) == 0) ? this
				.getSecond().compareTo(p.getSecond()) : this.getFirst()
				.compareTo(p.getFirst());
	}

	@Override
	public String toString() {
		return "(" + this.getFirst() + ", " + this.getSecond() + ")";
	}

	// classe interne non statique
	// public class FirstComparator implements Comparator<Pair<X, Y>> {
	// @Override
	// public int compare(Pair<X, Y> p1, Pair<X, Y> p2) {
	// return p1.getFirst().compareTo(p2.getFirst());
	// }
	// }

	// classe interne statique
	public static class SecondComparator<U extends Comparable<U>, V extends Comparable<V>>
			implements Comparator<Pair<U, V>> {
		@Override
		public int compare(Pair<U, V> p1, Pair<U, V> p2) {
			return p1.getSecond().compareTo(p2.getSecond());
		}
	}

	public static class SumComparator implements
			Comparator<Pair<? extends Number, ? extends Number>> {
		@Override
		public int compare(Pair<? extends Number, ? extends Number> p1,
				Pair<? extends Number, ? extends Number> p2) {
			return new Double(Pair.sum(p1)).compareTo(new Double(Pair.sum(p2)));
		}
	}

	public static <E> void displayList(List<E> l) {
		for (E e : l) {
			System.out.print(e + " ");
		}
		System.out.println();
	}

	public static void main(String[] args) {
		List<Pair<Integer, Integer>> pairs = new ArrayList<>();
		pairs.add(new Pair<Integer, Integer>(1, 1));
		pairs.add(new Pair<Integer, Integer>(1, 7));
		pairs.add(new Pair<Integer, Integer>(2, 0));
		pairs.add(new Pair<Integer, Integer>(2, 2));
		pairs.add(new Pair<Integer, Integer>(2, 0));
		for (Pair<Integer, Integer> p : pairs) {
			System.out.println("Plus grand de " + p + " : " + Pair.greater(p));
		}
		System.out.println(pairs.get(0) + " > " + pairs.get(1) + " ? : "
				+ pairs.get(0).compareTo(pairs.get(1)));
		System.out.println(pairs.get(2) + " > " + pairs.get(1) + " ? : "
				+ pairs.get(2).compareTo(pairs.get(1)));
		System.out.println(pairs.get(2) + " > " + pairs.get(4) + " ? : "
				+ pairs.get(2).compareTo(pairs.get(4)));
		List<Pair<Integer, Double>> pairs2 = new ArrayList<>();
		pairs2.add(new Pair<Integer, Double>(2, 0.0));
		pairs2.add(new Pair<Integer, Double>(1, 1.5));
		pairs2.add(new Pair<Integer, Double>(1, 7.5));
		pairs2.add(new Pair<Integer, Double>(2, 2.6));
		for (Pair<Integer, Double> p : pairs2) {
			System.out.println("Somme de " + p + " : " + Pair.sum(p));
		}
		System.out.println("Liste de paires non triée :");
		displayList(pairs2);
		System.out.println("Liste de paire triée :");
		Collections.sort(pairs2);
		displayList(pairs2);
		System.out.println("Liste de paire triée selon la seconde valeur :");
		Collections.sort(pairs2, new Pair.SecondComparator<Integer, Double>());
		displayList(pairs2);
		System.out.println("Liste de paire triée selon la première valeur :");
		Collections.sort(pairs2, new Comparator<Pair<Integer, Double>>() { // classe
																			// interne
																			// et
																			// anonyme
					@Override
					public int compare(Pair<Integer, Double> p1,
							Pair<Integer, Double> p2) {
						return p1.getFirst().compareTo(p2.getFirst());
					}
				});
		displayList(pairs2);
		System.out.println("Liste de paire triée selon la somme des deux valeurs :");
		Collections.sort(pairs2, new Pair.SumComparator());
		displayList(pairs2);
	}
}
