#!/usr/bin/env python3
"""
Howard, buckle the fuck up. This script parses those old-ass .rec files
from DTR, shows them in a GUI, and lets you tweak the turn strength
(or "braking" if you want to treat it that way). Then you can save the
damn thing back out.

We'll assume the file structure is:
- For each path:
  1) 4-byte int = number_of_points
  2) For each point:
     - 6 floats (24 bytes) for position/direction (x, y, z, dirX, dirY, dirZ)
     - 1 float (4 bytes) for turn_strength

We read until we run out of file data, which should typically be 2 paths,
but let's not assume that. Just keep reading as long as there's data.

Fucking disclaimers:
- This is a minimal example, so if you need advanced editing, or if your
  rec file differs, adapt it accordingly.
- For any bigger or more complex GUIs, consider using PyQt or something else.
- This is just for demonstration, so it might not be production-grade.

Shit yeah, let's do this.
"""

import struct
import tkinter as tk
from tkinter import filedialog, messagebox

class RecPathPoint:
    """Simple container for one motherfucking control point."""
    def __init__(self, x=0.0, y=0.0, z=0.0, dx=0.0, dy=0.0, dz=0.0, turn=0.0):
        self.x = x
        self.y = y
        self.z = z
        self.dx = dx
        self.dy = dy
        self.dz = dz
        self.turn = turn

class RecPath:
    """Holds all the points for one path, plus the path name or index."""
    def __init__(self, point_count=0):
        self.point_count = point_count
        self.points = []

def read_int32(f):
    """Read a 4-byte int from file (little-endian)."""
    data = f.read(4)
    if len(data) < 4:
        return None
    return struct.unpack("<i", data)[0]

def read_float32(f):
    """Read a 4-byte float from file (little-endian)."""
    data = f.read(4)
    if len(data) < 4:
        return None
    return struct.unpack("<f", data)[0]

def load_rec_file(filepath):
    """Load the .rec file, parse it into a list of RecPath objects."""
    paths = []
    with open(filepath, "rb") as f:
        while True:
            # Read path count (4-byte int)
            path_count = read_int32(f)
            if path_count is None:
                break  # No more data, bail the fuck out

            # Create a RecPath
            rec_path = RecPath(point_count=path_count)

            # Read each point
            for _ in range(path_count):
                x = read_float32(f)
                y = read_float32(f)
                z = read_float32(f)
                dx = read_float32(f)
                dy = read_float32(f)
                dz = read_float32(f)
                turn = read_float32(f)
                if None in (x, y, z, dx, dy, dz, turn):
                    # We ran out of file unexpectedly
                    break
                point = RecPathPoint(x, y, z, dx, dy, dz, turn)
                rec_path.points.append(point)

            paths.append(rec_path)

    return paths

def save_rec_file(filepath, paths):
    """Save the list of RecPath objects back to the .rec file."""
    with open(filepath, "wb") as f:
        for path in paths:
            # Write the path's point count
            f.write(struct.pack("<i", path.point_count))
            # Write each point
            for pt in path.points:
                f.write(struct.pack("<f", pt.x))
                f.write(struct.pack("<f", pt.y))
                f.write(struct.pack("<f", pt.z))
                f.write(struct.pack("<f", pt.dx))
                f.write(struct.pack("<f", pt.dy))
                f.write(struct.pack("<f", pt.dz))
                f.write(struct.pack("<f", pt.turn))

