From fd8ab6b4e7f4cc1617c5e042ddfc0c694bccc5f1 Mon Sep 17 00:00:00 2001
From: Jeeves <guydoodlesdev@gmail.com>
Date: Mon, 25 Mar 2024 20:11:13 -0600
Subject: [PATCH] much much much better(ish)

---
 src/main.zig | 105 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 95 insertions(+), 10 deletions(-)

diff --git a/src/main.zig b/src/main.zig
index c447b4d..8db27f1 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -158,25 +158,109 @@ pub const Listener = struct {
         }
 
         pub fn handle(self: *Router, event: *Listener.Event) !void {
-            const handlerFn = self.route(event.req.uri.path);
+            const handlerFn = try self.route(event.req.uri.path);
             try handlerFn(event);
         }
 
         pub fn addRoute(self: *Router, path: []const u8, handler: HandlerFn) !void {
-            try self.addStaticRoute(path, handler);
-        }
+            var is_static_route = true;
+            var sections = mem.splitScalar(u8, path, '/');
+            var node = &self.root_node;
+            var unnamed_placeholder_ctr: usize = 0;
+            var matched_nodes = std.ArrayList(*Node).init(self.allocator);
+            defer matched_nodes.deinit();
+            try matched_nodes.append(node);
+            while (sections.next()) |section| {
+                if (section.len == 0) continue;
+                std.debug.print("adding section {s}\n", .{section});
+                if (node.children.get(section)) |child| {
+                    node = child;
+                } else {
+                    var child_node = try Node.init(self.allocator);
+                    child_node.type = if (mem.startsWith(u8, section, "**"))
+                        .wildcard
+                    else if ((section.len > 0 and section[0] == ':') or mem.eql(u8, section, "*"))
+                        .placeholder
+                    else
+                        .normal;
+                    child_node.parent = node;
+                    try node.children.put(section, child_node);
+
+                    switch (child_node.type) {
+                        .normal => {},
+                        .wildcard => {
+                            node.wildcard_child_node = child_node;
+                            child_node.param_name = if (section.len > 3) section[3..] else "_";
+                            is_static_route = false;
+                        },
+                        .placeholder => {
+                            child_node.param_name = if (mem.eql(u8, section, "*")) blk: {
+                                const s = try std.fmt.allocPrint(self.allocator, "_{d}", .{unnamed_placeholder_ctr}); // TODO: this will leak
+                                unnamed_placeholder_ctr += 1;
+                                break :blk s;
+                            } else section[1..];
+                            try node.placeholder_children.append(child_node);
+                            is_static_route = false;
+                        },
+                    }
+
+                    try matched_nodes.append(child_node);
+                    node = child_node;
+                }
+            }
 
-        fn addStaticRoute(self: *Router, path: []const u8, handler: HandlerFn) !void {
-            const node = try Node.init(self.allocator);
             node.handler = handler;
-            try self.static_routes.put(path, node);
+
+            if (is_static_route) try self.static_routes.put(path, node);
         }
 
-        // fn addNode(self: *Router, path: []const u8) !void {}
-
-        pub fn route(self: *Router, path: []const u8) HandlerFn {
+        pub fn route(self: *Router, path: []const u8) !HandlerFn {
             if (self.static_routes.get(path)) |rt| return rt.handler;
-            if (self.root_node.wildcard_child_node) |node| return node.handler;
+
+            var params = std.StringHashMap([]const u8).init(self.allocator);
+            defer params.deinit();
+            var params_found = false;
+            var wildcard_node: ?*Node = null;
+            var node: *Node = &self.root_node;
+            var wildcard_param: ?[]const u8 = null;
+
+            // std.debug.print("{any}\n", .{node.handler});
+
+            var sections = mem.splitScalar(u8, path, '/');
+            while (sections.next()) |section| {
+                if (node.wildcard_child_node) |wildcard_child_node| {
+                    wildcard_node = wildcard_child_node;
+                    wildcard_param = sections.rest();
+                }
+
+                const next_node = node.children.get(section);
+                if (next_node) |child| {
+                    node = child;
+                    std.debug.print("found child_node {any}\n", .{child});
+                } else {
+                    var child_node: ?*Node = null;
+                    if (node.placeholder_children.items.len > 1) {
+                        // TODO
+                    } else if (node.placeholder_children.items.len == 1)
+                        child_node = node.placeholder_children.items[0];
+
+                    if (child_node) |n| {
+                        std.debug.print("didn't find child_node {any}\n", .{child_node});
+                        if (n.param_name) |name| try params.put(name, section);
+                        params_found = true;
+                        node = n;
+                    } else break;
+                }
+            }
+
+            // std.debug.print("{any}\n", .{node.handler});
+
+            if (wildcard_node) |wildcard| {
+                node = wildcard;
+                try params.put("_", wildcard_param.?);
+                params_found = true;
+            }
+
             return self.root_node.handler;
         }
 
@@ -186,6 +270,7 @@ pub const Listener = struct {
             parent: ?*Node = null,
             children: std.StringHashMap(*Node),
             handler: HandlerFn,
+            param_name: ?[]const u8 = null,
             wildcard_child_node: ?*Node = null,
             placeholder_children: std.ArrayList(*Node),