#include <sstream>
#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>

#include <pqxx/pqxx>

using namespace std;
using namespace pqxx;

struct true_type
{
};

struct false_type
{
};

template<typename T>
struct is_container:public false_type
{
};

template<typename T, typename U>
struct is_container<vector<T, U> >:public true_type
{
};

template<typename T, typename U>
struct is_container<deque<T, U> >:public true_type
{
};

template<typename T, typename U>
struct is_container<list<T, U> >:public true_type
{
};

template<typename T, typename U, typename V>
struct is_container<set<T, U, V> >:public true_type
{
};

template<typename T>
void do_pg_empty_element(const T&, stringstream&, false_type)
{
	// do nothing; there is no element/constant
}

template<typename container>
void do_pg_empty_element(const container& elm, stringstream& append, true_type)
{
	typedef typename container::value_type contained_type;
	// empty inner array
	append << "{";
	do_pg_empty_element(contained_type(), append, is_container<contained_type>());
	append << "}";
}

// terminating condition: individual elements
template<typename T>
void do_pg_array_element(const T& elm, stringstream& append, false_type)
{
	append << "\"" << elm << "\"";
}

// append outer part of nested array
template<typename container>
void do_pg_array_element(const container& cnt, stringstream& append, true_type)
{
	typedef typename container::const_iterator it;
	typedef typename container::value_type contained_type;

	
	it last = cnt.end();
	if(!cnt.empty())
	{
		// there is no neater way of determining if 
		// an element is the last that works across
		// std lib containers
		--last;
	}
	else
	{
		do_pg_empty_element(cnt, append, true_type());
		return;
	}

	append << "{";

	for(it i = cnt.begin(); i != cnt.end(); ++i)
	{	
		do_pg_array_element(*i, append, is_container<contained_type>());
		if(i != last)
			append << ", ";
	}
	append << "}";
}

template<typename container>
string to_pg_array_constr(const container& cnt)
{
	stringstream result;
	do_pg_array_element(cnt, result, true_type());
	return result.str();
}

int main()
{
	vector<string> a;
	list<vector<int> > b;


	for(int i = 0; i < 10; ++i)
	{
		a.push_back("Peter's vector");	
		vector<int> sss;
		sss.push_back(0);
		sss.push_back(1);
		sss.push_back(2);
		b.push_front(sss);			
	}
	cout << "a: " << to_pg_array_constr(a) << endl << endl;
	cout << "b: " << to_pg_array_constr(b) << endl << endl;

	connection conn("dbname=postgres");

	work test(conn, "test");

	conn.prepare("unnest", "SELECT unnest($1::text[][])")("text[][]");

	result r = test.prepared("unnest")(to_pg_array_constr(a)).exec();

	for(result::const_iterator c = r.begin(); c != r.end(); ++c)
	{
		cout << c[0].as(string()) << endl;
	}
	
	return 0;
	
}

// c++ to_pg_array.cpp -L/usr/local/pgsql/lib -lpqxx -lpq

