/***************************************************************************
 *   copyright           : (C) 2002 by Hendrik Sattler                     *
 *   mail                : post@hendrik-sattler.de                         *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef HELPERS_H
#define HELPERS_H

#include "intincl.h"
#include "charsets.h"
#include "gtincl.h"
#include <stdlib.h>
#if defined(WINDOWS_API)
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif

void helper_init ();

#define VERBOSE_LEVEL_ERROR   0
#define VERBOSE_LEVEL_WARNING 1
#define VERBOSE_LEVEL_NOTICE  2
#define VERBOSE_LEVEL_DEBUG   3
int verbosity_get ();
void verbosity_set (int level);

#define print_verbose(level,m, ...) { if (verbosity_get() >= level) { fprintf(stderr,m,__VA_ARGS__); fflush(stderr); } }
#define print_message(level,key, m, ...) { print_verbose(level,"%s: ",key); print_verbose(level,m,__VA_ARGS__); }
#define print_error(m, ...) print_message(VERBOSE_LEVEL_ERROR,_("\nError"),m,__VA_ARGS__)
#define print_warning(m, ...) print_message(VERBOSE_LEVEL_WARNING,_("Warning"),m,__VA_ARGS__)
#define print_notice(m, ...) print_message(VERBOSE_LEVEL_NOTICE,_("Notice"),m,__VA_ARGS__)
#define print_debug(m, ...) print_message(VERBOSE_LEVEL_DEBUG,_("Debug"),m,__VA_ARGS__)
#define errexit(m, ...) { print_error(m,__VA_ARGS__); exit(EXIT_FAILURE); }


/* check if a file can be read */
int file_accessible_ro (char* file);
/* open an input file (read-only) */
int file_open_input (char* file);
/* open an output file (read-write) */
int file_open_output (char* file);
/* read a binary file */
unsigned int file_read_binary (char* file, char** buffer);
/* close a file handle */
void file_close (int filedes);


/* returns the console width in columns for fd */
long console_width(int fd);
/* print a status bar to console */
void console_print_status (int fd, const char* text, size_t textlen,
			   const unsigned long* current,
			   const unsigned long* total,
			   unsigned int fcount);


/* returns the number of digits in num */
unsigned int numlen (long num);
/* returns the GSM type of address (TOA) value */
uint8_t numtype (const char* number);
/* returns 1 if every character in s is a digit else 0*/
int is_number(const char* s);
/* returns 1 if s is a telephone number else 0 */
int is_telephone_number (const char* s);
/* converts a hexadezimal string with a given length to an int */
unsigned int hexstr2int(char *hexstring, unsigned int length);


/* (re)allocate memory */
void* mem_alloc (size_t size, short zero_it);
void* mem_realloc (void* oldpointer, size_t size);


/* duplicate a c string */
char* str_dup (const char* input);
char* strn_dup (const char* input, size_t insize);

/* strlen() does not seem to check for strlen(NULL) and crashes */
size_t str_len(const char *s);

/** calculate the printed string width
 * This works for UTF-8 and charsets with fixed-size elements
 * @param s the string
 * @param len bytecount of s or less
 * @return amount of printed characters
 */
size_t str_width (const char* s);
size_t strn_width (const char* s, size_t len);

/** check if a string is valid
 * This works for UTF-8 and charsets with fixed-size elements
 * @param s string in ISO-8859-? or UTF-8
 * @param len bytecount of s or less
 */
int strn_valid (const char* s, size_t len);
int str_valid (const char* s);

/*                        *
 * String array functions *
 *                        */
#define str_array_t char*
/** split a string
 * @param str string to split up (it gets modified!)
 * @param split at what points in str to split
 * @param count maximum number of splits, 0 means unlimited
 * 
 * @return return the dynamically allocated array ([0] = str)
 */
str_array_t* str_split (char* str, char* split, unsigned long count);

/** remove duplicates from a string array (keeps order)
 * @param array a NULL terminated list of strings
 */
void str_array_uniq (str_array_t* array);

/** append a array to another array
 * @param array1 malloc'ed pointer to an array
 * @param size1 current number of elements in array1
 * @param array2 array to append to array1
 * @param size2 number of elements in array2
 * @return realloc'ed (from array1), NULL-terminated list pointer
 */
