#pragma endian little
#pragma pattern_limit 512000

#include <std/sys.pat>
#include <std/mem.pat>
#include <std/io.pat>
#include <std/core.pat>

struct RGBA8 {
  u8 red;
  u8 green;
  u8 blue;
  u8 alpha;
} [[static, color(std::format("{:02X}{:02X}{:02X}", red, green, blue))]];

struct Point {
    double x;
    double y;
};

struct MultiLine {
    u32 points;
    Point point[points];
};

enum WobbleType : u32 {
    Spiral = 0,
    Sinusoidal = 1,
    Ellipse = 2,
    Vert_8 = 3,
    Hoti_8 = 4,
};

// Field of a custom defined type
struct FieldOf<T> {
    u32 length;
    T value;
    
    std::assert(length == sizeof(value), "Size mismatch");
} [[sealed, format("format_field_of")]];

fn format_field_of(FieldOf<u8> f) {
    return f.value;
};

// Field of generic types
struct Field {
    u32 length;
    
    match (length) {
        (4): u32 value;
        (8): double value;
        (2): u16 value; // ??
        (16): Point value; // ??
        (1): u32 value; // ??
        (_): {
            std::warning(std::format("Unknown length tag: {} at 0x{:02X}", length, $));
            u8 value[length];
        }
    }
} [[sealed, format("format_field")]];

fn format_field(Field f) {
    return f.value;
};

// Variable length field of a fixed type.
struct String {
    u32 length;
    char16 value[length / sizeof(char16)];
} [[sealed, format("format_string")]];

fn format_string(String s) {
    return s.value;
};

struct Header {
    char16 magic[0x8];
    u8 unknown[0x338];
};

struct Pen {
    u32 num_fields; // Number of fields in this struct (236)
    Field color;
    String name;
    Field disabled;
    Field use_default_param;
    Field loop_count;
    Field speed; // Changes with wobble relative speed
    Field power;
    Field frequency;
    Field unknown_1[1];
    Field start_tc;
    Field end_tc;
    Field polygon_tc;
    Field jump_speed;
    Field unknown_2[10];
    Field laser_off_tc;
    Field wave; // Only available if continue_mode is false
    Field unknown_3[1];
    Field wobble_enable;
    Field wobble_diameter;
    Field wobble_distance;
    Field unknown_4[8];
    Field min_jump_tc;
    Field max_jump_tc;
    Field jump_limit;
    Field unknown_5[2];
    Field frequency2;
    Field unknown_6[152];
    FieldOf<WobbleType> wobble_type;
    Field continue_mode;
    Field unknown_7[12];
    Field wobble_diameter2; // Only with wobble type ellipse
    Field unknown_8[26];
    Field unknown_9[134];
};

bitfield ObjectFlags {
    disabled : 1;
    aspect_ratio_unlocked : 1; // ??
    padding : 14;
};

enum ObjectType: u32 {
    Curve = 1,
    Point = 2,
    Rectangle = 3,
    Circle = 4,
    Ellipse = 5,
    Polygon = 6,
    Hatch = 32,
};

struct ObjCommon {
    u32 num_fields; // Number of fields in this struct (17)
    Field pen;
    Field type; // Seems to always be same value as object type
    FieldOf<ObjectFlags>;
    String name;
    Field count;
    Field unknown_2[1];
    Field io_control_enable_mask;
    Field io_control_disable_mask;
    Field unknown_3[5];
    FieldOf<Point> origin;
    Field z;
    Field a;
    Field unknown_4[1];
};

enum LineType : u16 {
    Point = 0x0001,
    Line = 0x0100,
    Bezier = 0x0300,
};

struct LineEntry {
    LineType type;
    u32; // Zeros
    
    match (type) {
        (LineType::Point): Point;
        (LineType::Line): {
            u32 count;
            Point points[count];
        }
        (LineType::Bezier): {
            u32 count;
            Point points[count];
        }
        (_): std::error(std::format("Unknown line type: 0x{:02X} at 0x{:02X}", u32(type), $));
    }
};

struct LineSet : ObjCommon {
    u32 count;
    u32; // Zeros
    
    LineEntry entries[count];
};

struct ClosedSet : ObjCommon {
    u32 count;
    Field entries[count];
};

struct Rectangle : ObjCommon {
    u32 num_fields; // Number of fields in this struct (8)
    FieldOf<Point> corner_a;
    FieldOf<Point> corner_b;
    Field round_bottom_left;
    Field round_bottom_right;
    Field round_top_right;
    Field round_top_left;
    Field unknown[2];
};

