#include "config.h"

#include <stdio.h>

#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
#  include <stdlib.h>
# endif
#endif

#ifdef HAVE_STRING_H
# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
#  include <memory.h>
# endif
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
#  include <strings.h>
# endif
#endif

#include <glib.h>
#include <glib/gi18n.h>

#include "cddbp.h"
#include "main_window_handler.h"
#include "misc_utils.h"


int cddbp_query_proxy(FILE *, const char *disk_id, int tracknum,
                      long int offsets[], int duration, int *matches,
                      char ***category_buffer, char ***title_buffer,
                      char ***id_buffer);
int cddbp_stat(FILE *, char **result);
int http_stat(const char *server, int port, const char *URL,
              char **result, const char *client, const char *version);


int cddbp_signon(FILE *socket)
{
    char *buffer;
    int code;

    buffer = get_string_piece(socket, '\n');

    if(buffer == NULL)
    {
        return -1;
    }

#ifdef DEBUG
    printf("<= %s\n", buffer);
#endif
    /* convert the answer code to int */
    code = ((buffer[ 0 ] - 0x30) * 10 + (buffer[ 1 ] - 0x30)) * 10 + (buffer[ 2 ] - 0x30);

    free(buffer);
    return code;
}



int cddbp_handshake(FILE *socket, const char *clientname, const char *version)
{
    char *buffer;
    int code;

    /* Greetings! */
    /* <tmancill@debian.org> - no need to disclose user and hostname */
#ifdef DEBUG
    printf("=> cddb hello %s %s %s %s\n",
           "anonymous", "localhost", clientname, version);
#endif
    fprintf(socket, "cddb hello %s %s %s %s\n",
            "anonymous", "localhost", clientname, version);

    buffer = get_string_piece(socket, '\n');

    if(buffer == NULL)
    {
        return -1;
    }

#ifdef DEBUG
    printf("<= %s\n", buffer);
#endif

    code = ((buffer[ 0 ] - 0x30) * 10 + (buffer[ 1 ] - 0x30)) * 10 + (buffer[ 2 ] - 0x30);

    free(buffer);
    return code;
}



int cddbp_query(FILE *socket, const char *disk_id, int tracknum,
                long int offset[], int duration, int *matches,
                char ***category_buffer, char ***title_buffer,
                char ***id_buffer)
{
    char *buffer, *tmp;
    int code, i;

    buffer = (char *) malloc(strlen("cddb query ") + strlen(disk_id) + 1 + 3 +
                             tracknum * 10 + 6 + 1);

    sprintf(buffer, "cddb query %s %d ", disk_id, tracknum);
    tmp = (char *) malloc(10);

    for(i = 0; i < tracknum; i++)
    {
        sprintf(tmp, "%ld ", offset[ i ]);
        strcat(buffer, tmp);
    }

    sprintf(tmp, "%d\n", duration);
    strcat(buffer, tmp);
    free(tmp);

#ifdef DEBUG
    printf("=> %s\n", buffer);
#endif

    fwrite(buffer, strlen(buffer)+1, 1, socket);
    free(buffer);

    tmp = buffer = get_string_piece(socket, '\n');

    if(buffer == NULL)
    {
        return -1;
    }

#ifdef DEBUG
    printf("<= %s\n", buffer);
#endif

    code = ((buffer[ 0 ] - 0x30) * 10 + (buffer[ 1 ] - 0x30)) * 10 + (buffer[ 2 ] - 0x30);
    *matches = 0;

    if(code == 200)
    {
        buffer = tmp + 4;
    }
    else if(code == 211)
    {
        free(buffer);
        tmp = buffer = get_string_piece(socket, '\n');
    }
    else
    {
        return code;
    }


    /* get the alternavtives */
    *title_buffer = (char **) malloc(sizeof(char *) * 1000);
    *category_buffer = (char **) malloc(sizeof(char *) * 1000);
    *id_buffer = (char **) malloc(sizeof(char *) * 1000);

    do
    {
        if(strcmp(buffer, ".\r\n") == 0)
        {
            break;
        }

        /* if we get more than 1000 matches, the char*[] will be full,
        	and we will skip the remaining few million matches */
        if(*matches == 999)
        {
            free(tmp);
            continue;
        }

        i = strcspn(buffer, " ");
        (*category_buffer)[ *matches ] = (char *) malloc(i + 1);
        strncpy((*category_buffer)[ *matches ], buffer, i);
        (*category_buffer)[ *matches ][ i ] = 0;             /*terminate the string*/

        buffer += i + 1;          /* skip to the disk id */
        (*id_buffer)[ *matches ] = (char *) malloc(9);          /* the disk id is always
						        		                                                        																		 8 char long */
        strncpy((*id_buffer)[ *matches ], buffer, 8);
        (*id_buffer)[ *matches ][ 8 ] = 0;             /*terminate the string */
        buffer += 9;

        i = strlen(buffer) - 2;          /*strip the remaining '\r\n' from the
						        												 end of the line*/
        (*title_buffer)[ *matches ] = (char *) malloc(i + 1);
        strncpy((*title_buffer)[ *matches ], buffer, i);
        (*title_buffer)[ *matches ][ i ] = 0;             /*terminate the string */

        (*matches) ++;
        free(tmp);
    }
    while(code != 200 &&
            (tmp = buffer = get_string_piece(socket, '\n')) != NULL);

    return code;
}



