/* includes */
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

/* internal prototypes */
static void a(void);

static void b(const char *str);

static void c(void);

int main(int argc, char **argv) {
  a();
  if (argc > 1) {
    b(argv[1]);
  } else {
    printf("\nAufgabe b)\nTODO: Uebergeben Sie eine Zahl auf der Kommandozeile "
           "um Funktion b() auszufuehren.\n");
  }
  c();
  return 0;
}

/* internal function definitions */
static void a(void) {
  /* displays the size and ranges of the fixed size integer types */
  printf("\nAufgabe a)\n");

  int8_t i8_min = 0x80;
  int8_t i8_max = 0x7f;

  uint8_t u8_min = 0;
  uint8_t u8_max = 0xff;

  int16_t i16_min = 0x8000;
  int16_t i16_max = 0x7fff;

  uint16_t u16_min = 0;
  uint16_t u16_max = 0xffff;

  int32_t i32_min = 0x80000000;
  int32_t i32_max = 0x7fffffff;

  uint32_t u32_min = 0;
  uint32_t u32_max = 0xffffffff;

  int64_t i64_min = 0x8000000000000000;
  int64_t i64_max = 0x7fffffffffffffff;

  uint64_t u64_min = 0;
  uint64_t u64_max = 0xffffffffffffffff;

  printf("i8_min: %hhd, i8_max: %hhd\n", i8_min, i8_max);
  printf("u8_min: %hhu, u8_max: %hhu\n", u8_min, u8_max);
  printf("i16_min: %hd, i16_max: %hd\n", i16_min, i16_max);
  printf("u16_min: %hu, u16_max: %hu\n", u16_min, u16_max);
  printf("i32_min: %d, i32_max: %d\n", i32_min, i32_max);
  printf("u32_min: %u, u32_max: %u\n", u32_min, u32_max);
  printf("i64_min: %ld, i64_max: %ld\n", i64_min, i64_max);
  printf("u64_min: %lu, u64_max: %lu\n", u64_min, u64_max);
}

// gib einfach 2147483648
static void b(const char *str) {
  /* No compiler warnings anymore */
  printf("\nAufgabe b)\n");
  char *endptr;
  errno = 0;
  int32_t s32 = (int32_t)strtol(str, &endptr, 10);
  if (errno || *endptr) {
    fprintf(stderr, "Conversion error, non-convertible part: %s\n", endptr);
  } else {
    printf("s32 = %d\n", s32);
  }
}

static void c(void) {
  /* gcc generates compiler warnings (-Woverflow) */
  printf("\nAufgabe c)\n");

  const int8_t target = 42;

  uint8_t u8 = 122;
  int8_t s8 = 100;
  uint16_t u16 = 1567;
  int16_t s16 = 3000;
  uint32_t u32 = 5049039;
  int32_t s32 = 93049309;
  uint64_t u64 = 90394039403;
  int64_t s64 = 59848904909;

  uint8_t u8_comp = target + 255 - u8 + 1;
  uint16_t u16_comp = target + 65535 - u16 + 1;
  uint32_t u32_comp = target + 4294967295 - u32 + 1;
  uint64_t u64_comp = target + 18446744073709551615 - u64 + 1;

  int8_t s8_comp = target + 255 - ((uint8_t) s8) + 1;
  int16_t s16_comp = target + 65535 - ((uint16_t) s16) + 1;
  int32_t s32_comp = target + 4294967295 - ((uint32_t) s32) + 1;
  int64_t s64_comp = target + 18446744073709551615 - ((uint64_t) s64) + 1;

  printf("u8: %hhu\n", u8 + u8_comp);
  printf("u16: %hu\n", u16 + u16_comp);
  printf("u32: %u\n", u32 + u32_comp);
  printf("u64: %lu\n", u64 + u64_comp);

  printf("s8: %hhd\n", s8 + s8_comp);
  printf("s16: %hd\n", s16 + s16_comp);
  printf("s32: %d\n", s32 + s32_comp);
  printf("s64: %ld\n", s64 + s64_comp);
}

// int02: s8, s16, u32