/*
 * Comm.cpp
 *
 *  Created on: Apr 7, 2018
 *      Author: armin
 */

#include <Comm.h>
#include <Work.h>
#include <arpa/inet.h>
#include <bits/stdint-uintn.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cstring>
#include <sstream>
#include <stdexcept>

namespace comm {

using namespace std;

Comm::Comm(string host, int port) : port(port), host(host), sock(-1) {}

Work Comm::getWork(void) {
  if (sock < 0) {
    if (!conn()) {
      ostringstream o;
      o << "Connection to " << host << ":" << port << " failed";
      throw runtime_error(o.str());
    }
  }

  const char cmd[] = "WRK\n";
  if (send(sock, cmd, strlen(cmd), 0) < 0) {
    throw runtime_error("Sending WRK failed");
  }

  char buf[1024];
  ssize_t wrk_len;
  if ((wrk_len = recv(sock, buf, 1024, 0)) < 0) {
    throw runtime_error("Receiving of work failed");
  }

  string ws = string(buf, wrk_len - 1);
  Work wrk(ws);

  return (wrk);
}

/**
 * Connects socket to server
 *
 * @return true if connected successfully, false otherwise
 */
bool Comm::conn() {
  if (sock > -1) {
    return (true);
  }

  sock = socket(AF_INET, SOCK_STREAM, 0);

  if (sock < 0) {
    return (false);
  }

  sockaddr_in serv_addr;

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons((uint16_t)port);

  if (inet_pton(AF_INET, host.c_str(), &serv_addr.sin_addr) <= 0) {
    return (false);
  }

  if (connect(sock, reinterpret_cast<sockaddr*>(&serv_addr),
              sizeof(serv_addr)) < 0) {
    close(sock);
    return (false);
  }

  return (true);
}

Comm::~Comm() {
  shutdown(sock, SHUT_RDWR);
  close(sock);
  sock = -1;
}

}  // namespace comm
