#include <string>
#include <vector>
using namespace std;
#include "mysql.h"
#include "mysql++.h"

using namespace mysqlpp;

Connection my_connection;

/**
 * Definition of a User identified by:
 * - identifier (int)
 * - last name (string / VC 30)
 * - first name (string / VC 30)
 * - salary (float)
 */
class User {
protected:
	int id;
	string first_name;
	string last_name;
	float salary;
public:	
	// default constructor
	User() : id(-1), first_name(""), last_name(""), salary(0.0) {
	}
	
	// constructor with arguments, strings for last and first name 
	User(int _id, string _first_name, string _last_name, 
		float _salary) : id(_id), first_name(_first_name), 
		last_name(_last_name), salary(_salary) {
	}
	
	// constructor with arguments, const char * for last and first name
	User(int _id, const char *_first_name, const char *_last_name, 
		float _salary) : id(_id), first_name(_first_name), 
		last_name(_last_name), salary(_salary) {
	}
	
	// getters
	int get_id() { return id; }
	string get_first_name() { return first_name; }
	string get_last_name() { return last_name; }
	float get_salary() { return salary; }
	
	// printer
	friend ostream& operator<<(ostream& out, User& obj) {
		out << obj.id << ": " << obj.first_name << ": " << obj.last_name
			<< ": " << obj.salary;
		return out;
	}
};

// function that opens a connection to the database
bool open_connection(Connection &c) {
	try {
		if (c.connected()) return true;
		cerr << ">>> open connection..." << endl;
		c.connect("mydb", "localhost", "root", "mysqlpass");
		cerr << ">>> SUCCESS" << endl;
		return true;
	} catch(Exception& exc) {
		cout << ">>> FAILURE: Connection could not be established." << endl <<
			"Please create a MySQL database" << endl;
		return false;
	}
}

// retrieve the Users that corresponds to some last name criterion
void retrieve_all(string name, vector<User *>& v) {
	
	if (!open_connection(my_connection)) return ;

	try {
		User us;
		Query query = my_connection.query();
		query << "SELECT * FROM users WHERE us_last_name LIKE \"" << name << "\";";
		cout << query << endl;
		StoreQueryResult result = query.store();
		if (result.num_rows() == 0) {
			cout << "no record found" << endl;
		} else {
			for (size_t i=0; i<result.num_rows(); ++i) {
			
				const char *fn = result[i]["us_first_name"];
				const char *ln = result[i]["us_last_name"];
				User *new_us = new User(atoi(result[i]["us_id"]),
					fn, ln,	static_cast<float>(atof(result[i]["us_salary"])) );
				v.push_back(new_us);
			}
		}

	} catch(Exception& exc) {
		cout << ">>> FAILURE: could not retrieve users: " << exc.what() << endl;
	}

}

// insert a new User in the database
void insert(User& us) {

	if (!open_connection(my_connection)) return ;

	try {
		Query query = my_connection.query();
		query << "INSERT INTO users VALUES(''," <<
			"\"" << us.get_first_name() << "\"," <<
			"\"" << us.get_last_name() << "\"," <<
			us.get_salary() << ");";
		cout << query << endl;
		query.execute();
	} catch(Exception& exc) {
		cout << ">>> FAILURE: could not insert user" << endl;
	}
}

int main() {
	// insert users
	User us1(-1, "jean", "pinon", 1000.0);
	User us2(-1, "john", "pinson", 2000.0);
	User us3(-1, "tom", "robinson", 3000.0);
	
	insert(us1);
	insert(us2);
	insert(us3);
	
	// retrieve users
	vector<User *> users;
	retrieve_all("%in%", users);
	if (users.size() > 0) {
		for (User *us : users) {
			cout << (*us) << endl;
		}
	} else {
		cout << "no user found" << endl;
	}
	return 0;	
}

