#include "mavka/prystriy.h"

// спільне для unix і wasm

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

  return true;
}

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

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

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

extern логічне пристрій_мавки_отримати_теку_шляху(п8* дані_шляху,
                                                  природне розмір_шляху,
                                                  п8** вихід_даних,
                                                  природне* вихід_розміру,
                                                  природне рівень) {
  char* шлях_рядок = (char*)пристрій_мавки_виділити(розмір_шляху + 1);
  for (природне і = 0; і < розмір_шляху; і++) {
    шлях_рядок[і] = (char)дані_шляху[і];
  }
  шлях_рядок[розмір_шляху] = '\0';

  char* шлях_копія = strdup(шлях_рядок);
  char* тека = dirname(шлях_копія);

  for (природне і = 1; і < рівень; і++) {
    char* нова_копія = strdup(тека);
    пристрій_мавки_звільнити(шлях_копія);
    шлях_копія = нова_копія;
    тека = dirname(шлях_копія);
  }

  природне довжина = strlen(тека);
  *вихід_розміру = довжина;
  *вихід_даних = (п8*)пристрій_мавки_виділити(довжина);
  if (!*вихід_даних) {
    пристрій_мавки_звільнити(шлях_рядок);
    пристрій_мавки_звільнити(шлях_копія);
    return false;
  }

  for (природне і = 0; і < довжина; і++) {
    (*вихід_даних)[і] = (п8)тека[і];
  }

  пристрій_мавки_звільнити(шлях_рядок);
  пристрій_мавки_звільнити(шлях_копія);
  return true;
}

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

  *вихід_розміру = розмір_шляху + довжина_суфікса;
  *вихід_даних = (п8*)пристрій_мавки_виділити(*вихід_розміру);
  if (!*вихід_даних) {
    return false;
  }

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

  return true;
}

extern логічне пристрій_мавки_отримати_назву_модуля_з_шляху_ю8(
    п8* дані_шляху,
    природне розмір_шляху,
    п8** вихід_даних,
    природне* вихід_розміру) {
  char* шлях_рядок = (char*)пристрій_мавки_виділити(розмір_шляху + 1);
  for (природне і = 0; і < розмір_шляху; і++) {
    шлях_рядок[і] = (char)дані_шляху[і];
  }
  шлях_рядок[розмір_шляху] = '\0';

  char* шлях_копія = strdup(шлях_рядок);
  char* назва = basename(шлях_копія);

  const char* суфікс = ".м";
  природне довжина_суфікса = strlen(суфікс);
  природне довжина = strlen(назва);

  if (довжина >= довжина_суфікса) {
    логічне має_суфікс = true;
    for (природне і = 0; і < довжина_суфікса; і++) {
      if (назва[довжина - довжина_суфікса + і] != суфікс[і]) {
        має_суфікс = false;
        break;
      }
    }
    if (має_суфікс) {
      довжина -= довжина_суфікса;
    }
  }

  п8* назва_ю8 = (п8*)пристрій_мавки_виділити(довжина);
  for (природне і = 0; і < довжина; і++) {
    назва_ю8[і] = (п8)назва[і];
  }

  *вихід_розміру = довжина;
  *вихід_даних = назва_ю8;

  пристрій_мавки_звільнити(шлях_рядок);
  пристрій_мавки_звільнити(шлях_копія);
  return true;
}

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

  природне загальний_розмір = кількість_елементів - 1 + strlen(суфікс);

  for (природне і = 0; і < кількість_елементів; і++) {
    загальний_розмір += елементи[і].розмір;
  }

  *вихід_розміру = загальний_розмір;
  *вихід_даних = (п8*)пристрій_мавки_виділити(загальний_розмір);
  if (!*вихід_даних) {
    return false;
  }

  природне позиція = 0;
  for (природне і = 0; і < кількість_елементів; і++) {
    memcpy(*вихід_даних + позиція, елементи[і].дані, елементи[і].розмір);
    позиція += елементи[і].розмір;
    if< кількість_елементів - 1) {
      (*вихід_даних)[позиція++] = '/';
    }
  }

  for (природне і = 0; і < strlen(суфікс); і++) {
    (*вихід_даних)[позиція++] = (п8)суфікс[і];
  }

  return true;
}

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

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

  return true;
}

extern логічне пристрій_мавки_отримати_шлях_до_паку_з_шляху_теки_модулів(
    п8* дані_шляху,
    природне розмір_шляху,
    п8* дані_шляху_до_паків,
    природне розмір_шляху_до_паків,
    п8** вихід_даних,
    природне* вихід_розміру) {
  // Check if the module path starts with the packages path
  if (розмір_шляху <= розмір_шляху_до_паків) {
    return false;
  }

  // Verify that the module path starts with the packages path
  for (природне і = 0; і < розмір_шляху_до_паків; і++) {
    if (дані_шляху[і] != дані_шляху_до_паків[і]) {
      return false;
    }
  }

  // Find the next '/' after the packages path to get the package directory
  природне позиція_наступного_слешу = 0;
  логічне знайдено = false;

  // Skip the packages path and any immediate '/'
  природне початок = розмір_шляху_до_паків;
  if (початок < розмір_шляху && дані_шляху[початок] == '/') {
    початок++;
  }

  // Find the next '/' which marks the end of the package name
  for (природне і = початок; і < розмір_шляху; і++) {
    if (дані_шляху[і] == '/') {
      позиція_наступного_слешу = і; // Don't include the trailing slash
      знайдено = true;
      break;
    }
  }

  if (!знайдено) {
    позиція_наступного_слешу = розмір_шляху;
  }

  // Return the path up to but not including the trailing slash
  *вихід_розміру = позиція_наступного_слешу;
  *вихід_даних = (п8*)пристрій_мавки_виділити(*вихід_розміру);
  if (!*вихід_даних) {
    return false;
  }

  for (природне і = 0; і < позиція_наступного_слешу; і++) {
    (*вихід_даних)[і] = дані_шляху[і];
  }

  return true;
}