
/*
 *  Name:           getDeleteCommand
 *  Input:          FILE pointer
 *  Output:         index key
 *                  list of non-key data attributes
 *  Return:         GET_DELETE_SUCCESS, or
 *                  GET_DELETE_IO_ERROR,
 *                  GET_DELETE_EARLY_EOI,
 *                  GET_DELETE_INVALID_CODE_ERROR,
 *                  GET_DELETE_ALLOCATION_ERROR
 *  Description:    The routine reads a Delete command from input stream via 
 *                  FILE pointer.  Assumes that the current stream pointer 
 *                  position is correct, and returns the file pointer open and 
 *                  the current position immediately after the command just 
 *                  read.  The file pointer is expected to be at the beginning 
 *                  of the Delete command immediately after the command code. 
 *                  The Delete command consists of a list of attribute code and 
 *                  value pairs.  An error occurs if any attribute code does 
 *                  not have an accompanying value, an attribute code is 
 *                  out-of-range as specified in the DIS Benchmark Suite: Data 
 *                  Management, or an I/O error occurs reading the values from 
 *                  the stream.  For any error during the read, the routine 
 *                  will leave the current values of the command attribute list 
 *                  intact and clear the FILE pointer to the end of the current 
 *                  line. 
 *
 *                  A Delete command is made up of a list of attribute code and
 *                  value pairs.  The total number of pairs can range from zero 
 *                  to the MAX_ATTRIBUTE_CODE.  Each command is carriage return 
 *                  delimited, i.e., one line per command.  So, to read a Delete
 *                  command, read until the end-of-line indicator is 
 *                  encountered.
 *
 *                  It is possible to have a Delete command return an empty 
 *                  attribute list without producing an error.  Since missing 
 *                  attributes are defaulted to "wild-card" values, this type 
 *                  of delete would logically remove the entire database.  This 
 *                  type of delete is a valid Delete command as defined by the 
 *                  DIS Benchmark Suite: Data Management document.
 *  Calls:          errorMessage()
 *                  getInt()
 *                  getKeyAttribute()
 *                  getNonKeyAttribute()
 *      System:     
 *  Author:         M.L.Rivas
 *
 *  Revision History:
 *
 *  Date    Name            Revision
 *  ------- --------------- ------------------------------
 *  24May99 Matthew Rivas   Created
 *
 *              Copyright 1999, Atlantic Aerospace Electronics Corp.
 */

#include <assert.h>             /* for assert()                               */
#include <stdlib.h>             /* for NULL                                   */
#include <stdio.h>              /* for FILE definition                        */
#include "dataManagement.h"     /* for primitive data types                   */
#include "dataObject.h"         /* for DataAttribute definition               */
#include "indexKey.h"           /* for IndexKey definition                    */
#include "errorMessage.h"       /* for errorMessage() definition              */
#include "getDeleteCommand.h"   /* for getDeleteCommand() and return codes    */
#include "getInt.h"             /* for getInt() and return code definitions   */
#include "getKeyAttribute.h"    /* for prototype and return code definitions  */
#include "getNonKeyAttribute.h" /* for prototype and return code definitions  */

