/*
 *  misc.c:             Some useful functions, that don't fit in one of
 *                      the other files and that are needed by at least
 *                      two modules.
 *
 *  Written by:         Stefan Frank
 *                      Ullrich Hafner
 *
 *  This file is part of FIASCO (Fractal Image And Sequence COdec)
 *  Copyright (C) 1994-2000 Ullrich Hafner
 */

/*
 *  $Date: 2000/06/14 20:49:37 $
 *  $Author: hafner $
 *  $Revision: 5.1 $
 *  $State: Exp $
 */

#include "config.h"

#include <math.h>
#include <ctype.h>

#ifdef TIME_WITH_SYS_TIME
#       include <sys/time.h>
#       include <time.h>
#else  /* not TIME_WITH_SYS_TIME */
#       if HAVE_SYS_TIME_H
#               include <sys/time.h>
#       else /* not HAVE_SYS_TIME_H */
#               include <time.h>
#       endif /* not HAVE_SYS_TIME_H */
#endif /* not TIME_WITH_SYS_TIME */

#include <stdlib.h>
#include <string.h>

#include "pm_c_util.h"

#include "types.h"
#include "macros.h"
#include "error.h"

#include "bit-io.h"
#include "misc.h"

/*****************************************************************************

                                prototypes

*****************************************************************************/

static void
remove_comments (FILE *file);

/*****************************************************************************

                                public code

*****************************************************************************/

void *
Calloc (size_t n, size_t size)
/*
 *  Allocate memory like calloc ().
 *
 *  Return value: Pointer to the new block of memory on success,
 *                otherwise the program is terminated.
 */
{
   void *ptr;                           /* pointer to the new memory block */

   if (n <= 0 || size <= 0)
      error ("Can't allocate memory for %d items of size %d",
             (int) n, (int) size);

   ptr = calloc (n, size);
   if (!ptr)
      error ("Out of memory!");

   return ptr;
}

void
Free (void *memory)
/*
 *  Free memory given by the pointer 'memory'
 *
 *  No return value.
 */
{
   if (memory != NULL)
      free (memory);
   else
      warning ("Can't free memory block <NULL>.");
}

unsigned
prg_timer (clock_t *last_timer, enum action_e action)
/*
 *  If 'action' == START then store current value of system timer.
 *  If 'action' == STOP  then compute number of elapsed micro seconds since
 *                       the last time 'prg_timer' was called
 *                       with 'action' == START.
 *
 *  Return value:
 *      Number of elapsed micro seconds if 'action' == STOP
 *      0                               if 'action' == START
 *
 *  Side effects:
 *      last_timer is set to current timer if action == START
 */
{
   assert (last_timer);

   if (action == START)
   {
      *last_timer = clock ();
      return 0;
   }
   else
      return (clock () - *last_timer) / (CLOCKS_PER_SEC / 1000.0);
}

real_t
read_real (FILE *infile)
/*
 *  Read one real value from the given input stream 'infile'.
 *
 *  Return value:
 *      real value on success
 */
{
   float input;

   assert (infile);

   remove_comments (infile);
   if (fscanf(infile, "%f", &input) != 1)
      error("Can't read float value!");

   return (real_t) input;
}

int
read_int (FILE *infile)
/*
 *  Read one integer value from the given input stream 'infile'.
 *
 *  Return value:
 *      integer value on success
 */
{
   int input;                           /* integer */

   assert (infile);

   remove_comments (infile);
   if (fscanf(infile, "%d", &input) != 1)
      error("Can't read integer value!");

   return input;
}

static void
remove_comments (FILE *file)
/*
 *  Remove shell/pgm style comments (#) from the input 'file'
 *
 *  No return value.
 */
{
   int c;                               /* current character */

   assert (file);

   do
   {
      while (isspace(c = getc (file)))
         ;
      if (c == EOF)
         error ("EOF reached, input seems to be truncated!");
      if (c == '#')
      {
         int dummy;

         while (((dummy = getc (file)) != '\n') && dummy != EOF)
            ;
         if (dummy == EOF)
            error ("EOF reached, input seems to be truncated!");
      }
      else
         ungetc (c, file);
   } while (c == '#');
}

