/*******************************************************************************
 * // Begin statement                                                          *
 *                                                                             *
 * Permission to use this software is granted provided that this statement     *
 * is retained.                                                                *
 *                                                                             *
 * This software is for NON-COMMERCIAL use only!                               *
 *                                                                             *
 * If you would like to use any part of my software in a commercial or public  *
 * environment/product/service, let me know (askitisn@gmail.com) before        *
 * you use it (this statement will also need to be retained along with other   *
 * details), so I can grant you permission.                                    *
 *                                                                             *
 * Please DO NOT distribute my software (in any manner), in part or in whole.  *
 * Thank you.                                                                  *
 *                                                                             *
 * Developer: Dr. Nikolas Askitis                                              *
 * Website:   http://www.naskitis.com                                          *
 * Email:     askitisn@gmail.com                                               *
 * Please show your support by visiting:      www.naskitis.com                 *
 *                                                                             *
 * Copyright @ 2010.  All rights reserved.                                     *
 * This program is distributed without any warranty; without even the          *
 * implied warranty of merchantability or fitness for a particular purpose.    *
 *                                                                             *
 *                                                                             *
 * Compiler version used: gcc (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5            *
 * O/S used: Linux ubuntu 2.6.35-22-generic #33-Ubuntu SMP Sun Sep 19 20:32:27 *
 * UTC 2010 x86_64 GNU/Linux                                                   *
 *                                                                             *
 * Developed and implemented by Dr. Nikolas Askitis, April 2004-2009 for       *
 * Linux-based 64-bit platforms.                                               *
 *                                                                             *
 * // End statement                                                            *
 ******************************************************************************/

#include "include/common.h"

/* the following code deals with the user interface */
static int total_searched=0;
static int total_inserted=0;
static int inserted=0;
static int found=0;

/* display an error message and exit the program */
void fatal(char *str) { puts(str); exit(1); }

/* copy a block of memory, a word at a time */
void node_cpy(uint32_t *dest, uint32_t *src, uint32_t bytes)
{
  bytes=bytes>>2;
  while(bytes != 0)
  {
    *dest++=*src++;
    bytes--;
  }
}

/* string compare routine with string lengths provided */
int32_t sncmp(const char  *s1, const char  *s2, uint64_t s1_len, uint64_t s2_len)
{
  while ( *s1 == *s2 )
  {
    *s1++;
    *s2++;
    --s1_len;
    --s2_len;

    if ( s1_len == 0 && s2_len ==0)  return 0;
    if ( s1_len == 0 ) return -1;
    if ( s2_len == 0 ) return 1;
  }
  return ( *s1 - *s2);
}

/*
 * scan an array of characters and replace '\n' characters
 * with '\0'
 */
void set_terminator(char *buffer, int length)
{
  register int32_t i=0;
  for(; i<length; ++i)  
  {
    if( *(buffer+i) == '\n' )   
    {
      *(buffer+i) = '\0';
    }
  }
}

/* string length routine */
int32_t slen(char *word)
{
  char *x=word;
  for(; *x != '\0'; ++x);
  return x-word;
}

void reset_counters()
{
  total_searched=total_inserted=inserted=found=0;
}

int32_t get_inserted()
{
  return inserted;
}

int32_t get_found()
{
  return found;
}

/* access the data structure to insert the strings found in the 
 * filename that is provided as a parameter. The file supplied must
 * be smaller than 2GB in size, otherwise, the code below has to be
 * modified to support large files, i.e., open64(), lseek64().
 * This should not be required, however, since the caller to this
 * function should be designed to handle multiple files, to allow you 
 * to break a large file into smaller pieces.  
 */
double perform_insertion(char *to_insert)
{ 
   int32_t  input_file=0;
   int32_t  return_value=0;
   uint32_t input_file_size=0;
   uint32_t read_in_so_far=0;

   char *buffer=0;
   char *buffer_start=0;
   
   timer start, stop;
   double insert_real_time=0.0;
   
   /* open the file for reading */
   if( (input_file=(int32_t) open(to_insert, O_RDONLY))<=0) 
     fatal(BAD_INPUT);  
     
   /* get the size of the file in bytes */
   input_file_size=lseek(input_file, 0, SEEK_END);
     
   /* allocate a buffer in memory to store the file */
   if( (buffer = (char *)calloc(1, input_file_size+1 )) == NULL) 
     fatal(MEMORY_EXHAUSTED);
     
   /* keep a pointer to the start of the buffer */
   buffer_start=buffer;
   
   /* read the file into memory and close the file pointer */
   lseek(input_file, 0, SEEK_SET);

   /* attempt to read the entire file into memory */
   while(read_in_so_far < input_file_size)
   {
     return_value=read(input_file, buffer, input_file_size);
     assert(return_value>=0);
     read_in_so_far+=return_value;
   }
   close(input_file);
   
   /* make sure that all strings are null terminated */
   set_terminator(buffer, input_file_size);
   
   /* start the timer for insertion */  
   gettimeofday(&start, NULL);

   /* main insertion loop */
   time_loop_insert: 

   /* insert the first null-terminated string in the buffer */
   if(insert(buffer))
   {
     inserted++;
   } 
   total_inserted++;

   /* point to the next string in the buffer */
   for(; *buffer != '\0'; buffer++);
   buffer++;

   /* if the buffer pointer has been incremented to beyond the size of the file,
    * then all strings have been processed, and the insertion is complete. 
    */   
   if(buffer - buffer_start >= input_file_size) goto insertion_complete;
   goto time_loop_insert;

   insertion_complete:

   /* stop the insertion timer */
   gettimeofday(&stop, NULL);

   /* do the math to compute the time required for insertion */   
   insert_real_time = 1000.0 * ( stop.tv_sec - start.tv_sec ) + 0.001  
   * (stop.tv_usec - start.tv_usec );
   insert_real_time = insert_real_time/1000.0;

   /* free the temp buffer used to store the file in memory */
   free(buffer_start);
   
   /* return the elapsed insertion time */
   return insert_real_time;
}


