#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>

#define P_SZ 4194304
#define M_SZ 262144
#define TOT_SPL (P_SZ / 16)
#define TPF 100

struct __attribute__((packed)) Splat {
    int16_t x, y, z;
    uint16_t t0;
    uint8_t dt;
    uint8_t op;
    uint8_t r, g, b, pad;
};

static struct Splat p_pool[TOT_SPL];
static int8_t m_pool[TOT_SPL];
static uint8_t tar_hdr[512];
static char path_p[64];
static char path_m[64];

static uint32_t seed = 5321;
static uint32_t djb_rand(void) {
    seed = seed * 1103515245 + 12345;
    return (seed / 65536) % 32768;
}

static int32_t sub_abs(int32_t a, int32_t b) {
    return (a > b) ? (a - b) : (b - a);
}

static void put_octal(uint8_t *buf, uint32_t val, int size) {
    int i;
    buf[size - 1] = ' ';
    for (i = size - 2; i >= 0; i--) {
        buf[i] = '0' + (val % 8);
        val /= 8;
    }
}

static void write_tar_header(const char *name, uint32_t size_dec, char type, const char *link_target) {
    int i; uint32_t chk = 0;
    for (i = 0; i < 512; i++) tar_hdr[i] = 0;
    for (i = 0; name[i] != '\0' && i < 100; i++) tar_hdr[i] = name[i];

    put_octal(tar_hdr + 100, 0000755, 8);
    put_octal(tar_hdr + 108, 0000000, 8);
    put_octal(tar_hdr + 116, 0000000, 8);

    if (type == '2') {
        put_octal(tar_hdr + 124, 0, 12); /* Symlinks haben im tar-Header die Größe 0 */
        for (i = 0; link_target[i] != '\0' && i < 100; i++) tar_hdr[157 + i] = link_target[i];
    } else {
        if (size_dec == 4194304) put_octal(tar_hdr + 124, 020000000, 12);
        else if (size_dec == 262144) put_octal(tar_hdr + 124, 01000000, 12);
        else put_octal(tar_hdr + 124, size_dec, 12);
    }

    put_octal(tar_hdr + 136, 00000000000, 12);
    tar_hdr[156] = type; /* '0' = Regular, '2' = Symlink */

    for (i = 0; i < 8; i++) tar_hdr[148 + i] = ' ';
    for (i = 0; i < 512; i++) chk += tar_hdr[i];
    put_octal(tar_hdr + 148, chk, 7);
    tar_hdr[155] = '\0';

    write(1, tar_hdr, 512);
}

static void build_filename(char *buf, int32_t sz, int32_t zeit, char sfx) {
    int32_t ux = 5000, uy = 5000, uz = sz + 5000;
    char *p = buf;
    *p++ = 'w'; *p++ = 'o'; *p++ = 'r'; *p++ = 'l'; *p++ = 'd'; *p++ = '/';
    *p++ = '0' + (ux / 1000); *p++ = '0' + ((ux / 100) % 10); *p++ = '0' + ((ux / 10) % 10); *p++ = '0' + (ux % 10); *p++ = '/';
    *p++ = '0' + (uy / 1000); *p++ = '0' + ((uy / 100) % 10); *p++ = '0' + ((uy / 10) % 10); *p++ = '0' + (uy % 10); *p++ = '/';
    *p++ = '0' + (uz / 1000); *p++ = '0' + ((uz / 100) % 10); *p++ = '0' + ((uz / 10) % 10); *p++ = '0' + (uz % 10); *p++ = '/';
    *p++ = '0' + (zeit / 10000); *p++ = '0' + ((zeit / 1000) % 10); *p++ = '0' + ((zeit / 100) % 10); *p++ = '0' + ((zeit / 10) % 10); *p++ = '0' + (zeit % 10);
    *p++ = '.'; *p++ = sfx; *p = '\0';
}

int main(void) {
    int32_t sz, tp; uint32_t i;
    char target_p[] = "00000.p";
    char target_m[] = "00000.m";

    for (sz = 0; sz <= 5; sz++) {
        /* Wichtig: Wir generieren die echten Daten NUR EINMAL für tp == 0 */
        int32_t zeit_base = 0;

        for (i = 0; i < TOT_SPL; i++) {
            int32_t gx = djb_rand() % 500; int32_t gy = djb_rand() % 500; int32_t gz = djb_rand() % 500;
            int32_t wz = (sz * 500) + gz;
            p_pool[i].x = gx; p_pool[i].y = gy; p_pool[i].z = gz;
            p_pool[i].t0 = 0; p_pool[i].dt = 100; p_pool[i].op = 255; m_pool[i] = 0;

            int32_t h_center = 250 + (int32_t)(sz * 10 - 25);
            int32_t dx = sub_abs(gx, h_center);

            if (dx > 120) {
                uint32_t b_cell = (gx / 60) ^ (wz / 80); int32_t b_max_h = 150 + (int32_t)((b_cell * 73) % 250);
                if (gy < b_max_h) {
                    p_pool[i].r = 25; p_pool[i].g = 25; p_pool[i].b = 35;
                    if ((gx % 12 < 3) && (gy % 25 > 8 && gy % 25 < 18)) {
                        uint32_t f_color = b_cell % 3;
                        if (f_color == 0) { p_pool[i].r = 0;   p_pool[i].g = 230; p_pool[i].b = 255; }
                        else if (f_color == 1) { p_pool[i].r = 255; p_pool[i].g = 0;   p_pool[i].b = 180; }
                        else { p_pool[i].r = 255; p_pool[i].g = 160; p_pool[i].b = 0; }
                        m_pool[i] = 110;
                    }
                } else p_pool[i].op = 0;
            }
            else if (dx < 40 && gy > 80 && gy < 95) {
                if (gx < h_center) { p_pool[i].r = 255; p_pool[i].g = 30; p_pool[i].b = 30; }
                else { p_pool[i].r = 40; p_pool[i].g = 120; p_pool[i].b = 255; }
                m_pool[i] = 90;
            }
            else if (gy < 20 && dx <= 120) {
                p_pool[i].r = 15; p_pool[i].g = 15; p_pool[i].b = 20;
                if (dx % 40 < 4 && wz % 30 < 10) { p_pool[i].r = 0; p_pool[i].g = 255; p_pool[i].b = 120; }
            }
            else p_pool[i].op = 0;
        }

        /* Schleife über alle Zeitphasen im Sektor */
        for (tp = 0; tp <= 4; tp++) {
            int32_t zeit = tp * 100;

            build_filename(path_p, sz, zeit, 'p');
            build_filename(path_m, sz, zeit, 'm');

            if (tp == 0) {
                /* Phase 00000: Schreibe die echten, vollen Datenblöcke */
                write_tar_header(path_p, P_SZ, '0', NULL); write(1, p_pool, P_SZ);
                write_tar_header(path_m, M_SZ, '0', NULL); write(1, m_pool, M_SZ);
            } else {
                /* Phasen 00100 bis 00400: Erzeuge leichtgewichtige relative Symlinks */
                write_tar_header(path_p, 0, '2', target_p);
                write_tar_header(path_m, 0, '2', target_m);
            }
        }
    }

    write_tar_header("finished", 512, '0', NULL);
    for (i = 0; i < 512; i++) ((uint8_t*)p_pool)[i] = 0;
    write(1, p_pool, 512);

    for (i = 0; i < 512; i++) tar_hdr[i] = 0;
    write(1, tar_hdr, 512); write(1, tar_hdr, 512);
    return 0;
}
