<?xml version="1.0"?>
<!--  RouterComponent.wsc  -->
<component>

  <!-- COM registration -->
  <registration
      description = "Classic ASP Router Component"
      progid      = "App.Router"
      version     = "1.0"
      classid     = "{A1FC6EA8-519E-4E34-AC08-77788E3E5E44}" />

  <!-- Public interface -->
  <public>
    <method name="AddRoute"/>
    <method name="Resolve"/>
  </public>
  <!-- Give the component ASP intrinsic objects (Request, Response, Server …) -->
  <implements type="ASP"/>
  <!-- Implementation -->
  <script language="VBScript">
  <![CDATA[
Option Explicit

'------------------------------------------------------------
' Private state
'------------------------------------------------------------
Dim routes : Set routes = CreateObject("Scripting.Dictionary")

'------------------------------------------------------------
' METHOD  AddRoute(method, path, controller, action)
'------------------------------------------------------------
Public Sub AddRoute(method, path, controller, action)
    ' Input validation
    If IsEmpty(method) Or Len(Trim(method)) = 0 Then
        Err.Raise 5, "Router.AddRoute", "HTTP method parameter is required and cannot be empty"
    End If

    If IsEmpty(path) Then
        Err.Raise 5, "Router.AddRoute", "Path parameter is required"
    End If

    If IsEmpty(controller) Or Len(Trim(controller)) = 0 Then
        Err.Raise 5, "Router.AddRoute", "Controller parameter is required and cannot be empty"
    End If

    If IsEmpty(action) Or Len(Trim(action)) = 0 Then
        Err.Raise 5, "Router.AddRoute", "Action parameter is required and cannot be empty"
    End If

    ' Validate HTTP method (allow common methods)
    Dim validMethods, methodUpper, i, isValidMethod
    validMethods = Array("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS")
    methodUpper = UCase(Trim(method))
    isValidMethod = False

    For i = 0 To UBound(validMethods)
        If validMethods(i) = methodUpper Then
            isValidMethod = True
            Exit For
        End If
    Next

    If Not isValidMethod Then
        Err.Raise 5, "Router.AddRoute", "Invalid HTTP method: " & method & ". Allowed: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS"
    End If

    Dim routeKey
    routeKey = methodUpper & ":" & LCase(Trim(path))

    If Not routes.Exists(routeKey) Then
        routes.Add routeKey, Array(Trim(controller), Trim(action))
    End If
End Sub

'------------------------------------------------------------
' METHOD  Resolve(method, path) -> Array(controller, action, params())
'------------------------------------------------------------
Public Function Resolve(method, path)
    Dim routeKey, routeValue, values
    routeKey = UCase(method) & ":" & LCase(path)

    ' Always return a params array (empty by default)
    Dim emptyParams() : ReDim emptyParams(-1)

    ' Exact match first
    If routes.Exists(routeKey) Then
        routeValue = routes(routeKey)
        Resolve = Array(routeValue(0), routeValue(1), emptyParams)
        Exit Function
    End If

    ' Dynamic routes  (e.g. /users/:id)
    Dim r, routeMethod, routePattern
    For Each r In routes.Keys
        routeMethod  = Split(r, ":")(0)
        routePattern = Mid(r, Len(routeMethod) + 2) ' strip "METHOD:"
        If UCase(routeMethod) = UCase(method) Then
            If IsMatch(path, routePattern, values) Then
                routeValue = routes(r)
                Resolve = Array(routeValue(0), routeValue(1), values)
                Exit Function
            End If
        End If
    Next

    ' 404 fallback
    Resolve = Array("ErrorController", "NotFound", emptyParams)
End Function

'------------------------------------------------------------
' INTERNAL  IsMatch(requestPath, routePattern, values())
'           Returns True/False and fills values() with parameters
'------------------------------------------------------------
Private Function IsMatch(requestPath, routePattern, values)
    Dim reqParts, routeParts, i, paramCount
    reqParts   = Split(requestPath, "/")
    routeParts = Split(routePattern, "/")

    If UBound(reqParts) <> UBound(routeParts) Then
        IsMatch = False : Exit Function
    End If

    paramCount = 0 : ReDim values(-1)

    For i = 0 To UBound(reqParts)
        If Left(routeParts(i), 1) = ":" Then
            ReDim Preserve values(paramCount)
            values(paramCount) = reqParts(i)
            paramCount = paramCount + 1
        ElseIf LCase(routeParts(i)) <> LCase(reqParts(i)) Then
            IsMatch = False : Exit Function
        End If
    Next

    If paramCount = 0 Then ReDim values(-1)
    IsMatch = True
End Function

'------------------------------------------------------------
' Optional lifecycle hooks
'------------------------------------------------------------
Private Sub Class_Terminate()
    Set routes = Nothing
End Sub
  ]]>
  </script>
</component>
