// ==========================================================================
// $Id: stl_bind.cpp,v 1.2 2014/11/29 00:31:45 jlang Exp $
// CSI2372 example Code for lecture 13 C++11
// ==========================================================================
// (C)opyright:
//
//   Jochen Lang
//   SITE, University of Ottawa
//   800 King Edward Ave.
//   Ottawa, On., K1N 6N5
//   Canada. 
//   http://www.site.uottawa.ca
// 
// Creator: jlang (Jochen Lang)
// Email:   jlang@site.uottawa.ca
// ==========================================================================
// $Log: stl_bind.cpp,v $
// Revision 1.2  2014/11/29 00:31:45  jlang
// Check-in of in-class version
//
// Revision 1.1  2013/11/10 02:28:08  jlang
// Added examples on bind and lambdas
//
// ==========================================================================
#include <iostream>
#include <vector>
#include <algorithm>

using std::cout;
using std::endl;
using std::bind;
using std::ostream;
using std::placeholders::_1;
using std::placeholders::_2;
using std::cref;
using std::ref;


template <class T, const int NUM> class Point;

template <class T, const int NUM>
bool lessThan(const Point<T,NUM>&, const Point<T,NUM>& );

template <class T, const int NUM>
ostream& operator<<( ostream&, const Point<T,NUM>& );


template <class T, const int NUM>
class Point{
  T d_components[NUM];
  // Make sure Point cannot be copied
  Point(const Point<T,NUM>&);
public:
  Point();
  Point( T* _components );
  friend bool lessThan<T,NUM>(const Point<T,NUM>& ptA, 
			      const Point<T,NUM>& ptB );
	friend  
	ostream& operator<< <T,NUM> ( ostream& _os, const Point<T,NUM>& _pt );
};

template <class T, const int NUM>
Point<T,NUM>::Point() 
{}

template <class T, const int NUM>
Point<T,NUM>::Point( T* _components ) 
{
  for ( int i=0; i<NUM; i++ ) {
    d_components[i] = _components[i];
  }
}

template <class T, const int NUM>
ostream& operator<<( ostream& _os, const Point<T,NUM>& _pt )
{
  _os << "( ";
  for ( int i=0; i<NUM; i++ ) {
    if (i!=0) _os  << ", ";
    _os << _pt.d_components[i];
  }  
  _os << " )";
  return _os;
}

// lexographic <
template <class T, const int NUM>
bool lessThan(const Point<T,NUM>& ptA, const Point<T,NUM>& ptB ) {
  static_assert( NUM > 1, "Point must have at least 2 components" );
	return ptA.d_components[0] < ptB.d_components[0] || (
		!(ptB.d_components[0] < ptA.d_components[0]) && 
		ptA.d_components[1] < ptB.d_components[1]);
}

int main() {
  int initA[] = {-3,15};
  int initB[] = {-3,13};
  int zeroVal[] = {0,0};
  Point<int,2> iPt1(initA), iPt2(initB), iPt0(zeroVal);
	
	std::function<bool( const Point<int,2>& )> lessThanZero = 
					bind(lessThan<int,2>,_1,cref(iPt0));
	auto greaterThan = bind(lessThan<int,2>,_2,_1);
	
	if (lessThan(iPt2,iPt1)) {
		cout << "Pt2 " << iPt2 << " is less than Pt1 " << iPt1 << endl;
	}	
	if (lessThanZero(iPt1)) {  
	  cout << "Pt1 is less than zero: " << iPt1 << endl;
	}
	if (greaterThan(iPt1,iPt2)) {
		cout << "Pt1 " << iPt1 << " is greater than Pt2 " << iPt2 << endl;
	}	
  return 0;
}
