#include "session_manager.h"
#include "msql_acces.h"
#include "config_package.h"
#include <unistd.h>
#include <sys/wait.h>
#include <iostream>
#include <cstring>

session_manager::session_manager(int fd)
{
  this->fd=fd;
  this->data=new msql_acces();
}

bool session_manager::validate_pass(){
  char* buffer = new char[256];
  this->read_data(buffer, 256);
  std::string user=buffer;
  this->read_data(buffer, 256);
  std::string pass=buffer;
  if(this->data->get_passwd(user)==pass){
      this->write_data("pass");
      this->user=user;
      return true;
    }else{
      this->write_data("fail");
      return false;
    }
}

void session_manager::start_dialog(){
  char* buffer = new char[5];
  while(true){
      int n_read=this->read_data(buffer,5);
      if(strcmp(buffer, "exec")==0){
          this->execute();
        }else if(strcmp(buffer, "info")==0){
          this->send_information();
        }else if(strcmp(buffer, "remv")==0){
          this->remove();
        }else if(strcmp(buffer,"uinf")==0){
          this->send_user_info();
        }else if(strcmp(buffer,"cusr")==0){
          this->create_user();
        }else if(strcmp(buffer,"rusr")==0){
          this->remove_user();
        }else if((strcmp(buffer,"exit")==0)||(n_read==0)){
          break;
        }
  }
}

int session_manager::execute(){
  char* n_package = new char[250];
  this->read_data(n_package, 5);
  this->read_data(n_package, 250);
  char* use_conf=new char[256];
  this->read_data(use_conf,2);
  if(strcmp(use_conf,"y")==0){
     config_package conf = config_package(n_package);
     this->read_data(use_conf,256);
     conf.change_uses(use_conf);
    }else if(strcmp(use_conf,"n")!=0){
      perror("fail in protocol comunication");
      return -1;
    }
  delete [] (use_conf);
  std::string result = this->appli_command("--ask", n_package);
  if(result=="err"){
      return -1;
    }else{
      if(!this->data->get_package_exists(result)){
          this->data->write_install(result, user);
        }
      return 1;
    }
}

int session_manager::remove(){
  char* n_package = new char[256];
  this->read_data(n_package, 256);
  std::string result = this->appli_command("--unmerge",n_package);
  if(result=="err"){
      return -1;
    }else{
      this->data->write_remove(result);
      return 1;
    }
}

std::string session_manager::appli_command(char comand[], char* n_package){
  this->args=new char*[4];
    this->args[0]="emerge";
    this->args[1]=comand;
    this->args[2]=n_package;
    this->args[3]=nullptr;
  int pid = fork();
  int status=-2;
  std::string ret;
  if(pid==0){
      if(execvp(this->args[0],this->args)==-1){
          std::cout << "error inesperado" << std::endl;
        }
      exit(0);
  }else {
    waitpid(pid, &status, WCONTINUED);
    if(status>0){
        this->write_data("ok");
        ret = n_package;
        delete[] (n_package);
      }else{
        this->write_data("bad");
        delete[] (n_package);
        ret = "err";
      }
  }
  return ret;
}

void session_manager::send_information(){
  std::list<std::string> lis=this->data->get_pinfo();
  for(std::string info : lis){
      this->write_data(info);
    }
  this->write_data("end:info");
}

void session_manager::send_user_info(){
  std::list<std::string> lis=this->data->get_uinfo();
  for(std::string info : lis){
      this->write_data(info);
    }
  this->write_data("end:info");
}

void session_manager::create_user(){
  char* user=new char[256];
  char* pass=new char[256];
  char* admin=new char[256];
  //basura
  this->read_data(user, 256);
  this->read_data(user, 256);
  this->read_data(pass, 256);
  this->read_data(admin, 256);
  this->data->create_user(std::string(user), std::string(pass), admin[0]=='t');
  delete [] (user);
  delete [] (pass);
  delete [] (admin);
}

void session_manager::remove_user(){
  char *buffer=new char[256];
  this->read_data(buffer,256);
  this->read_data(buffer,256);
  this->data->remove_user(std::string(buffer));
}

int session_manager::read_data(char* input, int size){
  return read(this->fd, input, size);
}

int session_manager::write_data(std::string output){
  return write(this->fd, output.data(), output.size());
}