// ----------------------------------------------------------------------------
// Tuple structs for use in .NET Not-Quite-3.5 (e.g. Unity3D).
//
// Used Chapter 3 in http://functional-programming.net/ as a starting point.
//
// Note: .NET 4.0 Tuples are immutable classes so they're *slightly* different.
// ----------------------------------------------------------------------------
using System;
/// 
/// Represents a functional tuple that can be used to store
/// two values of different types inside one object.
/// 
/// The type of the first element
/// The type of the second element
/// The type of the third element
public sealed class Tuple {
	private readonly T1 item1;
	private readonly T2 item2;
	private readonly T3 item3;
	/// 
	/// Retyurns the first element of the tuple
	/// 
	public T1 Item1{
		get{ return item1; }
	}
	/// 
	/// Returns the second element of the tuple
	/// 
	public T2 Item2{
		get{ return item2; }
	}
	/// 
	/// Returns the second element of the tuple
	/// 
	public T3 Item3{
		get{ return item3; }
	}
	/// 
	/// Create a new tuple value
	/// 
	/// First element of the tuple
	/// Second element of the tuple
	/// Third element of the tuple
	public Tuple(T1 item1, T2 item2, T3 item3){
		this.item1 = item1;
		this.item2 = item2;
		this.item3 = item3;
	}
	public override int GetHashCode(){
		int hash = 17;
		hash = hash * 23 + (item1 == null ? 0 : item1.GetHashCode());
		hash = hash * 23 + (item2 == null ? 0 : item2.GetHashCode());
		hash = hash * 23 + (item3 == null ? 0 : item3.GetHashCode());
		return hash;
	}
	public override bool Equals(object o){
		if(!(o is Tuple)){
			return false;
		}
		var other = (Tuple)o;
		return this == other;
	}
	public static bool operator==(Tuple a, Tuple b){
		if(object.ReferenceEquals(a, null)){
			return object.ReferenceEquals(b, null);
		}else{
			if(object.ReferenceEquals(b, null)) return false;
		}
		if(a.item1 == null && b.item1 != null) return false;
		if(a.item2 == null && b.item2 != null) return false;
		if(a.item3 == null && b.item3 != null) return false;
		return
			a.item1.Equals(b.item1) &&
			a.item2.Equals(b.item2) &&
			a.item3.Equals(b.item3);
	}
	public static bool operator!=(Tuple a, Tuple b){
		return !(a == b);
	}
	public void Unpack(Action unpackerDelegate){
		unpackerDelegate(Item1, Item2, Item3);
	}
}