class RecEditorGUI:
    """A simple-as-shit Tkinter GUI to load/edit/save .rec paths."""
    def __init__(self, master):
        self.master = master
        self.master.title("Fucking DTR REC Editor")
        self.paths = []
        self.current_path_index = 0

        # Top frame for load/save
        top_frame = tk.Frame(master)
        top_frame.pack(pady=5)

        load_btn = tk.Button(top_frame, text="Load .rec", command=self.load_file)
        load_btn.pack(side=tk.LEFT, padx=5)

        save_btn = tk.Button(top_frame, text="Save .rec", command=self.save_file)
        save_btn.pack(side=tk.LEFT, padx=5)

        # Path selector
        self.path_var = tk.StringVar()
        self.path_menu = tk.OptionMenu(master, self.path_var, ())
        self.path_menu.pack(pady=5)

        # We’ll create a frame for the points list
        self.points_frame = tk.Frame(master)
        self.points_frame.pack(fill=tk.BOTH, expand=True)

        # We'll store an array of entry widgets so we can update them easily
        self.entry_widgets = []

        # Create a scrollable canvas for the points
        self.canvas = tk.Canvas(self.points_frame)
        self.scrollbar = tk.Scrollbar(self.points_frame, orient="vertical", command=self.canvas.yview)
        self.scrollable_frame = tk.Frame(self.canvas)

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        )

        self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=self.scrollbar.set)

        self.canvas.pack(side="left", fill="both", expand=True)
        self.scrollbar.pack(side="right", fill="y")

    def load_file(self):
        filepath = filedialog.askopenfilename(title="Open .rec File", filetypes=[("REC Files","*.rec"),("All Files","*.*")])
        if not filepath:
            return
        try:
            self.paths = load_rec_file(filepath)
            if not self.paths:
                messagebox.showerror("Error", "No paths found, you might be fucked.")
                return
            self.update_path_selector()
        except Exception as e:
            messagebox.showerror("Error", f"Failed to load .rec: {e}")

    def save_file(self):
        if not self.paths:
            messagebox.showwarning("Warning", "Load a file first, you filthy animal.")
            return
        filepath = filedialog.asksaveasfilename(title="Save .rec File", filetypes=[("REC Files","*.rec"),("All Files","*.*")], defaultextension=".rec")
        if not filepath:
            return
        # Update data from GUI to self.paths
        self.update_paths_from_gui()
        try:
            save_rec_file(filepath, self.paths)
            messagebox.showinfo("Success", "File saved. Hell yeah.")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to save .rec: {e}")

    def update_path_selector(self):
        # Clear old menu
        menu = self.path_menu["menu"]
        menu.delete(0, "end")

        for i, path in enumerate(self.paths):
            menu.add_command(label=f"Path {i} ({path.point_count} points)",
                             command=lambda idx=i: self.select_path(idx))

        # Set the first path by default
        self.current_path_index = 0
        self.path_var.set(f"Path 0 ({self.paths[0].point_count} points)")
        self.select_path(0)

    def select_path(self, idx):
        self.current_path_index = idx
        path = self.paths[idx]
        self.path_var.set(f"Path {idx} ({path.point_count} points)")
        self.display_points(path)

    def display_points(self, path):
        # Clear old widgets
        for w in self.scrollable_frame.winfo_children():
            w.destroy()
        self.entry_widgets = []

        headers = ["X", "Y", "Z", "DirX", "DirY", "DirZ", "TurnStr"]
        header_frame = tk.Frame(self.scrollable_frame)
        header_frame.pack(fill=tk.X)
        for h in headers:
            lbl = tk.Label(header_frame, text=h, width=10, anchor="w")
            lbl.pack(side=tk.LEFT, padx=2)

        for i, pt in enumerate(path.points):
            row_frame = tk.Frame(self.scrollable_frame)
            row_frame.pack(fill=tk.X)
            entries = []
            values = [pt.x, pt.y, pt.z, pt.dx, pt.dy, pt.dz, pt.turn]
            for val in values:
                e = tk.Entry(row_frame, width=10)
                e.insert(0, str(val))
                e.pack(side=tk.LEFT, padx=2)
                entries.append(e)
            self.entry_widgets.append(entries)

    def update_paths_from_gui(self):
        # Grab the current path
        path = self.paths[self.current_path_index]
        for i, entries in enumerate(self.entry_widgets):
            # Parse floats from each entry
            try:
                x = float(entries[0].get())
                y = float(entries[1].get())
                z = float(entries[2].get())
                dx = float(entries[3].get())
                dy = float(entries[4].get())
                dz = float(entries[5].get())
                turn = float(entries[6].get())
            except ValueError:
                # If there's a parse error, set default
                x, y, z, dx, dy, dz, turn = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0

            path.points[i].x = x
            path.points[i].y = y
            path.points[i].z = z
            path.points[i].dx = dx
            path.points[i].dy = dy
            path.points[i].dz = dz
            path.points[i].turn = turn

def main():
    root = tk.Tk()
    app = RecEditorGUI(root)
    root.mainloop()

if __name__ == "__main__":
    main()
