#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _MSC_VER
#  include <process.h>
#else
#  include <sys/types.h>
#  include <sys/wait.h>
#endif

#define CONCAT_ARRAYS(TYPE, ARRAY_A, SIZE_A, ARRAY_B, SIZE_B) \
  (TYPE*)concatArrays((const void**)(ARRAY_A), (SIZE_A), \
  (const void**)(ARRAY_B), (SIZE_B), sizeof(TYPE))

#define NULL_TERMINATE(TYPE, ARRAY, SIZE) \
  (TYPE*)realloc(ARRAY, sizeof(TYPE) * (SIZE + 1))

#define ARRAY_LEN(ARRAY) (sizeof(ARRAY) / sizeof *(ARRAY))

void*
concatArrays(const void* arrayA, size_t sizeA,
  const void* arrayB, size_t sizeB, size_t sizeType) {
    char* concatenatedArray = malloc(sizeType * (sizeA + sizeB));
    memcpy(concatenatedArray, arrayA, sizeA * sizeType);
    memcpy(concatenatedArray + sizeA * sizeType, arrayB, sizeB * sizeType);
    return concatenatedArray;
}

char*
joinStr(char* strA, char* strB, char* separator) {
    int lenA = strlen(strA);
    int lenB = strlen(strB);
    int lenSeparator = strlen(separator);
    char* concatenatedStr = malloc(lenA + lenB + lenSeparator + 1);
    memcpy(concatenatedStr, strA, lenA);
    memcpy(concatenatedStr + lenA, separator, lenSeparator);
    memcpy(concatenatedStr + lenA + lenSeparator, strB, lenB + 1);
    return concatenatedStr;
}

int
spawnParpgProcess(char* pythonExecutable, char* configDir, int argc,
  char* argv[]) {
    char* baseArgs[] = {pythonExecutable, "-m", "parpg.main", configDir};
    int nBaseArgs = ARRAY_LEN(baseArgs);
    int nAdditionalArgs = argc - 1;
    char* additionalArgs[nAdditionalArgs];
    int i;
    for (i = 1; i < argc; i++) {
        additionalArgs[i - 1] = argv[i];
    }
    int nArgs = nBaseArgs + nAdditionalArgs;
    char** args = NULL_TERMINATE(char*, CONCAT_ARRAYS(char*, baseArgs,
      nBaseArgs, additionalArgs, nAdditionalArgs), nArgs);
    char* oldPythonPath = getenv("PYTHONPATH");
    char* newPythonPath = joinStr(oldPythonPath, "@PY_PACKAGES_DIR@", ":");
    int exitStatus;
    char* env[2] = {joinStr("PYTHONPATH=", newPythonPath, ""), (char*)(0)};
#ifdef _MSC_VER
    exitStatus = spawnve(P_WAIT, pythonExecutable, args, env);
#else
    exitStatus = execve(pythonExecutable, args, env);
#endif
    return exitStatus;
}

int
main(int argc, char* argv[]) {
    int exitStatus = spawnParpgProcess("@PYTHON@", "@SYS_CONF_DIR@", argc,
      argv);
    if (exitStatus) {
        perror("parpg exited with error");
    }
    return exitStatus;
}