int cddbp_read(FILE *socket, const char *category, const char *disk_id,
               char **result_buffer)
{
    char *buffer;
    int code;
    int count;
    char status_buf[ 36 ];

#ifdef DEBUG
    printf("=> cddb read %s %s\n", category, disk_id);
#endif
    fprintf(socket, "cddb read %s %s\n", category, disk_id);

    buffer = get_string_piece(socket, '\n');

    if(buffer == NULL)
    {
        return -1;
    }

#ifdef DEBUG
    printf("<= %s\n", buffer);
#endif

    code = ((buffer[ 0 ] - 0x30) * 10 + (buffer[ 1 ] - 0x30)) * 10 + (buffer[ 2 ] - 0x30);
    free(buffer);

    if(code > 210)
    {
        return code;
    }

    /* skip the first row, and copy the data that follows into the result buffer*/

    *result_buffer = (char *) malloc(1);

    strcpy(*result_buffer, "");
    count = 1;

    do
    {
        buffer = get_string_piece(socket, '\n');

        if(strncmp(buffer, "TTITLE", 6) == 0)
        {
            sprintf(status_buf, _("Reading Information about track %2d"), count);
            main_window_handler(MW_UPDATE_STATUSBAR, status_buf, NULL);

            while(gtk_events_pending())
            {
                gtk_main_iteration();
            }

            count++;
        }

#ifdef DEBUG
        printf("<= %s", buffer);
#endif
        string_append(result_buffer, buffer);
        free(buffer);
    }
    while(strstr(*result_buffer, "\r\n.\r\n") == NULL);

    main_window_handler(MW_UPDATE_STATUSBAR, _("Done..."), NULL);

    while(gtk_events_pending())
    {
        gtk_main_iteration();
    }

    return code;
}

int cddbp_stat(FILE *socket, char **result)
{
    int code;
    char *buffer;
#ifdef DEBUG
    printf("=> stat\n");
#endif
    fprintf(socket, "stat\n");

    buffer = get_string_piece(socket, '\n');

    if(buffer == NULL)
    {
        return -1;
    }

#ifdef DEBUG
    printf("<= %s\n", buffer);
#endif
    code = ((buffer[ 0 ] - 0x30) * 10 + (buffer[ 1 ] - 0x30)) * 10 + (buffer[ 2 ] - 0x30);
    free(buffer);

    if(code > 210)
    {
        return code;
    }

    do
    {
        buffer = get_string_piece(socket, '\n');
#ifdef DEBUG
        printf("<= %s", buffer);
#endif
        string_append(result, buffer);
        free(buffer);
    }
    while(strstr(*result, "\r\n.\r\n") == NULL);

    return code;
}

void cddbp_signoff(FILE *socket)
{
    char *buffer;
    fprintf(socket, "quit\n");
    buffer = get_string_piece(socket, '\n');
    free(buffer);
    fclose(socket);
#ifdef DEBUG
    printf("Signing off\n");
#endif
}