Int getDeleteCommand( FILE           *file,           /* file for reading     */
                      IndexKey       *searchKey,      /* index key            */
                      DataAttribute  **searchNonKey ) /* list of attributes   */
{   /*  begin getDeleteCommand()    */
    Int attributeCode; /* attribute code read from file     */
    Int returnCode;    /* return code from various routines */
    
    static Char name[] = "getDeleteCommand";

    assert( file );
    assert( searchKey );
    assert( MIN_ATTRIBUTE_CODE < NUM_OF_KEY_ATTRIBUTES );
    assert( MIN_ATTRIBUTE_CODE < MAX_ATTRIBUTE_CODE );
    assert( MAX_ATTRIBUTE_CODE < NUM_OF_LARGE_ATTRIBUTES );
    assert( NUM_OF_KEY_ATTRIBUTES < NUM_OF_SMALL_ATTRIBUTES );
    assert( NUM_OF_KEY_ATTRIBUTES < NUM_OF_MEDIUM_ATTRIBUTES );
    assert( NUM_OF_KEY_ATTRIBUTES < NUM_OF_LARGE_ATTRIBUTES );

    /*
     *  Set the values for the index key and non-key list to wild-card values.  
     *  The key values are float, and the wild-card is a hyper-cube of maximum 
     *  volume.  The non-key values are char, and the wild-card values are NULL 
     *  with an empty list.
     */
    searchKey->lower.T = MINIMUM_VALUE_OF_FLOAT;
    searchKey->lower.X = MINIMUM_VALUE_OF_FLOAT;
    searchKey->lower.Y = MINIMUM_VALUE_OF_FLOAT;
    searchKey->lower.Z = MINIMUM_VALUE_OF_FLOAT;
    searchKey->upper.T = MAXIMUM_VALUE_OF_FLOAT;
    searchKey->upper.X = MAXIMUM_VALUE_OF_FLOAT;
    searchKey->upper.Y = MAXIMUM_VALUE_OF_FLOAT;
    searchKey->upper.Z = MAXIMUM_VALUE_OF_FLOAT;
    
    *searchNonKey = NULL;

    /*
     *  A Delete command is made up of a list of attribute code and value pairs.
     *  The total number of pairs can range from zero to MAX_ATTRIBUTE_CODE.  
     *  Each command is on a separate line, i.e., an end-of-line indicator is 
     *  used to delimit commands.  So, to read the Delete command, read 
     *  code/value pairs until an end-of-line indicator.  
     */
    returnCode = GET_INT_SUCCESS;
    while ( returnCode != GET_INT_EOI ) {
        /*
         *  Read the attribute code first and check return code.  If a 
         *  successful read, check range of code for error.  If code is in 
         *  range, check for key or non-key attribute.  For key and non-key 
         *  attributes, read in appropriate values.
         */
        returnCode = getInt( file, &attributeCode );
        if ( returnCode == GET_INT_SUCCESS ) {
            if ( attributeCode < MIN_ATTRIBUTE_CODE || /* check code range */
                 attributeCode > MAX_ATTRIBUTE_CODE ) {
                errorMessage( "code out-of-range", REPLACE );
                errorMessage( name, PREPEND );
                return ( GET_DELETE_INVALID_CODE_ERROR );
            }   /*  end of check for invalid code   */
            else if ( attributeCode < NUM_OF_KEY_ATTRIBUTES ) {
                Float   value;

                returnCode = getKeyAttribute( file, &value );
                if ( returnCode == GET_KEY_ATTRIBUTE_SUCCESS ) {
                    if ( attributeCode == LOWER_POINT_T ) {
                        searchKey->lower.T = value;
                    }   /*  end of LOWER_POINT_T    */
                    else if ( attributeCode == LOWER_POINT_X ) {
                        searchKey->lower.X = value;
                    }   /*  end of LOWER_POINT_X    */
                    else if ( attributeCode == LOWER_POINT_Y ) {
                        searchKey->lower.Y = value;
                    }   /*  end of LOWER_POINT_Y    */
                    else if ( attributeCode == LOWER_POINT_Z ) {
                        searchKey->lower.Z = value;
                    }   /*  end of LOWER_POINT_Z    */
                    else if ( attributeCode == UPPER_POINT_T ) {
                        searchKey->upper.T = value;
                    }   /*  end of UPPER_POINT_T    */
                    else if ( attributeCode == UPPER_POINT_X ) {
                        searchKey->upper.X = value;
                    }   /*  end of UPPER_POINT_X    */
                    else if ( attributeCode == UPPER_POINT_Y ) {
                        searchKey->upper.Y = value;
                    }   /*  end of UPPER_POINT_Y    */
                    else if ( attributeCode == UPPER_POINT_Z ) {
                        searchKey->upper.Z = value;
                    }   /*  end of UPPER_POINT_Z    */
                }   /*  end of GET_KEY_ATTRIBUTE_SUCCESS */
                else if ( returnCode == GET_KEY_ATTRIBUTE_EOI ) {
                    errorMessage( "improper format - early EOI", REPLACE );
                    errorMessage( name, PREPEND );
                    return ( GET_DELETE_EARLY_EOI );
                }   /*  end returnCode == GET_KEY_ATTRIBUTE_GET_FLOAT_FAILURE */
                else if ( returnCode == GET_KEY_ATTRIBUTE_GET_FLOAT_FAILURE ) {
                    errorMessage( "low-level I/O error", REPLACE );
                    errorMessage( name, PREPEND );
                    return ( GET_DELETE_IO_ERROR );
                }   /*  end returnCode == GET_KEY_ATTRIBUTE_GET_FLOAT_FAILURE */
            }   /*  end of key attribute        */
            else {
                Char    *value;
                                
                returnCode = getNonKeyAttribute( file, &value );
                if ( returnCode == GET_NON_KEY_ATTRIBUTE_SUCCESS ) {
                    DataAttribute *newAttribute;
                    
                    /*
                     *  Allocate new DataAttribute, store values of attribute 
                     *  code and attribute string, and add new DataAttribute to 
                     *  output list.
                     */
                    newAttribute =
                        (DataAttribute *)malloc( sizeof( DataAttribute ) );
                    if ( newAttribute == NULL ) {
                        errorMessage( "allocation failure", REPLACE );
                        errorMessage( name, PREPEND );
                        return ( GET_DELETE_ALLOCATION_ERROR );
                    }   /*  end of if ( attribute == NULL ) */

                    newAttribute->code                   = attributeCode;
                    newAttribute->attribute.value.nonKey = value;
                    
                    newAttribute->next = *searchNonKey;
                    *searchNonKey      = newAttribute;
                }
                else if ( returnCode == GET_NON_KEY_ATTRIBUTE_EOI ){
                    errorMessage( "improper format - early EOI", REPLACE );
                    errorMessage( name, PREPEND );
                    return ( GET_DELETE_EARLY_EOI );
                }   /*  end of if returnCode == GET_NON_KEY_ATTRIBUTE_EOI */
                else if ( returnCode==GET_NON_KEY_ATTRIBUTE_ALLOCATION_FAILURE){
                    errorMessage( "allocation of non-key attribute", REPLACE );
                    errorMessage( name, PREPEND );
                    return ( GET_DELETE_ALLOCATION_ERROR );
                }   /*  end of if ( returnCode == ALLOCATION_FAILURE )  */
            }   /*  end of non-key attribute    */
        }   /*  end of if ( returnCode == GET_INT_SUCCESS ) */
        else if ( returnCode == GET_INT_EOI ) {
            /*
             *  empty
             */
        }   /*  end of if ( returnCode == GET_INT_EOI ) */
        else if ( returnCode == GET_INT_RANGE_EXCEEDED ) {
            return ( GET_DELETE_INVALID_CODE_ERROR );
        }   /*  end of if ( error == GET_INT_RANGE_EXCEEDED )  */
        else if ( returnCode == GET_INT_BAD_CONVERSION ) {
            return ( GET_DELETE_INVALID_CODE_ERROR );
        }   /*  end of if ( error == GET_INT_BAD_CONVERSION )  */
    }

    return ( GET_DELETE_SUCCESS );
}   /*  end of getDeleteCommand()   */
