#include "dbinc.h"
/*****************************************************************************
*                                                                            *
*      COMMON OCEANOGRAPHIC DATA ACCESS SYSTEM (CODAS)                       *
*                                                                            *
*      WRITTEN BY:  RAMON CABRERA, ERIC FIRING, and JULIE RANADA             *
*                   JOINT INSTITUTE FOR MARINE AND ATMOSPHERIC RESEARCH      *
*                   1000 POPE ROAD  MSB 404                                  *
*                   HONOLULU, HI 96822                                       *
*                                                                            *
*      VERSION:     3.00                                                     *
*                                                                            *
*      DATE:        APRIL 1989                                               *
*                                                                            *
*****************************************************************************/
/*

       FILE:  dbput_f.c

              SYSTEM FUNCTIONS FOR UPDATING SCALED DATA IN A DATABASE

*/
/*-----------------------------------------------------------------------------

   FUNCTION: DBPUT_F

      It automatically unscales and converts data in the user buffer from
      floating point to the specified data type, and writes the converted
      data to the database.  It can only store as much new data in the
      database as the space reserved for when the database was first created.

   PARAMETERS:

      type = pointer to data structure type to which floating point data
             are to be converted

      data  = address of user buffer

      user_nv = pointer to number of values in user buffer

      nbad = pointer to number of values set to BAD because of rescaling/
             conversion to a value outside range

      ierr = pointer to error code

   RETURNS: VOID

*/
#if PROTOTYPE_ALLOWED
void DBPUT_F(int *type, FLOAT data[], unsigned int *user_nv, unsigned int *nbad, int *ierr)
#else
void DBPUT_F(type, data, user_nv, nbad, ierr)
int *type, *ierr;
FLOAT data[];
unsigned int *user_nv, *nbad;
#endif
{
   if (*user_nv == 0) {*ierr = INVALID_BUFFER_SIZE; return;}
/*
  ---> PROFILE DATA (types 0 - 99)
*/
   if ((*type >= 0) & (*type < (int)db->block_hdr.data_list_nentries))
   {
      if ((*ierr = dbget_flags()) != 0) return;
      if (!db->profile_is_open) {*ierr = NO_PROFILE_IS_OPEN; *user_nv = 0; return;}
      if (db->data_list[*type].access_type == UNUSED) {*ierr = INVALID_TYPE_REQUEST; *user_nv = 0; return;}
      if (putf_profile_data(type, data, user_nv, nbad, ierr)) goto error_found;
   }
   else
      *ierr = INVALID_TYPE_REQUEST;  /* use DBPUT for types 100 - 300 */
   return;

   error_found:
      report_db_error("DBPUT_F");
      *ierr = db->error_code * 1000 - db->error_data;
}

/*----------------------------------------------------------------------------

   FUNCTION:  putf_profile_data

      It automatically rescales/converts user-defined floating-point data
      to the data types standardly used in the database, and then writes
      these to the database as an update.

   PARAMETERS:

      type = pointer to data type

      data = address of user buffer containing floating-point data

      user_nv = pointer to number of values in user buffer

      nbad = pointer to number of bad values that occurred during
             rescaling/conversion to out-of-range values

      ierr = pointer to error code

   RETURNS: 0 or DATABASE ERROR

*/
#if PROTOTYPE_ALLOWED
int putf_profile_data(int *type, FLOAT data[], unsigned int *user_nv, unsigned int *nbad, int *ierr)
#else
int putf_profile_data(type, data, user_nv, nbad, ierr)
int *type, *ierr;
unsigned int *user_nv, *nbad;
FLOAT data[];
#endif
{
   unsigned int nb, db_nv, i;
   long ofs;
   char *conv_data;
   FLOAT *copy_data;

   get_access_param(type, &nb, &ofs);
   if (nb)
   {
      if ((conv_data = malloc(nb)) == NULL)
      {
         db->error_data = PROFILE_DATA;
         db->error_code = INSUFFICIENT_MEMORY;
         goto error_found;
      }
      db_nv = nb / VALUE_SIZE[db->data_list[*type].value_type];
      if (*user_nv < db_nv) /* need to BAD-out the excess space in the database */
      {
         if ((copy_data = (FLOAT *) calloc(db_nv, sizeof(FLOAT))) == NULL)
         {
            db->error_data = PROFILE_DATA;
            db->error_code = INSUFFICIENT_MEMORY;
            goto error_found;
         }
         for (i = 0; i < *user_nv; i++)
            copy_data[i] = data[i];    /* copy user data to buffer */
         for (i = *user_nv; i < db_nv; i++)
            copy_data[i] = BADFLOAT;   /* BAD-out remainder of buffer */
         *ierr = (*scale[db->data_list[*type].value_type])
            (conv_data, copy_data, &(db->data_list[*type].scale),
            &(db->data_list[*type].offset), &db_nv, nbad);
         *nbad -= (db_nv - *user_nv); /* subtract out the BAD padding */
         free(copy_data);
      }
      else
         *ierr = (*scale[db->data_list[*type].value_type])
            (conv_data, data, &(db->data_list[*type].scale),
            &(db->data_list[*type].offset), &db_nv, nbad);
      if ( (!(*ierr)) && nb > 0 )
         if ((db->error_code = write_data(db->fpblkdata, conv_data, ofs, nb)) != 0)
         {
            free(conv_data);
            db->error_data = PROFILE_DATA;
            goto error_found;
         }
      if (*user_nv > db_nv)
         *ierr = INSUFFICIENT_SPACE; /* only first <db_nv> values were stored */
      free(conv_data);
   }
   return(0);

   error_found:
      report_db_error("putf_profile_data");
      return (db->error_code);
}