int http_query(const char *server, int port, const char *URL,
               const char *cd_id, int tracknum, long int offset[],
               int duration, int *matches,
               char ***category_buffer, char ***title_buffer,
               char ***id_buffer, const char *client, const char *version)
{
  char *buffer = new char[1024],		
    *tmp = new char[1024];
  
  int i, code;
  FILE *sock;

    sprintf(buffer, "GET /%s?cmd=cddb+query+%s+%d", URL, cd_id, tracknum);

    for(i = 0; i < tracknum; i++)
    {
        sprintf(tmp, "+%ld", offset[ i ]);
        strcat(buffer, tmp);
        strcpy(tmp, "");
    }

    sprintf(tmp, "+%d&hello=%s+%s+%s+%s&proto=1 HTTP/1.0\r\n\r\n", duration,
            "anonymous", "localhost", client, version);
    strcat(buffer, tmp);
    delete [] tmp;

#ifdef DEBUG
    printf("=> %s\n", buffer);
#endif

    sock = socket_init(server, port);

    if(!sock)
    {
		free(buffer);
        return 999;
    }

    fprintf(sock, "%s", buffer);
    delete [] buffer;

    buffer = get_ascii_file(sock);
#ifdef DEBUG
    printf("<= %s\n", buffer);
#endif

    /* strip the http header of the answer */
    tmp = strstr(buffer, "\r\n\r\n");

    if(tmp == NULL)      /* uhoh, no empty row anywhere.... */
    {
        free(buffer);
        return -1;
    }

    tmp += 4;

    tmp = strdup(tmp);
    free(buffer);

    buffer = tmp;
    *matches = 0;

    code = ((tmp[ 0 ] - 0x30) * 10 + (tmp[ 1 ] - 0x30)) * 10 + (tmp[ 2 ] - 0x30);

    if(code == 200)
    {
        buffer += 4;
    }
    else if(code == 211)
    {
        buffer = strchr(buffer, '\n');
    }
    else
    {
        free(tmp);
        return code;
    }

    *title_buffer = (char **) malloc(sizeof(char *) * 1000);
    *category_buffer = (char **) malloc(sizeof(char *) * 1000);
    *id_buffer = (char **) malloc(sizeof(char *) * 1000);

    do
    {
        if(strcmp(buffer, ".\r\n") == 0)
        {
            break;
        }

        /* if we get more than 1000 matches, the char*[] will be full,
        	and we will skip the remaining few million matches */
        if(*matches == 999)
        {
            continue;
        }

        i = strcspn(buffer, " ");

        if(buffer[ 0 ] == '\n')    		/* skip the \n only if it is there */
        {
            buffer++;
            i--;
        }

        (*category_buffer)[ *matches ] = (char *) malloc(i + 1);
        strncpy((*category_buffer)[ *matches ], buffer, i);
        (*category_buffer)[ *matches ][ i ] = 0;             /*terminate the string*/

        buffer += i + 1;          /* skip to the disk id */
        (*id_buffer)[ *matches ] = (char *) malloc(9);                /* the disk id is always 8 char long */
        strncpy((*id_buffer)[ *matches ], buffer, 8);
        (*id_buffer)[ *matches ][ 8 ] = 0;             /*terminate the string */
        buffer += 9;

        i = strcspn(buffer, "\r\n");
        (*title_buffer)[ *matches ] = (char *) malloc(i + 1);
        strncpy((*title_buffer)[ *matches ], buffer, i);
        (*title_buffer)[ *matches ][ i ] = 0;             /*terminate the string */

        (*matches) ++;
        buffer += i + 2;     /* skip the \r\n */
    }
    while((buffer = strchr(buffer, '\n')) != NULL);

#ifdef DEBUG
    printf("category: %s, title: %s", (*category_buffer)[ 0 ], (*title_buffer)[ 0 ]);
#endif

    free(tmp);
    return code;
}

