/*********************************************************************
 * This file is part of the cpplibs suite.
 *
 * Copyright (C) 2001 Topi Mäenpää and Jaakko Viertola
 * All rights reserved.
 *
 * This program is free software. You can redistribute and/or modify
 * it under the terms of the free software licence found in the
 * accompanying file "COPYING". The licence terms must always be
 * redistributed with this source file. The above copyright notice
 * must be reproduced in all modified and unmodified copies of this
 * source file.
 *
 * $Revision: 1.6 $
 *********************************************************************/

#ifndef _PAIR_H
#define _PAIR_H

#include "Object.h"
#include <iostream>

namespace util
{
	/**
	 * Pair is a utility class for storing pairs of objects. For
	 * example, Hashtable uses Pair to store key-value pairs.
	 **/
	template <class T, class U>	class Pair : virtual public Object
	{
	public:
		/**
		 * The default constructor. Primitive type elements are
		 * uninitialized, and complex type elements are initialized using
		 * their default constructor.
		 **/
		Pair() {}
		/**
		 * Create a pair of objects.
		 **/
		Pair(const T& obj1, const U& obj2) : _firstItem(obj1), _secondItem(obj2) {}
		/**
		 * Copy an object pair.
		 **/
		Pair(const Pair& other) : _firstItem(other._firstItem), _secondItem(other._secondItem) {}

		/**
		 * Copy the contents of another pair.
		 **/
		Pair& operator= (const Pair& other) { copy(other); return *this; }

		/**
		 * Get the first element in the pair.
		 **/
		T getFirst(void) const { return _firstItem; }
		/**
		 * Get the first element in the pair.
		 **/
		T& first(void) { return _firstItem; }
		/**
		 * Get the first element in the pair.
		 **/
		const T& first(void) const { return _firstItem; }
		/**
		 * Set the first element in the pair.
		 **/
		void setFirst(const T& obj) { _firstItem = obj; }

		/**
		 * Get the second element in the pair.
		 **/
		U getSecond(void) const { return _secondItem; }
		/**
		 * Get the second element in the pair.
		 **/
		U& second(void) { return _secondItem; }
		/**
		 * Get the second element in the pair.
		 **/
		const U& second(void) const { return _secondItem; }
		/**
		 * Set the second element in the pair.
		 **/
		void setSecond(const U& obj) { _secondItem = obj; }

		/**
		 * Compare two pairs. Pairs are equal if both of their elements
		 * are equal.
		 **/
		template <class V, class X> inline friend bool operator== (const Pair<V,X>& p1, const Pair<V,X>& p2);
		/**
		 * Compare two pairs. Pairs are different if either of their
		 * elements are different.
		 **/
		template <class V, class X> inline friend bool operator!= (const Pair<V,X>& p1, const Pair<V,X>& p2);

		/**
		 * Compare two pairs. The relative order of two pairs is defined
		 * by their first elements.
		 **/
		template <class V, class X> inline friend bool operator< (const Pair<V,X>& p1, const Pair<V,X>& p2);

		/**
		 * Compare two pairs. The relative order of two pairs is defined
		 * by their first elements.
		 **/
		template <class V, class X> inline friend bool operator> (const Pair<V,X>& p1, const Pair<V,X>& p2);

		/**
		 * Compare two pairs. The relative order of two pairs is defined
		 * by their first elements.
		 **/
		template <class V, class X> inline friend bool operator<= (const Pair<V,X>& p1, const Pair<V,X>& p2);

		/**
		 * Compare two pairs. The relative order of two pairs is defined
		 * by their first elements.
		 **/
		template <class V, class X> inline friend bool operator>= (const Pair<V,X>& p1, const Pair<V,X>& p2);

		/**
		 * Multiply two pairs. The multiplying of two pairs is defined
		 * by their first elements.
		 **/
		Pair& operator*= (const Pair& other) { _firstItem *= other._firstItem; return *this; }
		template <class V, class X> inline friend Pair<V,X> operator* (const Pair<V,X>& p1, const Pair<V,X>& p2);
		/**
		 * Divide two pairs. The dividing of two pairs is defined
		 * by their first elements.
		 **/
		Pair& operator/= (const Pair& other) { _firstItem /= other._firstItem; return *this; }
		template <class V, class X> inline friend Pair<V,X> operator/ (const Pair<V,X>& p1, const Pair<V,X>& p2);
		/**
		 * Adding two pairs. The adding of two pairs is defined
		 * by their first elements.
		 **/
		Pair& operator+= (const Pair& other) { _firstItem += other._firstItem; return *this; }
		template <class V, class X> inline friend Pair<V,X> operator+ (const Pair<V,X>& p1, const Pair<V,X>& p2);
		/**
		 * Subtract two pairs. The subtracting of two pairs is defined
		 * by their first elements.
		 **/
		Pair& operator-= (const Pair& other) { _firstItem -= other._firstItem; return *this; }
		template <class V, class X> inline friend Pair<V,X> operator- (const Pair<V,X>& p1, const Pair<V,X>& p2);
		
		/**
		 * Multiply pair and value. The multiplying of pair and value is defined
		 * by the first element of pair and the value.
		 **/
		Pair& operator*= (T value) { _firstItem *= value; return *this; }
		template <class V, class X> inline friend Pair<V,X> operator* (const Pair<V,X>& p1, V value);
		/**
		 * Dividing pair and value. The dividing of pair and value is defined
		 * by the first element of pair and the value.
		 **/
		Pair& operator/= (T value) { _firstItem /= value; return *this; }
		template <class V, class X> inline friend Pair<V,X> operator/ (const Pair<V,X>& p1, V value);
		/**
		 * Adding pair and value. The adding of pair and value is defined
		 * by the first element of pair and the value.
		 **/
		Pair& operator+= (T value) { _firstItem += value; return *this; }
		template <class V, class X> inline friend Pair<V,X> operator+ (const Pair<V,X>& p1, V value);
		/**
		 * Subtract pair and value. The subtracting of pair and value is defined
		 * by the first element of pair and the value.
		 **/
		Pair& operator-= (T value) { _firstItem -= value; return *this; }
		template <class V, class X> inline friend Pair<V,X> operator- (const Pair<V,X>& p1, V value);
		
	private:
		void copy(const Pair& other);
		T _firstItem;
		U _secondItem;
	};

