#include "./walloc.c"
#include "mavka/prystriy.h"

size_t strlen(const char* str) {
  size_t len = 0;
  while (str[len] != '\0') {
    len++;
  }
  return len;
}

КористувацькийПристрійМавкиЧитатиКД користувацький_пристрій_мавки_читати_кд;

extern void змінити_користувацький_пристрій_мавки_читати_кд(
    КористувацькийПристрійМавкиЧитатиКД нова_функція) {
  користувацький_пристрій_мавки_читати_кд = нова_функція;
}

extern логічне пристрій_мавки_отримати_версію(природне* вихід_розміру,
                                              п8** вихід_даних) {
  char* версія_ю8 = PROGRAM_VERSION;

  природне позиція_помилки;

  if (пристрій_мавки_перекодувати_ю8_в_кд(strlen(версія_ю8), (п8*)версія_ю8,
                                          вихід_розміру, вихід_даних,
                                          &позиція_помилки)) {
    return true;
  }

  return false;
}

extern void пристрій_мавки_вивести_кд(природне розмір, п8* дані) {
  природне розмір_ю8;
  п8* дані_ю8;
  природне позиція_помилки;

  if (пристрій_мавки_перекодувати_кд_в_ю8(розмір, дані, &розмір_ю8, &дані_ю8,
                                          &позиція_помилки)) {
    пристрій_мавки_вивести_ю8(розмір_ю8, дані_ю8);
    пристрій_мавки_звільнити_сиру_памʼять(дані_ю8);
  } else {
    // потім: обробити
  }
}

extern void пристрій_мавки_надрукувати_кд(природне розмір, п8* дані) {
  природне розмір_ю8;
  п8* дані_ю8;
  природне позиція_помилки;

  if (пристрій_мавки_перекодувати_кд_в_ю8(розмір, дані, &розмір_ю8, &дані_ю8,
                                          &позиція_помилки)) {
    пристрій_мавки_вивести_ю8(розмір_ю8, дані_ю8);
    char новий_рядок = '\n';
    пристрій_мавки_вивести_ю8(1, (п8*)&новий_рядок);
    пристрій_мавки_звільнити_сиру_памʼять(дані_ю8);
  } else {
    // потім: обробити
  }
}

extern п8* пристрій_мавки_виділити_сиру_памʼять(природне розмір) {
  return malloc(розмір);
}

extern п8* пристрій_мавки_перевиділити_сиру_памʼять(п8* значення,
                                                    природне новий_розмір) {
  return realloc(значення, новий_розмір);
}

extern void пристрій_мавки_звільнити_сиру_памʼять(п8* значення) {
  free(значення);
}

extern логічне перетворити_п64_в_ю8(п64 значення,
                                    природне* вихід_розміру,
                                    п8** вихід_даних);

extern логічне перетворити_ц64_в_ю8(ц64 значення,
                                    природне* вихід_розміру,
                                    п8** вихід_даних);

extern логічне перетворити_р64_в_ю8(р64 значення,
                                    природне* вихід_розміру,
                                    п8** вихід_даних,
                                    ціле* вихід_розміру_експоненти);

extern логічне пристрій_мавки_перетворити_п64_в_кд(п64 значення,
                                                   природне* вихід_розміру,
                                                   п8** вихід_даних) {
  природне розмір_ю8;
  п8* дані_ю8;
  природне позиція_помилки;

  if (перетворити_п64_в_ю8(значення, &розмір_ю8, &дані_ю8)) {
    if (пристрій_мавки_перекодувати_ю8_в_кд(розмір_ю8, дані_ю8, вихід_розміру,
                                            вихід_даних, &позиція_помилки)) {
      пристрій_мавки_звільнити_сиру_памʼять(дані_ю8);

      return true;
    }

    пристрій_мавки_звільнити_сиру_памʼять(дані_ю8);
  }

  return false;
}

extern логічне пристрій_мавки_перетворити_ц64_в_кд(ц64 значення,
                                                   природне* вихід_розміру,
                                                   п8** вихід_даних) {
  природне розмір_ю8;
  п8* дані_ю8;
  природне позиція_помилки;

  if (перетворити_ц64_в_ю8(значення, &розмір_ю8, &дані_ю8)) {
    if (пристрій_мавки_перекодувати_ю8_в_кд(розмір_ю8, дані_ю8, вихід_розміру,
                                            вихід_даних, &позиція_помилки)) {
      пристрій_мавки_звільнити_сиру_памʼять(дані_ю8);

      return true;
    }

    пристрій_мавки_звільнити_сиру_памʼять(дані_ю8);
  }

  return false;
}

extern логічне пристрій_мавки_перетворити_р64_в_кд(
    р64 значення,
    природне* вихід_розміру,
    п8** вихід_даних,
    ціле* вихід_розміру_експоненти) {
  природне розмір_ю8;
  п8* дані_ю8;
  природне позиція_помилки;

  if (перетворити_р64_в_ю8(значення, &розмір_ю8, &дані_ю8,
                           вихід_розміру_експоненти)) {
    if (пристрій_мавки_перекодувати_ю8_в_кд(розмір_ю8, дані_ю8, вихід_розміру,
                                            вихід_даних, &позиція_помилки)) {
      пристрій_мавки_звільнити_сиру_памʼять(дані_ю8);

      return true;
    }

    пристрій_мавки_звільнити_сиру_памʼять(дані_ю8);
  }

  return false;
}

extern п64 пристрій_мавки_піднести_до_степеня_п64(п64 значення, п64 степінь) {
  п64 результат = 1;
  for (п64 і = 0; і < степінь; і++) {
    результат *= значення;
  }
  return результат;
}

extern ц64 пристрій_мавки_піднести_до_степеня_ц64(ц64 значення, ц64 степінь) {
  ц64 результат = 1;
  for (ц64 і = 0; і < степінь; і++) {
    результат *= значення;
  }
  return результат;
}

extern логічне пристрій_мавки_перевірити_чи_шлях_закінчується_як_модуль_мавки(
    природне розмір_шляху,
    п8* дані_шляху) {
  const char* суфікс = ".м";
  природне довжина_суфікса = strlen(суфікс);

  if (розмір_шляху < довжина_суфікса) {
    return false;
  }

  for (природне і = 0; і < довжина_суфікса; і++) {
    if (дані_шляху[розмір_шляху - довжина_суфікса + і] != (п8)суфікс[і]) {
      return false;
    }
  }

  return true;
}

extern логічне пристрій_мавки_перевірити_чи_шлях_починається_на(
    природне розмір_шляху,
    п8* дані_шляху,
    природне розмір_початку,
    п8* дані_початку) {
  if (розмір_початку > розмір_шляху) {
    return false;
  }

  for (природне і = 0; і < розмір_початку; і++) {
    if (дані_шляху[і] != дані_початку[і]) {
      return false;
    }
  }

  return true;
}