struct Circle : ObjCommon {
    u32 num_fields; // Number of fields in this struct (6)
    FieldOf<Point> origin;
    Field radius;
    Field start_angle; // Radians
    Field clockwise;
    Field unknown[2];
};

struct Ellipse : ObjCommon {
    u32 num_fields; // Number of fields in this struct (8)
    Field clockwise;
    FieldOf<Point> corner_a;
    FieldOf<Point> corner_b;
    Field start_angle; // Radians
    Field end_angle; // Radians
    Field unknown[2];
    Field open_curve;
};

struct Polygon : ObjCommon {
    u32 num_fields; // Number of fields in this struct (10)
    Field invert_shape;
    FieldOf<Point> corner_a;
    FieldOf<Point> corner_b;
    Field offset_cx; // Moves (intial) sharper corner
    Field offset_cy; // Moves (initial)sharper corner
    Field offset_dx;
    Field offset_dy;
    Field edges;
    Field unknown_3[2];
};

struct HatchLine {
    u32 num_lines;
    LineSet line[num_lines];
};

using Object;

bitfield HatchFlags {
    padding : 1;
    follow_edge_once : 1;
    padding : 4;
    auto_rotate_hatch_angle : 1;
    average_distribut_line : 1;
    padding : 2;
    cross_hatch : 1;
    padding : 21;
};

struct HatchSettings {
    u32 num_fields; // 47
    Field flags; // 1 = mark contour
    Field unknown_1[1];
    Field pen;
    FieldOf<HatchFlags> flags_2;
    Field edge_offset;
    Field line_spacing;
    Field start_offset;
    Field end_offset;
    Field angle;
    Field unknown_4[9];
    Field auto_rotate_angle;
    Field unknown_7[10];
    Field line_reduction;
    Field unknown_3[2];
    Field num_loops;
    Field unknown_5[2];
    Field loop_distance;
    Field unknown_6[5];
    Field contour_first;
    Field count;
    Field unknown_2[4];
};

struct HatchSettings2 {
    u32 num_fields; // 15
    Field count;
    Field unknown_1[1];
    Field pen;
    FieldOf<HatchFlags> flags_2; // Same as HatchSettings.flags_2
    Field edge_offset;
    Field line_spacing;
    Field start_offset;
    Field end_offset;
    Field angle;
    Field auto_rotate_angle;
    Field line_reduction;
    Field loop_distance;
    Field num_loops;
    Field unknown_5[2];
};

struct Hatch : ObjCommon {
    u32; // 1
    Object outline;
    HatchSettings settings;
    HatchSettings2 settings_2;
    u32 count_5; //17
    Field unknown_5[count_5];
    u32; // 1
    u32; // 16
    u32 count_6; // 17
    Field pen;
    Field unknown_6[2];
    String hatch_name;
    Field unknown_7[count_6 - 4];
    //Field unknown_6[count_6];
    
    u32 num_lines;
    HatchLine lines[num_lines];    
};

struct Object {
    ObjectType type;
    
    match (type) {
        (ObjectType::Curve): LineSet;
        (ObjectType::Point): LineSet;
        (ObjectType::Rectangle): Rectangle;
        (ObjectType::Circle): Circle;
        (ObjectType::Ellipse): Ellipse;
        (ObjectType::Polygon): Polygon;
        (ObjectType::Hatch): Hatch;
        (_): std::error(std::format("Unknown object type: 0x{:02X} at 0x{:02X}", u32(type), $));
    }
};

struct Layer {
    u32 num_fields_1; // Number of fields before object list (17)
    Field unknown_1[3];
    String name;
    Field count;
    Field unknown_2[1];
    Field input_signal_wait_enable_mask;
    Field input_signal_wait_disable_mask;
    Field unknown_3[9];
    u32 object_count;
    Object objects[object_count];
    u32 num_fields_2; // Number of fields to footer (151)
    Field unknown_4[54];
    Field output_signal_start_enable_mask;
    Field output_signal_start_disable_mask;
    Field output_signal_end_enable_mask;
    Field output_signal_end_disable_mask;
    Field unknown_5[9];
    Field fixture_offset;
    Field unknown_6[64];
    Field output_signal_start_delay;
    Field output_signal_end_delay;
    Field input_signal_wait_enable;
    Field unknown_7[2];
    Field output_signal_start_pulse;
    Field output_signal_end_pulse;
    Field unknown_8[12];
    u32 footer;
};

struct Layers {
    u32 count;
    Layer layer[count];
};

struct File {
    Header header;
    RGBA8 thumbnail[40000]; // 200x200?
    padding[16];
    Pen pens[256];
    Layers;
};

File file @ 0x0;