/* WIDE AREA INFORMATION SERVER SOFTWARE:
   No guarantees or restrictions.  See the readme file for the full standard
   disclaimer.

   Brewster@think.com
*/

/* This is a simple shell user interface for generating wprot packets.
 * -brewster 7/90
 *
 * Important functions:
 *   display_search_response
 *   main
 *
 */

/* to do:
 *  fix the number parser in view document number
 *  fix if <cr> put to view document number, same as q
 */

#include <ctype.h>
#include <string.h>
#include <ui.h>
#include <sockets.h>
#include <docid.h>

#define MAX_MESSAGE_LEN 100000
#define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
#define MAX_FILE_NAME_LEN 1000

#define WAISSEARCH_DATE "Fri Sep 13 1991"

char* log_file_name = NULL;
FILE* logfile = NULL;

/* modified from Jonny G's version in ui/question.c */
void showDiags(d)
diagnosticRecord **d;
{
  long i;

  for (i = 0; d[i] != NULL; i++) {
    if (d[i]->ADDINFO != NULL) {
      printf("Code: %s, %s\n", d[i]->DIAG, d[i] ->ADDINFO);
    }
  }
}

/* modified from tracy shen's version in wutil.c
 * displays either a text record of a set of headlines.
 */
void
display_search_response(response)
SearchResponseAPDU *response;

{
  WAISSearchResponse  *info;
  long continue_viewing;
  long i, k;

  printf("\n Search Response:\n");

  printf("  NumberOfRecordsReturned: %d\n", 
	 response->NumberOfRecordsReturned); 
  if ( response->DatabaseDiagnosticRecords != 0 ) {
    info = (WAISSearchResponse *)response->DatabaseDiagnosticRecords;
    i =0; 
    continue_viewing = 1; 

    if (info->Diagnostics != NULL)
      showDiags(info->Diagnostics);

    if ( info->DocHeaders != 0 ) {
      k =0;
      while ( (continue_viewing == 1) && info->DocHeaders[k] != 0 ) {
	i++;
	printf("  %2d: Score: %4ld, lines:%4ld '%s'\n", 
	       i, (info->DocHeaders[k]->Score),
	       info->DocHeaders[k]->Lines,
	       trim_junk(info->DocHeaders[k]->Headline));
	k++;
      }
    }
    if ( info->ShortHeaders != 0 ) {
      k =0;
      while ( (continue_viewing == 1) && info->ShortHeaders[k] != 0 ) {
	i++;
	printf("\n    ShortHeader record %2d, (can't display)", i);
      }
    }
    if ( info->LongHeaders != 0 ) {
      k =0;
      while ( (continue_viewing == 1) && (info->LongHeaders[k] != 0) ) {
	i++;
	printf("\n    Longheader record %2d, (cant display) ", i);
	/* dsply_long_hdr_record( info->LongHeaders[k++]); */
      }
    }
    if ( info->Text != 0 ) {
      k =0;
      while ( (continue_viewing == 1) && (info->Text[k] != 0) ) {
	i++;
	printf("\n    Text record %2d, ", i);
	display_text_record_completely( info->Text[k++], false);
      }
    }
    if ( info->Headlines != 0 ) {
      k =0;
      while ( (continue_viewing ==1) && (info->Headlines[k] != 0) ) {
	i++;
	printf("\n    headline record %2d, (cant display) ", i);
	/* dsply_headline_record( info->Headlines[k++]); */
      }
    }
    if ( info->Codes != 0 ) {
      k =0;
      while ( (continue_viewing ==1) && (info->Codes[k] != 0) ) {
	i++;
	printf("\n    code record %2d, (dont knowhow to display) ", i);
	/* dsply_code_record( info->Codes[k++]); */
      }
    }
  }				/* display user info */
}



#define MAX_KEYWORDS_LENGTH 1000
#define MAX_SERVER_LENGTH 1000
#define MAX_DATABASE_LENGTH 1000
#define MAX_SERVICE_LENGTH 1000
#define MAXDOCS 40

any*
copy_any(thing)
any *thing;
{
  int i;
  any* result;

  result = NULL;

  if(thing != NULL) {
    if((result = (any*)s_malloc(sizeof(any))) != NULL) {
      result->bytes = NULL;
      result->size = thing->size;
      if((result->bytes = s_malloc(thing->size)) != NULL) {
	for(i = 0; i < thing->size; i++)
	  result->bytes[i] = thing->bytes[i];
      }
    }
  }
  return result;
}