	template <class T, class U> void Pair<T,U>::copy(const Pair<T,U>& other)
	{
		_firstItem = other._firstItem;
		_secondItem = other._secondItem;
	}

	template <class V, class X> bool operator== (const Pair<V,X>& p1, const Pair<V,X>& p2)
	{
		return (p1._firstItem == p2._firstItem) && (p1._secondItem == p2._secondItem);
	}

	template <class V, class X> bool operator!= (const Pair<V,X>& p1, const Pair<V,X>& p2)
	{
		return (p1._firstItem != p2._firstItem) || (p1._secondItem != p2._secondItem);
	}

	template <class V, class X> bool operator< (const Pair<V,X>& p1, const Pair<V,X>& p2)
	{
		return p1._firstItem < p2._firstItem;
	}
	
	template <class V, class X> bool operator> (const Pair<V,X>& p1, const Pair<V,X>& p2)
	{
		return p1._firstItem > p2._firstItem;
	}
	
	template <class V, class X> bool operator<= (const Pair<V,X>& p1, const Pair<V,X>& p2)
	{
		return p1._firstItem <= p2._firstItem;
	}
	
	template <class V, class X> bool operator>= (const Pair<V,X>& p1, const Pair<V,X>& p2)
	{
		return p1._firstItem >= p2._firstItem;
	}
	
	template <class V, class X> Pair<V,X> operator* (const Pair<V,X>& p1, const Pair<V,X>& p2)
	{
		Pair<X,V> result(p1);
		result._firstItem *= p2._firstItem;
		return result;
	}
	
	template <class V, class X> Pair<V,X> operator/ (const Pair<V,X>& p1, const Pair<V,X>& p2)
	{
		Pair<X,V> result(p1);
		result._firstItem /= p2._firstItem;
		return result;
	}
	
	template <class V, class X> Pair<V,X> operator+ (const Pair<V,X>& p1, const Pair<V,X>& p2)
	{
		Pair<X,V> result(p1);
		result._firstItem += p2._firstItem;
		return result;
	}
	
	template <class V, class X> Pair<V,X> operator- (const Pair<V,X>& p1, const Pair<V,X>& p2)
	{
		Pair<X,V> result(p1);
		result._firstItem -= p2._firstItem;
		return result;
	}
	
	template <class V, class X> Pair<V,X> operator* (const Pair<V,X>& p1, V value)
	{
		Pair<V,X> result(p1);
		result._firstItem *= value;
		return result;
	}
	
	template <class V, class X> Pair<V,X> operator/ (const Pair<V,X>& p1, V value)
	{
		Pair<V,X> result(p1);
		result._firstItem /= value;
		return result;
	}
	
	template <class V, class X> Pair<V,X> operator+ (const Pair<V,X>& p1, V value)
	{
		Pair<V,X> result(p1);
		result._firstItem += value;
		return result;
	}
	
	template <class V, class X> Pair<V,X> operator- (const Pair<V,X>& p1, V value)
	{
		Pair<V,X> result(p1);
		result._firstItem -= value;
		return result;
	}
}

#define _LIST_INCLUDED_FROM_PAIR_H
#include "Util.h"
#undef _LIST_INCLUDED_FROM_PAIR_H

namespace util
{
	template <class T, class U> std::ostream& operator<< (std::ostream& out, const Pair<T,U>& pair)
	{
		out << "<pair>" << std::endl << "<first>";
		Util::writeXMLItem(out, pair.first());
		out << "</first>" << std::endl << "<second>";
		Util::writeXMLItem(out,pair.second());
		out << "</second>" << std::endl << "</pair>";
		return out;
	}
}

#endif