int http_query_proxy(const char *server, int port, const char *proxy_server, int proxy_port, const char *URL,
                     const char *cd_id, int tracknum, long int offset[],
                     int duration, int *matches,
                     char ***category_buffer, char ***title_buffer,
                     char ***id_buffer, const char *client, const char *version)
{
    char *buffer = (char *) malloc(1024),
          *tmp = (char *) malloc(1024);
    int i, code;
    FILE *sock;

    sprintf(buffer, "GET http://%s:%i/%s?cmd=cddb+query+%s+%d", server, port, URL, cd_id, tracknum);

    for(i = 0; i < tracknum; i++)
    {
        sprintf(tmp, "+%ld", offset[ i ]);
        strcat(buffer, tmp);
        strcpy(tmp, "");
    }

    sprintf(tmp, "+%d&hello=%s+%s+%s+%s&proto=1 HTTP/1.0\r\n\r\n", duration,
            "anonymous", "localhost", client, version);
    strcat(buffer, tmp);
    free(tmp);

#ifdef DEBUG
    printf("=> %s\n", buffer);
#endif


    sock = socket_init(proxy_server, proxy_port);

    if(!sock)
    {
		free(buffer);
        return 999;
    }

    fprintf(sock, "%s", buffer);
    free(buffer);

    buffer = get_ascii_file(sock);
#ifdef DEBUG
    printf("<= %s\n", buffer);
#endif

    /* strip the http header of the answer */
    tmp = strstr(buffer, "\r\n\r\n");

    if(tmp == NULL)      /* uhoh, no empty row anywhere.... */
    {
        free(buffer);
        return - 1;
    }

    tmp += 4;
    tmp = strdup(tmp);
    free(buffer);
    buffer = tmp;
    *matches = 0;

    code = ((tmp[ 0 ] - 0x30) * 10 + (tmp[ 1 ] - 0x30)) * 10 + (tmp[ 2 ] - 0x30);

    if(code == 200)
    {
        buffer += 4;
    }
    else if(code == 211)
    {
        buffer = strchr(buffer, '\n');
    }
    else
    {
        free(tmp);
        return code;
    }

    *title_buffer = (char **) malloc(sizeof(char *) * 1000);
    *category_buffer = (char **) malloc(sizeof(char *) * 1000);
    *id_buffer = (char **) malloc(sizeof(char *) * 1000);

    do
    {
        if(strcmp(buffer, ".\r\n") == 0)
        {
            break;
        }

        /* if we get more than 1000 matches, the char*[] will be full,
        	and we will skip the remaining few million matches */
        if(*matches == 999)
        {
            continue;
        }

        i = strcspn(buffer, " ");

        if(buffer[ 0 ] == '\n')    		/* skip the \n only if it is there */
        {
            buffer++;
            i--;
        }

        (*category_buffer)[ *matches ] = (char *) malloc(i + 1);
        strncpy((*category_buffer)[ *matches ], buffer, i);
        (*category_buffer)[ *matches ][ i ] = 0;             /*terminate the string*/

        buffer += i + 1;          /* skip to the disk id */
        (*id_buffer)[ *matches ] = (char *) malloc(9);          /* the disk id is always
						        		                                                        																		 8 char long */
        strncpy((*id_buffer)[ *matches ], buffer, 8);
        (*id_buffer)[ *matches ][ 8 ] = 0;             /*terminate the string */
        buffer += 9;

        i = strcspn(buffer, "\r\n");
        (*title_buffer)[ *matches ] = (char *) malloc(i + 1);
        strncpy((*title_buffer)[ *matches ], buffer, i);
        (*title_buffer)[ *matches ][ i ] = 0;             /*terminate the string */

        (*matches) ++;
        buffer += i + 2;     /* skip the \r\n */
    }
    while((buffer = strchr(buffer, '\n')) != NULL);

#ifdef DEBUG
    printf("category: %s, title: %s", (*category_buffer)[ 0 ], (*title_buffer)[ 0 ]);
#endif

    free(tmp);
    return code;
}