void
write_rice_code (unsigned value, unsigned rice_k, bitfile_t *output)
/*
 *  Write 'value' to the stream 'output' using Rice coding with base 'rice_k'.
 *
 *  No return value.
 */
{
   unsigned unary;                      /* unary part of Rice Code */

   assert (output);

   for (unary = value >> rice_k; unary; unary--)
      put_bit (output, 1);
   put_bit (output, 0);
   put_bits (output, value & ((1 << rice_k) - 1), rice_k);
}

unsigned
read_rice_code (unsigned rice_k, bitfile_t *input)
/*
 *  Read a Rice encoded integer (base 'rice_k') from the stream 'input'.
 *
 *  Return value:
 *      decoded integer
 */
{
   unsigned unary;                      /* unary part of Rice code */

   assert (input);

   for (unary = 0; get_bit (input); unary++) /* unary part */
      ;

   return (unary << rice_k) | get_bits (input, rice_k);
}

void
write_bin_code (unsigned value, unsigned maxval, bitfile_t *output)
/*
 *  Write 'value' to the stream 'output' using an adjusted binary code
 *  based on given 'maxval'.
 *
 *  No return value.
 */
{
   unsigned k;
   unsigned r;

   assert (output && maxval && value <= maxval);

   k = log2 (maxval + 1);
   r = (maxval + 1) % (1 << k);

   if (value < maxval + 1 - 2 * r)      /* 0, ... , maxval - 2r */
      put_bits (output, value, k);
   else                                 /* maxval - 2r + 1, ..., maxval */
      put_bits (output, value + maxval + 1 - 2 * r, k + 1);
}

unsigned
read_bin_code (unsigned maxval, bitfile_t *input)
/*
 *  Read a bincode encoded integer from the stream 'input'.
 *
 *  Return value:
 *      decoded integer
 */
{
   unsigned k;
   unsigned r;
   unsigned value;

   assert (input);

   k = log2 (maxval + 1);
   r = (maxval + 1) % (1 << k);

   value = get_bits (input, k);
   if (value < maxval + 1 - 2 * r)
      return value;
   else
   {
      value <<= 1;
      if (get_bit (input))
         value++;
      return value - maxval - 1 + 2 * r;
   }
}

unsigned
bits_rice_code (unsigned value, unsigned rice_k)
/*
 *  Compute number of bits needed for coding integer 'value'
 *  with given Rice code 'rice_k'.
 *
 *  Return value:
 *      number of bits
 */
{
   unsigned unary;
   unsigned bits = 0;

   for (unary = value >> rice_k; unary; unary--)
      bits++;
   bits += rice_k + 1;

   return bits;
}

unsigned
bits_bin_code (unsigned value, unsigned maxval)
/*
 *  Compute number of bits needed for coding integer 'value'
 *  with adjusted binary code of given maximum value 'maxval'.
 *
 *  Return value:
 *      number of bits
 */
{
   unsigned k;
   unsigned r;

   assert (maxval && value <= maxval);

   k = log2 (maxval + 1);
   r = (maxval + 1) % (1 << k);

   return value < maxval + 1 - 2 * r ? k : k + 1;
}

unsigned *
init_clipping (void)
/*
 *  Initialize the clipping tables
 *
 *  Return value:
 *      pointer to clipping table
 */
{
   static unsigned *gray_clip = NULL;   /* clipping array */

   if (gray_clip == NULL)               /* initialize clipping table */
   {
      int i;                            /* counter */

      gray_clip  = calloc (256 * 3, sizeof (unsigned));
      if (!gray_clip)
      {
         set_error (_("Out of memory."));
         return NULL;
      }
      gray_clip += 256;

      for (i = -256; i < 512; i++)
         if (i < 0)
            gray_clip [i] = 0;
         else if (i > 255)
            gray_clip [i] = 255;
         else
            gray_clip [i] = i;
   }

   return gray_clip;
}

