#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[40];
static char path_m[40];

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) {
    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, 0000644, 8);
    put_octal(tar_hdr + 108, 0000000, 8);
    put_octal(tar_hdr + 116, 0000000, 8);

    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] = '0';

    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;

    for (sz = 0; sz <= 5; sz++) {
        for (tp = 0; tp <= 4; tp++) {
            int32_t zeit = tp * 100;

            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 {
                    if ((djb_rand() % 1000) < 6) {
                        p_pool[i].op = 160 + (djb_rand() % 95);
                        if (tp % 2 == 0) {
                            p_pool[i].r = 0; p_pool[i].g = 255; p_pool[i].b = 140;
                        } else {
                            p_pool[i].r = 255; p_pool[i].g = 220; p_pool[i].b = 0;
                        }
                        p_pool[i].t0 = djb_rand() % 60;
                        p_pool[i].dt = 25 + (djb_rand() % 35);
                        m_pool[i] = 127;
                    } else {
                        p_pool[i].op = 0;
                    }
                }
            }

            build_filename(path_p, sz, zeit, 'p');
            write_tar_header(path_p, P_SZ);
            write(1, p_pool, P_SZ);

            build_filename(path_m, sz, zeit, 'm');
            write_tar_header(path_m, M_SZ);
            write(1, m_pool, M_SZ);
        }
    }


    write_tar_header("finished", 512);
    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;
}