int http_read(const char *server, int port, const char *URL,
              const char *category, const char *disk_id, char **result,
              const char *client, const char *version)
{
    int code;
    char *buffer, *tmp;
    FILE *sock;

#ifdef DEBUG
    printf("=> GET /%s?cmd=cddb+read+%s+%s&hello=%s+%s+%s+%s&proto=1 HTTP/1.0\r\n\r\n",
           URL, category, disk_id, "anonymouse", "localhost", client,
           version);
#endif

    sock = socket_init(server, port);

    if(!sock)
    {
        return 999;
    }

    fprintf(sock,
            "GET /%s?cmd=cddb+read+%s+%s&hello=%s+%s+%s+%s&proto=5 HTTP/1.0\r\n\r\n",
            URL, category, disk_id, "anonymous", "localhost", client,
            version);

    buffer = get_ascii_file(sock);
#ifdef DEBUG
    printf("<= %s\n", buffer);
#endif

    /* strip the http header of the answer */
    tmp = strstr(buffer, "\r\n\r\n");

    if(tmp == NULL)      /* uhoh, no empty row anywhere.... */
    {
        free(buffer);
        return - 1;
    }

    tmp += 4;
    tmp = strdup(tmp);
    free(buffer);
    buffer = tmp;

    code = ((buffer[ 0 ] - 0x30) * 10 + (buffer[ 1 ] - 0x30)) * 10 + (buffer[ 2 ] - 0x30);

    if(code > 210)
    {
        free(buffer);
        return code;
    }

    /* skip the first row, and copy the data that follows into the result buffer*/
    tmp = strchr(buffer, '\n') + 1;
    *result = strdup(tmp);
    free(buffer);

    return code;
}


int http_read_proxy(const char *server, int port, const char *proxy_server, int proxy_port, const char *URL,
                    const char *category, const char *disk_id, char **result,
                    const char *client, const char *version)
{
    int code;
    char *buffer, *tmp;
    FILE *sock;

#ifdef DEBUG
    printf("=> GET http://%s:%i/%s?cmd=cddb+read+%s+%s&hello=%s+%s+%s+%s&proto=1 HTTP/1.0\r\n\r\n",
           server, port, URL, category, disk_id, "anonymous", "localhost", client,
           version);
#endif

    sock = socket_init(proxy_server, proxy_port);

    if(!sock)
    {
        return 999;
    }

    fprintf(sock,
            "GET http://%s:%i/%s?cmd=cddb+read+%s+%s&hello=%s+%s+%s+%s&proto=5 HTTP/1.0\r\n\r\n",
            server, port, URL, category, disk_id, "anonymous", "localhost", client,
            version);

    buffer = get_ascii_file(sock);
#ifdef DEBUG
    printf("<= %s\n", buffer);
#endif

    /* strip the http header of the answer */
    tmp = strstr(buffer, "\r\n\r\n");

    if(tmp == NULL)      /* uhoh, no empty row anywhere.... */
    {
        free(buffer);
        return - 1;
    }

    tmp += 4;
    tmp = strdup(tmp);
    free(buffer);
    buffer = tmp;

    code = ((buffer[ 0 ] - 0x30) * 10 + (buffer[ 1 ] - 0x30)) * 10 + (buffer[ 2 ] - 0x30);

    if(code > 210)
    {
        free(buffer);
        return code;
    }

    /* skip the first row, and copy the data that follows into the result buffer*/
    tmp = strchr(buffer, '\n') + 1;
    *result = strdup(tmp);
    free(buffer);

    return code;
}


int http_stat(const char *server, int port, const char *URL, char **result,
              const char *client, const char *version)
{
    int code;
    char *buffer, *tmp;
    FILE *sock;

#ifdef DEBUG
    printf("=> GET /%s?cmd=stat&hello=%s+%s+%s+%s&proto=1 HTTP/1.0\r\n\r\n",
           URL, "anonymous", "localhost", client, version);
#endif

    sock = socket_init(server, port);

    if(!sock)
    {
        return 999;
    }

    fprintf(sock, "GET /%s?cmd=stat&hello=%s+%s+%s+%s&proto=1 HTTP/1.0\r\n\r\n",
            URL, "anonymous", "localhost", client, version);

    buffer = get_ascii_file(sock);
#ifdef DEBUG
    printf("<= %s\n", buffer);
#endif

    /* strip the http header of the answer */
    tmp = strstr(buffer, "\r\n\r\n");

    if(tmp == NULL)      /* uhoh, no empty row anywhere.... */
    {
        free(buffer);
        return - 1;
    }

    tmp += 4;
    tmp = strdup(tmp);
    free(buffer);
    buffer = tmp;

    code = ((buffer[ 0 ] - 0x30) * 10 + (buffer[ 1 ] - 0x30)) * 10 + (buffer[ 2 ] - 0x30);

    if(code > 210)
    {
        free(buffer);
        return code;
    }

    /* skip the first row, and copy the data that follows into the result buffer*/
    tmp = strchr(buffer, '\n') + 1;
    *result = strdup(tmp);
    free(buffer);

    return code;
}