str_array_t* str_array_append (str_array_t* array1, size_t size1,
			       str_array_t* array2, size_t size2);

/** sort the list (alphabetical order)
 * Be warned that if you use an array created be str_split,
 * the memory pointer may not be at element 0 anymore!
 * @param list a NULL terminated list of strings
 */
void str_array_sort (str_array_t* array);


/*                       *
 * String list functions *
 *                       */
typedef struct str_list {
  char* data;
  struct str_list* prev;
  struct str_list* next;
} str_list_t;

/* Initialize a string list element so it can
 * be use as list head.
 */
void str_list_init (str_list_t* this);

/* Create a new string list element from string:
 * The string gets copied. The element is already
 * initialized.
 */
str_list_t* str_list_create (char* data);

/* Destroy a string list element
 * You should remove it from its list first.
 */
void str_list_destroy (str_list_t* this);

/* insert tail directly after entry */
void str_list_insert (str_list_t* entry, str_list_t* tail);

/* append tail after last element of list
 * If this is repeated many times, it is suggested to use the
 * return value as list in the next invocation and
 * run str_list_rewind() later.
 */
str_list_t* str_list_append (str_list_t* list, str_list_t* tail);

/* remove an element from its current list */
str_list_t* str_list_remove (str_list_t* element);

/* return pointer to first element of list */
str_list_t* str_list_rewind (str_list_t* list);


#include <sys/types.h>
#define PTR8(ptr) ((uint8_t*)(ptr))
#define PTR16(ptr) ((uint16_t*)(ptr))
struct mmapped_file {
  void* ptr;
  off_t size;
};

/* These are wrapper functons to similar named ones
 * but they check for return code and may exit on failure.
 * They also check to NULL on there parameters.
 */

/* wrapper to mmap: map a file to memory
 * Does not exit on failure but returns -1 instead
 */
int mem_map(char* file, struct mmapped_file* fs);
void mem_unmap (struct mmapped_file* fs);


/* little endianess to host endianess */
uint16_t letohs (uint16_t i);
uint32_t letohl (uint32_t i);
/* host endianess to little endianess */
uint16_t htoles (uint16_t i);
uint32_t htolel (uint32_t i);

/* big endianess to host endianess */
#define betohs(i) ntohs(i)
#define betohl(i) ntohl(i)

/* host endianess to big endianess */
#define htobes(i) htons(i)
#define htobel(i) htonl(i)

/* GSM number
 */
#define GSM_NUMBER_TEXT_LEN   11
#define GSM_NUMBER_DIGITS_LEN 20
#define GSM_NUMBER_TYPE_UNKNOWN  0
#define GSM_NUMBER_TYPE_INTERNAT 1
#define GSM_NUMBER_TYPE_NAT      2
#define GSM_NUMBER_TYPE_TEXT     5
#define GSM_NUMBER_PLAN_UNKNOWN  0
#define GSM_NUMBER_PLAN_ISDN     1
struct gsm_number {
  struct { /* see ETSI 23.040, Ch. 9.1.2.5 */
    /* MSB is always 1! */
    unsigned int type :3; // type of number, see GSM_NUMBER_TYPE_*
    unsigned int plan :4; // nummbering plan identification, see GSM_NUMBER_PLAN_*
  } toa; /* type of address */

  char digits[GSM_NUMBER_DIGITS_LEN+1]; /* if toa.type != GSM_NUMBER_TYPE_TEXT */
  ucs4char_t* text;
};
void gsm_number_init (struct gsm_number* s);
void gsm_number_delete (struct gsm_number* s);
int gsm_number_compare (const struct gsm_number* s1, const struct gsm_number* s2);
void gsm_number_set_semioctets (struct gsm_number* this, uint8_t toa,
				uint8_t* semioctets, size_t len);
size_t gsm_number_get_semioctets (struct gsm_number* this, uint8_t* out);
void gsm_number_set (struct gsm_number* this,
		     const char* number, size_t len);
char* gsm_number_get (const struct gsm_number* this);
void gsm_number_set_toa (struct gsm_number* this, uint8_t toa);
uint8_t gsm_number_get_toa (const struct gsm_number* this);



#endif