void
main(argc, argv)
int argc;
char *argv[];
{
  char* request_message = NULL; /* arbitrary message limit */
  char* response_message = NULL; /* arbitrary message limit */
  long request_buffer_length;	/* how of the request is left */
  SearchResponseAPDU  *query_response;
  SearchResponseAPDU  *retrieval_response;
  WAISSearchResponse  *query_info, *retrieval_info;
  char keywords[MAX_KEYWORDS_LENGTH + 1];
  char server_name[MAX_SERVER_LENGTH + 1];	
  char service[MAX_SERVICE_LENGTH + 1];
  char database[MAX_DATABASE_LENGTH + 1];
  char *next_argument, *command_name;
  long count;
  FILE *connection;

#ifdef THINK_C
  argc = ccommand(&argv);
#endif
  next_argument = next_arg(&argc, &argv);
  command_name = next_argument;

  if(0 == argc){		/* no args */
    printf("Usage: %s [-h host-machine] /* defaults to local machine */\n", 
	   command_name);
    printf("                  [-p service-or-port]  /* defaults to z39_50 */\n");
    printf("                  [-d database]  /* defaults to nil */\n");
    printf("                  [-v] /* print the version */\n");
    printf("                  word word...\n");
    exit(0);
  }
  
#ifdef THINK_C
  strncpy(server_name, "wais:System Folder:wais-index:index", MAX_SERVER_LENGTH);
#else
  server_name[0] = '\0';  /* null it out */
#endif				/* THINK_C */
  database[0] = '\0';  /* null it out */
  service[0] = '\0';  /* null it out */

  if(NULL == (next_argument = next_arg(&argc, &argv))){
    printf("No arguments specified\n");
    exit(0);
  }
  while('-' == next_argument[0]){
    /* then we have an argument to process */
    if(0 == strcmp("-debug", next_argument)){
      logfile = stderr;
    }
    else if(0 == strcmp("-h", next_argument)){
      if(NULL == (next_argument = next_arg(&argc, &argv))){
	printf("Expected a hostname\n");
	exit(0);
      }
      strncpy(server_name, next_argument, MAX_SERVER_LENGTH);
    }
    else if((0 == strcmp("-s", next_argument)) || /* -s is for backcompatibility */
	    (0 == strcmp("-p", next_argument))){
      if(NULL == (next_argument = next_arg(&argc, &argv))){
	printf("Expected a service name or portname\n");
	exit(0);
      }
      strncpy(service, next_argument, MAX_SERVICE_LENGTH);
    }	
    else if(0 == strcmp("-d", next_argument)){
      if(NULL == (next_argument = next_arg(&argc, &argv))){
	printf("Expected a database name\n");
	exit(0);
      }
      strncpy(database, next_argument, MAX_DATABASE_LENGTH);
    }
    else if(0 == strcmp("-v", next_argument)){
      printf("%s version: %s, %s\n",
	     command_name, VERSION, WAISSEARCH_DATE);
    }
    else{
      panic("Don't recognize the %s option", next_argument);
    }
    if(NULL == (next_argument = next_arg(&argc, &argv))){
      printf("No search words specified\n");
      exit(0);
    }
  }
  /* collect up the words for the query */
  strncpy(keywords, next_argument, MAX_KEYWORDS_LENGTH);
  while(NULL != (next_argument = next_arg(&argc, &argv))){
    strncat(keywords, " ", MAX_KEYWORDS_LENGTH);
    strncat(keywords, next_argument, MAX_KEYWORDS_LENGTH);
  }
    
  
  if (server_name[0] == 0)
    connection = NULL;

  else if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
   {
    fprintf (stderr, "Error openning connection to %s via service %s.\n",
	     server_name, service);
    exit(-1);
  }

  request_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  response_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));

  {
    char userInfo[500];
    char hostname[80];

    gethostname(hostname, 80);
#ifdef TELL_USER
    sprintf(userInfo, "waissearch %s, from host: %s, user: %s",
	    VERSION, hostname, getenv("USER"));
#else
    sprintf(userInfo, "waissearch %s, from host: %s", VERSION, hostname);
#endif

    init_connection(request_message, response_message,
		    MAX_MESSAGE_LEN,
		    connection,
		    userInfo);
  }

  while(1){		/* continue to search until the user gets tired */
    request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
    if(NULL ==
	generate_search_apdu(request_message + HEADER_LENGTH, 
			     &request_buffer_length, 
			     keywords, database, NULL, MAXDOCS))
      panic("request too large");
       

    if(0 ==
       interpret_message(request_message, 
			 MAX_MESSAGE_LEN - request_buffer_length, 
			 response_message,
			 MAX_MESSAGE_LEN,
			 connection,
			 false	/* true verbose */
			 )) { /* perhaps the server shut down on us, let's see: */
      if ( connection != NULL) {
	fclose(connection);
	if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
	  {
	    fprintf (stderr, "Error openning connection to %s via service %s.\n",
		     server_name, service);
	    exit(-1);
	  }
	if(0 ==
	   interpret_message(request_message, 
			     MAX_MESSAGE_LEN - request_buffer_length, 
			     response_message,
			     MAX_MESSAGE_LEN,
			     connection,
			     false /* true verbose */
			     ))
	  panic("really couldn't deliver message");
	}
      else
	panic("returned message too large");
    }

    readSearchResponseAPDU(&query_response, response_message + HEADER_LENGTH);
    display_search_response(query_response);
    query_info = (WAISSearchResponse *)query_response->DatabaseDiagnosticRecords;

    if ( query_response->DatabaseDiagnosticRecords != 0 &&
	query_info->DocHeaders !=0) {
      long document_number = -1;
      any* lastDocID;
      while(1){			/* keep viewing until user wants out */
	while(1){		/* keep asking until we have an answer */
	  char document_string[1000]; /* to hold the users response */
	  long count;

	  if(document_number>0)
	    lastDocID = query_info->DocHeaders[document_number-1]->DocumentID;
	  printf("\nView document number [type 0 or q to quit]: ");
	  fflush(stdout);
	  fgets(document_string, 1000, stdin);
	  /* trim \n from string */
	  if(strlen(document_string) > 0)
	    document_string[strlen(document_string) -1] = '\0';

	  if(document_string[0] == 'q'){
	    document_number = 0; /* signal to quit */
	    break;
	  }
	  if(document_string[0] == 'n'){
	    document_number = -1; /* signal to get next document */
	    break;
	  }
	  if(document_string[0] == 'p'){
	    document_number = -2; /* signal to get previous document */
	    break;
	  }
	  /* check for a number */
	  for(count = 0; count < strlen(document_string); count++){
	    if(!isdigit(document_string[count])){
	      document_number = -1; /* ask again */
	      break;		/* break out of for loop */
	    }
	  }
	  if (count == strlen(document_string)){
	    /* it is a legal number */
	    document_number = atol(document_string);
	  }
	  if(document_number >= 0 &&
	     document_number <= query_response->NumberOfRecordsReturned){
	    break;		/* correct entry */
	  }
	  printf("\nEntry must be a number between 0 and %ld [type 0 or q to quit] you entered \"%s\"\n", query_response->NumberOfRecordsReturned, document_string);
	  
	}
	if(document_number == 0){
	  break;		/* leave the viewing loop */
	}
	if(document_number < 0) {
	  char *type;
	  DocObj *Doc[2];
	  if(document_number == -1)
	    type = "WAIS_NEXT";
	  else
	    type = "WAIS_PREV";
	  request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
	  {
	    DocID doc;
	    any* docID;

	    Doc[0] =
	      makeDocObjUsingWholeDocument(lastDocID, type);

	    Doc[1] = NULL;
	  }
	  if(0 ==
	     generate_search_apdu(request_message + HEADER_LENGTH, 
				  &request_buffer_length, 
				  "foo", database, Doc, 1)) {
	    panic("request too long");
	  }
	  if(0 ==
	     interpret_message(request_message, 
			       MAX_MESSAGE_LEN - request_buffer_length, 
			       response_message,
			       MAX_MESSAGE_LEN,
			       connection,
			       false /* true verbose */	
			       )) { /* perhaps the server shut down on us, let's see: */
	    if ( connection != NULL) {
	      fclose(connection);
	      if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
		{
		  fprintf (stderr, "Error openning connection to %s via service %s.\n",
			   server_name, service);
		  exit(-1);
		}
	      if(0 ==
		 interpret_message(request_message, 
				   MAX_MESSAGE_LEN - request_buffer_length, 
				   response_message,
				   MAX_MESSAGE_LEN,
				   connection,
				   false /* true verbose */
				   ))
		panic("really couldn't deliver message");
	    }
	    else
	      panic("returned message too large");
	  }

	    readSearchResponseAPDU(&retrieval_response, 
				   response_message + HEADER_LENGTH);

	    retrieval_info = (WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords;

	    if ( retrieval_info != NULL &&
		retrieval_info->DocHeaders != NULL) {
	      char *type;
	      long size;

	    lastDocID = copy_any(retrieval_info->DocHeaders[0]->DocumentID);
	    if(retrieval_info->DocHeaders[0]->Types == NULL)
	      type = s_strdup("TEXT");
	    else
	      type = s_strdup(retrieval_info->DocHeaders[0]->Types[0]);
	    printf("Headline: %s\n", 
		   retrieval_info->DocHeaders[0]->Headline);
	    size = retrieval_info->DocHeaders[0]->DocumentLength;
	    for(count = 0; 
		count * CHARS_PER_PAGE < size;
		count++){
	      request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
	      if(0 ==
		 generate_retrieval_apdu(request_message + HEADER_LENGTH,
					 &request_buffer_length, 
					 lastDocID,
					 CT_byte,
					 count * CHARS_PER_PAGE,
					 MIN((count + 1) * CHARS_PER_PAGE, size),
					 type,
					 database
					 ))
		panic("request too long");
	     
	      if(0 ==
		 interpret_message(request_message, 
				   MAX_MESSAGE_LEN - request_buffer_length, 
				   response_message,
				   MAX_MESSAGE_LEN,
				   connection,
				   false /* true verbose */	
				   )) { /* perhaps the server shut down on us, let's see: */
		if ( connection != NULL) {
		  fclose(connection);
		  if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
		    {
		      fprintf (stderr, "Error openning connection to %s via service %s.\n",
			       server_name, service);
		      exit(-1);
		    }
		  if(0 ==
		     interpret_message(request_message, 
				       MAX_MESSAGE_LEN - request_buffer_length, 
				       response_message,
				       MAX_MESSAGE_LEN,
				       connection,
				       false /* true verbose */
				       ))
		    panic("really couldn't deliver message");
		}
		else
		  panic("returned message too large");
	      }

	      readSearchResponseAPDU(&retrieval_response, 
				     response_message + HEADER_LENGTH);

	      /* display_search_response(retrieval_response); the general thing */
	      if(NULL == ((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text){
		display_search_response(retrieval_response);
		panic("No text was returned");
	      }
	      display_text_record_completely
		(((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text[0], false);
	    }
	  }
	  freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords); 
	  freeSearchResponseAPDU( retrieval_response);
	}
	else {
	  printf("Headline: %s\n", 
		 query_info->DocHeaders[document_number - 1]->Headline);
	  /* we must retrieve the document in parts since it might be very long*/
	  for(count = 0; 
	      count * CHARS_PER_PAGE <
	      query_info->DocHeaders[document_number - 1]->DocumentLength;
	      count++){
	    char *type;
	    if(query_info->DocHeaders[document_number - 1]->Types == NULL)
	      type = s_strdup("TEXT");
	    else
	      type = s_strdup(query_info->DocHeaders[document_number - 1]->Types[0]);
	    request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
	    if(0 ==
	       generate_retrieval_apdu(request_message + HEADER_LENGTH,
				       &request_buffer_length, 
				       query_info->DocHeaders[document_number - 1]->DocumentID, 
				       CT_byte,
				       count * CHARS_PER_PAGE,
				       MIN((count + 1) * CHARS_PER_PAGE,
					   query_info->DocHeaders[document_number - 1]->DocumentLength),
				       type,
				       database
				       ))
	      panic("request too long");
	     
	    if(0 ==
	       interpret_message(request_message, 
				 MAX_MESSAGE_LEN - request_buffer_length, 
				 response_message,
				 MAX_MESSAGE_LEN,
				 connection,
				 false /* true verbose */	
				 )) { /* perhaps the server shut down on us, let's see: */
	      if ( connection != NULL) {
		fclose(connection);
		if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
		  {
		    fprintf (stderr, "Error openning connection to %s via service %s.\n",
			     server_name, service);
		    exit(-1);
		  }
		if(0 ==
		   interpret_message(request_message, 
				     MAX_MESSAGE_LEN - request_buffer_length, 
				     response_message,
				     MAX_MESSAGE_LEN,
				     connection,
				     false /* true verbose */
				     ))
		  panic("really couldn't deliver message");
	      }
	      else
		panic("returned message too large");
	    }

	    readSearchResponseAPDU(&retrieval_response, 
				   response_message + HEADER_LENGTH);

	    /* display_search_response(retrieval_response); the general thing */
	    if(NULL == ((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text){
	      display_search_response(retrieval_response);
	      panic("No text was returned");
	    }
	    display_text_record_completely
	      (((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text[0], false);
	  }
	  freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords); 
	  freeSearchResponseAPDU( retrieval_response);
	}
      }
    }

    freeWAISSearchResponse(query_response->DatabaseDiagnosticRecords);         
    freeSearchResponseAPDU( query_response);
    printf("Search for new words [type q to quit]: ");
    fflush(stdout);
    gets(keywords);
    if(strlen(keywords) == 1 && keywords[0] == 'q'){
      close_connection(connection);
      break;			/* leave the asking loop */
    }
  }

  s_free(request_message);
  s_free(response_message);

  exit(0);
}



