#include "msql_acces.h"
#include <iostream>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <string.h>

std::string msql_acces::user="root";
std::string msql_acces::pass="1234";
msql_acces* msql_acces::instance=nullptr;

msql_acces* msql_acces::get_instance(){
  if(msql_acces::instance==nullptr){
      msql_acces::instance=new msql_acces();
    }
  return msql_acces::instance;
}

msql_acces::msql_acces()
{
  driver = get_driver_instance();
  con = driver->connect("tcp://127.0.0.1:3306", msql_acces::user, msql_acces::pass);
  con->setSchema("bin_database");
}


std::string msql_acces::get_passwd(std::string username){
  sql::PreparedStatement *pstmt = con->prepareStatement("select passwd from users where username=?");
  pstmt->setString(1,username);
  sql::ResultSet *res = pstmt->executeQuery();
  std::string ret;
  while(res->next())
    ret = res->getString("passwd");
  delete res;
  delete pstmt;
  return ret;
}

bool msql_acces::get_admin(std::string username){
  sql::PreparedStatement *pstmt = con->prepareStatement("select admin from users where username=?");
  pstmt->setString(1,username);
  sql::ResultSet *res = pstmt->executeQuery();
  bool ret=false;
  while(res->next())
    ret = res->getBoolean("admin");
  delete res;
  delete pstmt;
  return ret;
}

std::list<std::string> msql_acces::get_pinfo(){
  sql::PreparedStatement *pstmt =
      con->prepareStatement("select packages.name, packages.created, packages.uses, users.username "
                            "from packages "
                            "join users on users.id=packages.user ");
  sql::ResultSet *res = pstmt->executeQuery();
  std::list<std::string> ret;
  std::string aux;
  while(res->next()){
      aux="";
      aux += res->getString(1);
      aux += ":"+res->getString(2);
      if(res->getBoolean(3)){
          aux+=":t";
        }else{
          aux+=":f";
        }
      aux += ":"+res->getString(4);
      ret.push_back(aux);
    }
  delete res;
  delete pstmt;
  return ret;
}

std::list<std::string> msql_acces::get_uinfo(){
  sql::PreparedStatement *pstmt =
      con->prepareStatement("select username,admin from users");
  sql::ResultSet *res = pstmt->executeQuery();
  std::list<std::string> ret;
  std::string aux;
  while(res->next()){
      aux="";
      aux += res->getString(1);
      //aux += ":"+res->getString(2);
      if(res->getBoolean(2)){
          aux+=":t";
        }else{
          aux+=":f";
        }
      ret.push_back(aux);
    }
  delete res;
  delete pstmt;
  return ret;
}

void msql_acces::write_install(std::string package, std::string user){
  sql::PreparedStatement *pstmt =
      con->prepareStatement("insert into packages(name,user) values(?,(select id from users where username=?))");
  pstmt->setString(1,package);
  pstmt->setString(2,user);
  pstmt->executeUpdate();
  delete pstmt;
}

void msql_acces::write_remove(std::string package){
  sql::PreparedStatement *pstmt =
      con->prepareStatement("delete from packages where name=?");
  pstmt->setString(1,package);
  pstmt->executeUpdate();
  delete pstmt;
}

bool msql_acces::get_package_exists(std::string package){
  sql::PreparedStatement *pstmt = con->prepareStatement("select count(id) from packages where name=?");
  pstmt->setString(1,package);
  sql::ResultSet *res = pstmt->executeQuery();
  int ret=0;
  while(res->next()){
    ret = res->getInt(1);
    }
  delete pstmt;
  return ret>0;
}

void msql_acces::create_user(std::string user, std::string pass, bool admin){
  sql::PreparedStatement *pstmt = con->prepareStatement("insert into users(username, passwd, admin) values(?, ?, ?)");
  pstmt->setString(1,user);
  pstmt->setString(2,std::string(data_acces::get_hash(&pass[0])));
  pstmt->setBoolean(3,admin);
  pstmt->executeQuery();
  delete pstmt;
}

void msql_acces::remove_user(std::string user){
  sql::PreparedStatement *pstmt =
      con->prepareStatement("delete from users where username=?");
  pstmt->setString(1,user);
  pstmt->executeUpdate();
  delete pstmt;
}