#ifndef HAVE_MEMMOVE
void *
memmove (void *v_dst, const void *v_src, size_t n)
/*
 *  Copy 'n' bytes from memory area 'src' to memory area 'dest'.
 *  The memory areas may overlap.
 *
 *  Return value:
 *      pointer 'dest'
 */
{
   byte_t       *to, *dst = (byte_t *) v_dst;
   const byte_t *from, *src = (byte_t *) v_src;

   assert (v_dst && v_src);

   if (dst <= src)
   {
      from = src;
      to   = dst;
      for (; n; n--)
         *to++ = *from++;
   }
   else
   {
      from = src + (n - 1);
      to   = dst + (n - 1);
      for (; n; n--)
         *to-- = *from--;
   }

   return v_dst;
}
#endif /* not HAVE_MEMMOVE */

/* Note that some systems have a "log2()" in the math library and some
   have a "log2" macro.  So we name ours Log2.  But to avoid lots of
   differences from the original fiasco source code, we define a
   macro log2 in config.h to expand to Log2.
   */
double
Log2 (double x)
/*
 *  Return value:
 *      base-2 logarithm of 'x'
 */
{
   return log (x) / 0.69314718;
}

real_t
variance (const word_t *pixels, unsigned x0, unsigned y0,
          unsigned width, unsigned height, unsigned cols)
/*
 *  Compute variance of subimage ('x0', y0', 'width', 'height') of
 *  the image data given by 'pixels' ('cols' is the number of pixels
 *  in one row of the image).
 *
 *  Return value:
 *      variance
 */
{
   real_t   average;                    /* average of pixel values */
   real_t   variance;                   /* variance of pixel values */
   unsigned x, y;                       /* pixel counter */
   unsigned n;                          /* number of pixels */

   assert (pixels);

   for (average = 0, n = 0, y = y0; y < y0 + height; y++)
      for (x = x0; x < MIN(x0 + width, cols); x++, n++)
         average += pixels [y * cols + x] / 16;

   average /= n;

   for (variance = 0, y = y0; y < y0 + height; y++)
      for (x = x0; x < MIN(x0 + width, cols); x++)
         variance += square ((pixels [y * cols + x] / 16) - average);

   return variance;
}

int
sort_asc_word (const void *value1, const void *value2)
/*
 *  Sorting function for quicksort.
 *  Smallest values come first.
 */
{
   if (* (word_t *) value1 < * (word_t *) value2)
      return -1;
   else if (* (word_t *) value1 > * (word_t *) value2)
      return +1;
   else
      return 0;
}

int
sort_desc_word (const void *value1, const void *value2)
/*
 *  Sorting function for quicksort.
 *  Largest values come first.
 */
{
   if (* (word_t *) value1 > * (word_t *) value2)
      return -1;
   else if (* (word_t *) value1 < * (word_t *) value2)
      return +1;
   else
      return 0;
}

int
sort_asc_pair (const void *value1, const void *value2)
/*
 *  Sorting function for quicksort.
 *  Smallest values come first.
 */
{
   word_t v1 = ((pair_t *) value1)->key;
   word_t v2 = ((pair_t *) value2)->key;

   if (v1 < v2)
      return -1;
   else if (v1 > v2)
      return +1;
   else
      return 0;
}

int
sort_desc_pair (const void *value1, const void *value2)
/*
 *  Sorting function for quicksort.
 *  Largest values come first.
 */
{
   word_t v1 = ((pair_t *) value1)->key;
   word_t v2 = ((pair_t *) value2)->key;

   if (v1 > v2)
      return -1;
   else if (v1 < v2)
      return +1;
   else
      return 0;
}
