/* itgcorp.cpp
 *
 * $Id: itgcorp.cpp,v 1.2 2011/10/16 22:36:43 gildea Exp $
 */

#include "itgcorp.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <list>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <iostream>
#include <sstream>

using namespace std;

#define MAXLINELEN 50000
#define SEP " \t\n\r"

ITGCorp::ITGCorp(char *efname, char *cfname, char mode)
{
  if (mode=='t'||mode=='v') {
    ef = fopen(efname, "r");
    if (NULL == ef) {
      printf("* FATAL: can't read from %s\n", efname);
      exit(-1);
    }
  } else {
    ef = fopen(efname, "w");
    if (NULL == ef) {
      printf("* FATAL: can't write to corpus file %s\n", efname);
      exit(-1);
    }
  }     
  cf = fopen(cfname, "r");
  if (NULL == cf) {
    printf("* FATAL: can't read from %s\n", cfname);
    exit(-1);
  }
}

ITGCorp::~ITGCorp()
{
  fclose(ef);
  fclose(cf);
}

int ITGCorp::fillin(WORDTYPE **dest, string buf, int *len, int max) {
  stringstream tokens( buf );
  int token;
  list<WORDTYPE> ids;
  while (tokens >> token) {
    ids.push_back(token);
  }

  (*len) = ids.size();

  if ( (*len == 0) ||  (*len > max) ) //added by hao apr 24, 2008 to block zero-length sentences
//     cout << "sentence too long (" << *len << "), returning\n";
    return 0;


  ids.push_back(0);

  copy(ids.begin(), ids.end(), *dest);

  return 1;
}

/* retrieves from the corpus server instead of from its own file */
int ITGCorp::retrieve_net(WORDTYPE **earray, int *elen, int emax, WORDTYPE **carray, int *clen, int cmax) {

  int ok;

  do {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sock) {
      cerr << "* FATAL: socket error\n";
      exit(2);
    }

    // TODO: check for error in setsockopt?
    int on = 1;
#ifdef __APPLE__
    setsockopt( sock, SOL_SOCKET, SO_REUSEADDR & SO_NOSIGPIPE, 
                (const char*) &on, sizeof(on));
#else
    setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, sizeof(on));
#endif



    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    inet_pton(AF_INET, host.c_str(), &addr.sin_addr);
    int status = connect(sock, (sockaddr *) &addr, sizeof(addr));
    if (-1 == status) {
      cerr << "* FATAL: connect error\n";
      exit(2);
    }

    /* send the request */
    const char *msg = "GET\n";
#ifdef MSG_NOSIGNAL
    status = send(sock, msg, strlen(msg), MSG_NOSIGNAL);
#else
    status = send(sock, msg, strlen(msg), 0);
#endif
    if (-1 == status) {
      cerr << "* FATAL: send error\n";
      exit(2);
    }

    /* receive the sentence pair */
    int maxsize = 8192;
    char buffer[ maxsize ];
    *buffer = '\0';
    status = recv(sock, buffer, 8192, 0);
    if (-1 == status) {
      cerr << "* FATAL: recv error\n";
      exit(2);
    }
    buffer[status-1] = '\0';   // replace last newline
    string buf(buffer);
    int split = buf.find_first_of('\n');
//     printf("* recvd %d bytes, found break at %d\n", status, split);
    string l1str = buf.substr(0,split);
    string l2str;
    if (split == -1) { // couldn't find
//       printf("* didn't get all the data, going for more\n");
      *buffer = '\0';
      status = recv(sock, buffer, 8192, 0);
      if (-1 == status) {
        cerr << "* FATAL: recv error (2)\n";
        exit(2);
      }
      buffer[status-1] = '\0';   // replace last newline
      l2str = string(buffer);
    } else {
      l2str = buf.substr(split+1);
    }
    close(sock);

//     cout << "* buf = '" << buf << "'\n";
//     cout << "* l1str = '" << l1str << "'\n";
//     cout << "* l2str = '" << l2str << "'\n";
    if (l1str == "0" || l2str == "0") {
      return 0;
    }

    ok  = fillin(earray, l1str, elen, emax);
    ok &= fillin(carray, l2str, clen, cmax);

  } while (!ok);

  return 1;
}

int ITGCorp::retrieve(WORDTYPE **earray, int *elen, int emax, WORDTYPE **carray, int *clen, int cmax) {
//   if (port != 0) 
//     return retrieve_net(earray, elen, emax, carray, clen, cmax);

  char buffer[MAXLINELEN];
  int ok;

  //keep looking until finding the first pair within size limits
  do {
    if (feof(ef)||feof(cf))
      return 0;
    *buffer='\0';
    fgets(buffer, MAXLINELEN, ef);

    ok = fillin(earray, string(buffer), elen, emax);
    *buffer='\0';
    fgets(buffer, MAXLINELEN, cf);

    ok &= fillin(carray, string(buffer), clen, cmax);
  } while (!ok);

  return 1;
}

int ITGCorp::retrieve(WORDTYPE **carray, int *clen, int cmax) {
  char buffer[MAXLINELEN];
  int ok;

  do {
    if (feof(cf))
      return 0;
    *buffer='\0';
    fgets(buffer, MAXLINELEN, cf);

    if (strlen(buffer) == 0)
      return 0;

    ok = fillin(carray, string(buffer), clen, cmax);
  } while (!ok);

  return 1;
}

int ITGCorp::reset(){
  fseek(ef, 0, SEEK_SET);
  fseek(cf, 0, SEEK_SET);
  return 1;
}
