#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define ERR_OK 0
#define ERR_FAIL -1
#define ERR_INVALID_ARGS -2
#define ERR_INVALID_OPTS -3

#define RPE_BUFF_LEN 32
#define RPE_ID_LEN 32

typedef union {
    struct {
        uint32_t id;
        uint32_t count;
    };
    char raw[RPE_BUFF_LEN];
} rpe_header_t;

typedef struct {
    char id[RPE_ID_LEN];
    uint32_t offset;
    uint32_t size;
    float unknown;    // seems to be a floating point value of some sort, maybe duration as it is quite small
} rpe_file_header_t;

char* readWholeFile(char* fpath) {
    FILE* rpe = fopen(fpath, "r");
    fseek(rpe, 0, SEEK_END);
    int32_t rpe_len = ftell(rpe);
    char* rpe_data = (char*)malloc(rpe_len);
    fseek(rpe, 0, SEEK_SET);
    fread(rpe_data, 1, rpe_len, rpe);
    fclose(rpe);
    return rpe_data;
}

void extractFile(rpe_file_header_t* finfo, char* rpe_stream) {
    char fpath[RPE_ID_LEN + 4];
    strncpy(fpath, finfo->id, RPE_ID_LEN);
    int32_t flen = strlen(fpath);
    strncpy(&fpath[flen], ".wav", 5);

    FILE* out = fopen(fpath, "w");
    fwrite(rpe_stream + finfo->offset, 1, finfo->size, out);
    fclose(out);
}

int32_t extractRPE(char* rpe_path) {
    char* rpe_data = readWholeFile(rpe_path);
    rpe_header_t* rpe_header = (rpe_header_t*)rpe_data;
    rpe_file_header_t* rpe_file_header_table = (rpe_file_header_t*)(rpe_data + sizeof(rpe_header_t));
    for (int32_t i = 0; i < rpe_header->count; ++i) {
        extractFile(&rpe_file_header_table[i], rpe_data);
    }
    return ERR_OK;
}

int32_t createRPE(char* rpe_path) {
    printf("NOT YET IMPLEMENTED!\n");
    return ERR_FAIL;
}

void printUsage() {
    printf("    Usage:\n");
    printf("    rpe-extractor <options> <rpe_path>\n");
    printf("\n");
    printf("    Options:\n");
    printf("    -x => extract data from .rpe container to folder with same name\n");
    printf("    -c => create new .rpe container from data in folder with same name without .rpe extension\n");
    printf("\n");
}

int32_t main(int32_t argc, char** argv) {
    if ((argc < 2) || (argc > 3)) {
        printf("Invalid number of arguments!\n");
        printUsage();
        return ERR_INVALID_ARGS;
    }

    switch (argv[1][1]) {
        case 'x':
            return extractRPE(argv[2]);
        case 'c':
            return createRPE(argv[2]);
        default:
            printf("Invalid option \"-%c\"!\n", argv[1][1]);
            printUsage();
            return ERR_INVALID_ARGS;
    }

    return ERR_OK;
}