/*
 * This file is part of the Poliqarp suite.
 * 
 * Copyright (C) 2009 by Instytut Podstaw Informatyki Polskiej
 * Akademii Nauk (IPI PAN; Institute of Computer Science, Polish
 * Academy of Sciences; cf. www.ipipan.waw.pl).  All rights reserved.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file gpl.txt included in the packaging
 * of this file.  (See http://www.gnu.org/licenses/translations.html for
 * unofficial translations.)
 * 
 * A commercial license is available from IPI PAN (contact
 * Michal.Ciesiolka@ipipan.waw.pl or ipi@ipipan.waw.pl for more
 * information).  Licensees holding a valid commercial license from IPI
 * PAN may use this file in accordance with that license.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

#include <poliqarp-config.h>

#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include <foostring/foostring.h>

#include <sakura/poliqarp.h>
#include <sakura/common/memory-arena.h>

#include <bp/common.h>

static unsigned int verbosity = 1; /** Level of verbosity, 0 = quiet. */
static const char* command_name;

void bp_show_progress(unsigned int x)
{
   unsigned int i;
   if (verbosity == 0)
      return;
   assert(x <= 100);
   printf("\r%3d%%    [", x);
   x = (x * 60) / 100;
   for (i = 0; i < x; i++)
      putchar('*');
   for (i = 0; i < 60 - x; i++)
      putchar('.');
   putchar(']');
   fflush(stdout);
}

void bp_printf(const char *fmt, ...)
{
   va_list args;
   if (verbosity) {
      va_start(args, fmt);
      vprintf(fmt, args);
      va_end(args);
   }
}

void bp_set_verbosity(unsigned int x)
{
   verbosity = x;
}

static void bp_string_oom_callback(string_t s)
{
   bp_system_error("string allocation error");
}

void bp_init(const char *s)
{
   command_name = s;
   string_oom_callback = bp_string_oom_callback;
}

void bp_warning(const char *msg, ...)
{
   va_list args;

   fprintf(stderr, "%s: warning: ", command_name);
   va_start(args, msg);
   vfprintf(stderr, msg, args);
   fprintf(stderr, "\n");
   va_end(args);
}

void bp_fatal(const char *msg, ...)
{
   va_list args;

   fprintf(stderr, "%s: ", command_name);
   va_start(args, msg);
   vfprintf(stderr, msg, args);
   fprintf(stderr, "\n");
   va_end(args);
   exit(EXIT_FAILURE);
}

void bp_system_error(const char *msg, ...)
{
   va_list args;
   int my_errno = errno;

   fprintf(stderr, "%s: ", command_name);
   va_start(args, msg);
   vfprintf(stderr, msg, args);
   va_end(args);
   fputs(": ", stderr);
   errno = my_errno;
   perror(NULL);
   exit(EXIT_FAILURE);
}

void *bp_marena_alloc(struct marena *marena, size_t size)
{
   void *result;
   assert(marena != NULL);
   result = marena_alloc(marena, size);
   if (result == NULL)
      bp_system_error("memory allocation error");
   return result;
}

void *bp_malloc(size_t size)
{
   void *result = malloc(size);
   if (result == NULL)
      bp_system_error("memory allocation error");
   return result;
}

void *bp_realloc(void *ptr, size_t size)
{
   void *result = realloc(ptr, size);
   if (result == NULL)
      bp_system_error("memory allocation error");
   return result;
}

char *bp_strdup(const char *s)
{
   char *result = strdup(s);
   if (result == NULL)
      bp_system_error("memory allocation error");
   return result;
}

off64_t bp_file_size(FILE *f)
{
   off64_t offset, backup_offset = ftello(f);
   if (backup_offset < 0)
      goto error;
   if (fseeko(f, 0, SEEK_END) != 0)
      goto error;
   offset = ftello(f);
   if (offset < 0)
      goto error;
   if (fseeko(f, backup_offset, SEEK_SET) != 0)
      goto error;
   return offset;
error:
   bp_system_error("unable to determine file size");
   return -1; /* Just to shut up compilers. */
}

void bp_display_usage(const char *argv0, const char *option_summary,
   const char *summary, const char *option_list, const char *extra)
{
   if (option_summary == NULL)
      option_summary = "";
   printf("Usage: %s %s\n", argv0, option_summary);
   if (summary != NULL)
      printf("%s\n", summary);
   if (option_list != NULL)
      printf("\n%s", option_list);
   if (extra != NULL)
      printf("\n%s", extra);
   printf("\n%s\n", "Report bugs to <" PACKAGE_BUGREPORT ">.");
   exit(EXIT_SUCCESS);
}

void bp_display_version()
{
   printf("%s version %s\n", command_name, PACKAGE_VERSION);
   exit(EXIT_SUCCESS);
}

