#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include "popfetch.h"

char b[MAX_READ_BUFFER] = { 0 };
int s = 0, cur_in = 0, parse_in = 0, diff = 0;

/*
   Initialize all variables
*/
int socket_init(void)
{
  cur_in = 0;
  parse_in = 0;

  memset((char *)b, 0, MAX_READ_BUFFER);
  
  s = socket(AF_INET, SOCK_STREAM, 0);

  return s;   
}

/*
   Connect to defined POP server
*/
int socket_connect(void)
{
  int ret = 0;
  struct sockaddr_in addr;

  memset((struct sockaddr_in *)&addr, 0, sizeof(struct sockaddr_in));

  addr.sin_family      = AF_INET;
  addr.sin_port        = htons(POPFETCH_PORT);
  addr.sin_addr.s_addr = inet_addr(POPFETCH_ADDR);

  ret = connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
  if (ret == -1) {
     close(s);
     return 0;
  }

  return 1;
}

/*
   Read some more information into our head/tail buffer
*/
int socket_read(void)
{
  int ret = 0;
  fd_set rfds;
  struct timeval tv;

  if (cur_in >= (MAX_READ_BUFFER - 1)) {
     printf("Out of buffer space\n");
     return 0;
  }

  FD_SET(s, &rfds);
  
  tv.tv_sec = 1;
  tv.tv_usec = 0;

  ret = select((s + 1), &rfds, NULL, NULL, &tv);
  if (ret != 1)
     return 0;

  ret = read(s, (char *)(b + cur_in), ((MAX_READ_BUFFER - 1) - cur_in));

#ifdef SOCKET_DEBUG
  printf("READ(%d):[%s]\n", ret, (b + cur_in));
#endif

  if (ret > 0)
     cur_in += ret;

  else
     close(s);

  return ret;
}

/*
   Run through buffer looking for newline, return everything up to
   the newline.

   Save position in buffer.
*/
char *socket_parse(void)
{
  char *h = NULL, *t = NULL, *p = NULL;

  for (t = h = (char *)(b + parse_in); *h; h++) {
      if (*h == '\n')
         break;
  }

  diff = ((char *)h - (char *)t);
#ifdef SOCKET_DEBUG
  printf("Parsed %d more bytes\n", diff);
#endif

  if (!(*h))
     return NULL;  

  parse_in += diff;
#ifdef SOCKET_DEBUG
  printf("Parsed %d total of %d bytes\n", parse_in, cur_in);
#endif

  *h = '\0';

  parse_in++;

  for (p = t; *p; p++) {
      if (*p == '\r') {
         *p = '\0';
	 break;
      } 
  }

  return t;
}

/*
   Fix parsed and modified buffer
   based upon parse_in and diff
   variables.
*/
void socket_post_parse(void)
{
  if ((parse_in == 0) || (diff == 0)) {
#ifdef SOCKET_DEBUG
     printf("Cleanup with no leftovers\n");
#endif

     cur_in = 0;
     parse_in = 0;
     diff = 0;

     memset((char *)b, 0, MAX_READ_BUFFER);

     return;
  }

#ifdef SOCKET_DEBUG
  printf("Post cleanup\n");
  printf("  Before: [%s]\n", b);
#endif

  memcpy((char *)b, (char *)(b + parse_in), ((MAX_READ_BUFFER - 1) - parse_in));

#ifdef SOCKET_DEBUG
  printf("  After: [%s]\n", b);
#endif

  cur_in -= parse_in;
 
  parse_in = 0;
  diff = 0;

  memset((char *)(b + cur_in), 0, ((MAX_READ_BUFFER - 1) - cur_in));

#ifdef SOCKET_DEBUG
  printf("  Cleanup: [%s]\n", b);
  printf("%d(%d) bytes remain\n", cur_in, strlen(b));
#endif
}

int socket_write(char *str)
{
  int ret = 0, len = 0;

  len = strlen(str);

  ret = write(s, str, len); 
  if (ret < len) {
     close(s);
     return 0;
  } 

  return ret;
}
