#ifndef __MSYSTEM_H__
#define __MSYSTEM_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h> // close()
#include <string.h> // strcpy, memset(), and memcpy()
#include <stdarg.h>
#include <errno.h> // errno, perror()
#include <stdbool.h>
#include <pthread.h>
#include <semaphore.h>
#include <math.h>
#include <time.h>
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#include <getopt.h>
#include <termios.h>
#include <netdb.h> // struct addrinfo
#include <sys/stat.h>
#include <sys/ioctl.h>   // macro ioctl is defined
#include <bits/ioctls.h> // defines values for argument "request" of ioctl.
#include <sys/syscall.h>
#include <sys/types.h> // needed for socket(), uint8_t, uint16_t, uint32_t
#include <sys/select.h>
// #define _GNU_SOURCE
#include <sys/socket.h> // needed for socket()
#include <sys/time.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <libgen.h>
#include <poll.h>
#include <netinet/in.h>      // IPPROTO_ICMP, INET_ADDRSTRLEN
#include <netinet/ip.h>      // struct ip and IP_MAXPACKET (which is 65535)
#include <netinet/ip_icmp.h> // struct icmp, ICMP_ECHO
#include <arpa/inet.h>       // inet_pton() and inet_ntop()
#include <net/if.h>          // struct ifreq
#include <net/ethernet.h>
// #include <linux/time.h>
#include <linux/if_ether.h>  // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD
#include <linux/if_packet.h> // struct sockaddr_ll (see man 7 packet)
#include <linux/serial.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/can/j1939.h>
#include <linux/can/error.h>
#include <ifaddrs.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

#include "mlogger.h"
#include "mthread.h"
#include "mtimer.h"

char* formatAppVersion(void);

time_t get_timezone(void);
time_t get_systime(void);
struct tm* get_localtime(struct tm* ptm);
struct tm* get_gmttime(struct tm* ptm);

int64_t systime_ms(void);
int64_t systime_us(void);
int64_t systime_ns(void);

int printline(uint8_t *data, int N, const char* fmt, ...);

void msleep(int milliseconds);

void dump_U16String_To_U8String(uint8_t *dst, uint16_t *src, int N);

void dump_U8String_To_U16String(uint16_t *dst, uint8_t *src, int N);

uint8_t DEC2BCD(uint8_t dec);

uint8_t BCD2DEC(uint8_t bcd);

int sem_waittimeout(sem_t *__sem, int timeout);

time_t RFC3339String_to_time(const char* datetime, struct timeval* tv, struct timespec* ts);
int sprintf_UTCFileName(char* stream, time_t utc);
char* format_UTCFileName(char* stream, time_t utc);

int sprintf_UTCTime(char* stream, time_t utc);
char* format_UTCTime(char* stream, time_t utc);

int sprintf_structTM(char* stream, struct tm* tmp);
char* format_structTM(char* stream, struct tm* tmp);

int sprintf_structTV(char* stream, struct timeval* tv);
char* format_structTV(char* stream, struct timeval* tv);

int sprintf_structTS(char* stream, struct timespec* ts);
char* format_structTS(char* stream, struct timespec* ts);

int sprintf_basename(char* stream, const char* filename);
char* format_basename(char* stream, const char* filename);

int sprintf_pathname(char* stream, const char* filename);
char* format_pathname(char* stream, const char* filename);

const char* choose_first_ipv6_interface(void);

int get_ipv6_address(const char* if_name, struct sockaddr_in6* addr, char *ip_string, int size);
int create_listen_socket_bind_ipv6(struct sockaddr_in6* sockaddr);
int create_stream_socket_connect_ipv6(struct sockaddr_in6* sockaddr);

int get_ipv4_address(const char* if_name, struct sockaddr_in* addr, char *ip_string, int size);
int create_listen_socket_bind_ipv4(struct sockaddr_in* sockaddr);
int create_stream_socket_connect_ipv4(struct sockaddr_in* sockaddr);

int openSSL_check_certificate(SSL*  ssl);

int string_strip_chr(char* out, const char* xin, char target, int N);
#endif //__MSYSTEM_H__
