HEX
Server: Microsoft-IIS/10.0
System: Windows NT ITPWINWEBSVR22 10.0 build 20348 (Windows Server 2022) AMD64
User: www.conferencesearch.co.uk (0)
PHP: 8.3.30
Disabled: NONE
Upload Files
File: D:/web/hyperflight/apps/search-log-analysis/index-v1.asp
<%
Option Explicit
Response.Buffer = True
Response.CodePage = 65001
Response.CharSet = "utf-8"

' ======================================================================
' Search Log Analysis
' Bootstrap 5 / Classic ASP / MySQL
' ======================================================================

Const adCmdText = 1
Const adParamInput = 1
Const adVarChar = 200

Dim conn, cmd
Dim rsSummary, rsSources, rsDaily, rsTerms, rsProducts, rsVisitors, rsRecent
Dim startDate, endDate, sourceFilter, keyword, topLimit, recentLimit
Dim whereSql, sourceSql, keywordSql
Dim totalSearches, uniqueSessions, uniqueTerms
Dim incrementalSearches, productSelections, distinctProducts, selectionRate
Dim dateRangeDays, validationMessage
Dim sourceName, sourceLabel, sourceBadge, sourceCount, sourceSessions, sourceSelections
Dim sourcePercent, dayValue, searchTerm, productCode, productName
Dim searchCount, sessionCount, selectedCount, lastUsed, visitorIP
Dim eventID, sessionID, searchSource, lastUpdated
Dim dateLabel, rangeLabel

Function IsoDate(ByVal value)
    IsoDate = Year(value) & "-" & Right("0" & Month(value), 2) & "-" & Right("0" & Day(value), 2)
End Function

Function IsValidIsoDate(ByVal value)
    Dim parts, testDate
    IsValidIsoDate = False
    If Len(value) <> 10 Then Exit Function
    parts = Split(value, "-")
    If UBound(parts) <> 2 Then Exit Function
    If Not IsNumeric(parts(0)) Or Not IsNumeric(parts(1)) Or Not IsNumeric(parts(2)) Then Exit Function

    On Error Resume Next
    testDate = DateSerial(CInt(parts(0)), CInt(parts(1)), CInt(parts(2)))
    If Err.Number = 0 Then
        If Year(testDate) = CInt(parts(0)) And Month(testDate) = CInt(parts(1)) And Day(testDate) = CInt(parts(2)) Then
            IsValidIsoDate = True
        End If
    End If
    Err.Clear
    On Error GoTo 0
End Function

Function ParseIsoDate(ByVal value)
    Dim parts
    parts = Split(value, "-")
    ParseIsoDate = DateSerial(CInt(parts(0)), CInt(parts(1)), CInt(parts(2)))
End Function

Function Html(ByVal value)
    If IsNull(value) Then
        Html = ""
    Else
        Html = Server.HTMLEncode(CStr(value))
    End If
End Function

Function Number0(ByVal value)
    If IsNull(value) Or value = "" Then
        Number0 = "0"
    Else
        Number0 = FormatNumber(CDbl(value), 0)
    End If
End Function

Function SourceDescription(ByVal value)
    Select Case LCase(value)
        Case "button"
            SourceDescription = "Search button"
        Case "incremental"
            SourceDescription = "Incremental selection"
        Case "url"
            SourceDescription = "URL/query-string"
        Case Else
            SourceDescription = "Legacy"
    End Select
End Function

Function SourceBadgeClass(ByVal value)
    Select Case LCase(value)
        Case "button"
            SourceBadgeClass = "text-bg-primary"
        Case "incremental"
            SourceBadgeClass = "text-bg-success"
        Case "url"
            SourceBadgeClass = "text-bg-warning"
        Case Else
            SourceBadgeClass = "text-bg-secondary"
    End Select
End Function

Sub AddCommonParameters(ByRef commandObject, ByVal dateFrom, ByVal dateTo, ByVal searchText)
    commandObject.Parameters.Append commandObject.CreateParameter("@DateFrom", adVarChar, adParamInput, 10, dateFrom)
    commandObject.Parameters.Append commandObject.CreateParameter("@DateTo", adVarChar, adParamInput, 10, dateTo)
    If searchText <> "" Then
        commandObject.Parameters.Append commandObject.CreateParameter("@Keyword", adVarChar, adParamInput, 110, "%" & searchText & "%")
    End If
End Sub

' ----------------------------------------------------------------------
' Filters and defaults
' ----------------------------------------------------------------------
startDate = Trim(Request.QueryString("StartDate"))
endDate = Trim(Request.QueryString("EndDate"))
sourceFilter = LCase(Trim(Request.QueryString("Source")))
keyword = Trim(Request.QueryString("Keyword"))
topLimit = Trim(Request.QueryString("TopLimit"))
recentLimit = Trim(Request.QueryString("RecentLimit"))

If startDate = "" Then startDate = IsoDate(DateAdd("d", -6, Date()))
If endDate = "" Then endDate = IsoDate(Date())
If sourceFilter = "" Then sourceFilter = "human"
If topLimit = "" Or Not IsNumeric(topLimit) Then topLimit = 25
If recentLimit = "" Or Not IsNumeric(recentLimit) Then recentLimit = 100

topLimit = CInt(topLimit)
recentLimit = CInt(recentLimit)
If topLimit <> 10 And topLimit <> 25 And topLimit <> 50 And topLimit <> 100 Then topLimit = 25
If recentLimit <> 50 And recentLimit <> 100 And recentLimit <> 250 And recentLimit <> 500 Then recentLimit = 100

Select Case sourceFilter
    Case "human", "all", "legacy", "button", "incremental", "url"
        ' Valid.
    Case Else
        sourceFilter = "human"
End Select

validationMessage = ""
If Not IsValidIsoDate(startDate) Or Not IsValidIsoDate(endDate) Then
    validationMessage = "Please enter valid start and end dates."
ElseIf ParseIsoDate(startDate) > ParseIsoDate(endDate) Then
    validationMessage = "The start date must not be later than the end date."
Else
    dateRangeDays = DateDiff("d", ParseIsoDate(startDate), ParseIsoDate(endDate)) + 1
    If dateRangeDays > 366 Then
        validationMessage = "Please select a date range of 366 days or fewer."
    End If
End If

sourceSql = ""
Select Case sourceFilter
    Case "human"
        sourceSql = " AND sl.SearchSource IN ('legacy','button','incremental') "
    Case "legacy", "button", "incremental", "url"
        sourceSql = " AND sl.SearchSource = '" & sourceFilter & "' "
End Select

keywordSql = ""
If keyword <> "" Then keywordSql = " AND sl.Search LIKE ? "

whereSql = " WHERE sl.LastUpdated >= ? " & _
           "AND sl.LastUpdated < DATE_ADD(?, INTERVAL 1 DAY) " & _
           "AND TRIM(IFNULL(sl.Search, '')) <> '' " & _
           sourceSql & keywordSql

rangeLabel = startDate & " to " & endDate

' ----------------------------------------------------------------------
' Run report queries
' ----------------------------------------------------------------------
If validationMessage = "" Then
    Set conn = Server.CreateObject("ADODB.Connection")
    conn.Open "DSN=MySQL_hyperflight;"

    ' Summary
    Set cmd = Server.CreateObject("ADODB.Command")
    Set cmd.ActiveConnection = conn
    cmd.CommandType = adCmdText
    cmd.CommandText = _
        "SELECT " & _
        "COUNT(*) AS TotalSearches, " & _
        "COUNT(DISTINCT sl.SessionID) AS UniqueSessions, " & _
        "COUNT(DISTINCT TRIM(sl.Search)) AS UniqueTerms, " & _
        "SUM(CASE WHEN sl.SearchSource = 'incremental' THEN 1 ELSE 0 END) AS IncrementalSearches, " & _
        "SUM(CASE WHEN sl.ProductCode IS NOT NULL AND sl.ProductCode <> '' THEN 1 ELSE 0 END) AS ProductSelections, " & _
        "COUNT(DISTINCT CASE WHEN sl.ProductCode IS NOT NULL AND sl.ProductCode <> '' THEN sl.ProductCode END) AS DistinctProducts " & _
        "FROM searchlog sl " & whereSql
    AddCommonParameters cmd, startDate, endDate, keyword
    Set rsSummary = cmd.Execute()

    totalSearches = 0
    uniqueSessions = 0
    uniqueTerms = 0
    incrementalSearches = 0
    productSelections = 0
    distinctProducts = 0

    If Not rsSummary.EOF Then
        If Not IsNull(rsSummary("TotalSearches")) Then totalSearches = CLng(rsSummary("TotalSearches"))
        If Not IsNull(rsSummary("UniqueSessions")) Then uniqueSessions = CLng(rsSummary("UniqueSessions"))
        If Not IsNull(rsSummary("UniqueTerms")) Then uniqueTerms = CLng(rsSummary("UniqueTerms"))
        If Not IsNull(rsSummary("IncrementalSearches")) Then incrementalSearches = CLng(rsSummary("IncrementalSearches"))
        If Not IsNull(rsSummary("ProductSelections")) Then productSelections = CLng(rsSummary("ProductSelections"))
        If Not IsNull(rsSummary("DistinctProducts")) Then distinctProducts = CLng(rsSummary("DistinctProducts"))
    End If
    rsSummary.Close
    Set rsSummary = Nothing
    Set cmd = Nothing

    selectionRate = 0
    If incrementalSearches > 0 Then selectionRate = (productSelections / incrementalSearches) * 100

    ' Source breakdown
    Set cmd = Server.CreateObject("ADODB.Command")
    Set cmd.ActiveConnection = conn
    cmd.CommandType = adCmdText
    cmd.CommandText = _
        "SELECT sl.SearchSource, COUNT(*) AS SearchCount, " & _
        "COUNT(DISTINCT sl.SessionID) AS SessionCount, " & _
        "SUM(CASE WHEN sl.ProductCode IS NOT NULL AND sl.ProductCode <> '' THEN 1 ELSE 0 END) AS SelectedCount " & _
        "FROM searchlog sl " & whereSql & _
        "GROUP BY sl.SearchSource ORDER BY SearchCount DESC"
    AddCommonParameters cmd, startDate, endDate, keyword
    Set rsSources = cmd.Execute()
    Set cmd = Nothing

    ' Daily activity
    Set cmd = Server.CreateObject("ADODB.Command")
    Set cmd.ActiveConnection = conn
    cmd.CommandType = adCmdText
    cmd.CommandText = _
        "SELECT DATE(sl.LastUpdated) AS SearchDate, COUNT(*) AS SearchCount, " & _
        "COUNT(DISTINCT sl.SessionID) AS SessionCount, " & _
        "SUM(CASE WHEN sl.ProductCode IS NOT NULL AND sl.ProductCode <> '' THEN 1 ELSE 0 END) AS SelectedCount " & _
        "FROM searchlog sl " & whereSql & _
        "GROUP BY DATE(sl.LastUpdated) ORDER BY SearchDate DESC"
    AddCommonParameters cmd, startDate, endDate, keyword
    Set rsDaily = cmd.Execute()
    Set cmd = Nothing

    ' Top search terms
    Set cmd = Server.CreateObject("ADODB.Command")
    Set cmd.ActiveConnection = conn
    cmd.CommandType = adCmdText
    cmd.CommandText = _
        "SELECT TRIM(sl.Search) AS SearchTerm, COUNT(*) AS SearchCount, " & _
        "COUNT(DISTINCT sl.SessionID) AS SessionCount, " & _
        "SUM(CASE WHEN sl.ProductCode IS NOT NULL AND sl.ProductCode <> '' THEN 1 ELSE 0 END) AS SelectedCount, " & _
        "MAX(sl.LastUpdated) AS LastUsed " & _
        "FROM searchlog sl " & whereSql & _
        "GROUP BY TRIM(sl.Search) " & _
        "ORDER BY SearchCount DESC, SessionCount DESC, SearchTerm ASC " & _
        "LIMIT " & topLimit
    AddCommonParameters cmd, startDate, endDate, keyword
    Set rsTerms = cmd.Execute()
    Set cmd = Nothing

    ' Most selected products
    Set cmd = Server.CreateObject("ADODB.Command")
    Set cmd.ActiveConnection = conn
    cmd.CommandType = adCmdText
    cmd.CommandText = _
        "SELECT sl.ProductCode, MAX(p.ProductName) AS ProductName, COUNT(*) AS SearchCount, " & _
        "COUNT(DISTINCT sl.SessionID) AS SessionCount, MAX(sl.LastUpdated) AS LastUsed " & _
        "FROM searchlog sl " & _
        "LEFT JOIN products p ON p.ProductCode = sl.ProductCode " & _
        whereSql & _
        "AND sl.ProductCode IS NOT NULL AND sl.ProductCode <> '' " & _
        "GROUP BY sl.ProductCode " & _
        "ORDER BY SearchCount DESC, sl.ProductCode ASC " & _
        "LIMIT " & topLimit
    AddCommonParameters cmd, startDate, endDate, keyword
    Set rsProducts = cmd.Execute()
    Set cmd = Nothing

    ' Highest-volume visitor IPs
    Set cmd = Server.CreateObject("ADODB.Command")
    Set cmd.ActiveConnection = conn
    cmd.CommandType = adCmdText
    cmd.CommandText = _
        "SELECT IFNULL(NULLIF(sl.VisitorIP, ''), '(blank)') AS VisitorIP, COUNT(*) AS SearchCount, " & _
        "COUNT(DISTINCT sl.SessionID) AS SessionCount, " & _
        "COUNT(DISTINCT TRIM(sl.Search)) AS UniqueTerms, MAX(sl.LastUpdated) AS LastUsed " & _
        "FROM searchlog sl " & whereSql & _
        "GROUP BY IFNULL(NULLIF(sl.VisitorIP, ''), '(blank)') " & _
        "ORDER BY SearchCount DESC, VisitorIP ASC LIMIT " & topLimit
    AddCommonParameters cmd, startDate, endDate, keyword
    Set rsVisitors = cmd.Execute()
    Set cmd = Nothing

    ' Recent detail
    Set cmd = Server.CreateObject("ADODB.Command")
    Set cmd.ActiveConnection = conn
    cmd.CommandType = adCmdText
    cmd.CommandText = _
        "SELECT sl.ID, sl.LastUpdated, sl.SearchSource, sl.Search, sl.ProductCode, " & _
        "sl.SessionID, sl.VisitorIP, p.ProductName " & _
        "FROM searchlog sl " & _
        "LEFT JOIN products p ON p.ProductCode = sl.ProductCode " & _
        whereSql & _
        "ORDER BY sl.LastUpdated DESC, sl.ID DESC LIMIT " & recentLimit
    AddCommonParameters cmd, startDate, endDate, keyword
    Set rsRecent = cmd.Execute()
    Set cmd = Nothing
End If
%>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Search Log Analysis</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body { background: #f5f6f8; }
        .report-wrap { max-width: 1500px; }
        .metric-value { font-size: 1.8rem; font-weight: 700; line-height: 1.1; }
        .metric-label { color: #6c757d; font-size: 0.9rem; }
        .table th { white-space: nowrap; }
        .search-text { min-width: 260px; max-width: 620px; overflow-wrap: anywhere; }
        .product-name { min-width: 240px; }
        .small-note { font-size: 0.875rem; color: #6c757d; }
        .source-progress { min-width: 170px; }
        .sticky-table-head thead th { position: sticky; top: 0; z-index: 2; }
        .card-header h2 { font-size: 1.05rem; margin: 0; }
    </style>
</head>
<body class="pb-5">
<div class="container-fluid report-wrap py-4 px-3 px-lg-4">

    <div class="card shadow-sm mb-4">
        <div class="card-header bg-primary text-white py-3">
            <div class="d-flex flex-column flex-lg-row justify-content-between gap-2 align-items-lg-center">
                <div>
                    <h1 class="h4 mb-1">Search Log Analysis</h1>
                    <div class="small opacity-75">Search behaviour, source usage and incremental product selections</div>
                </div>
                <span class="badge text-bg-light"><%=Html(rangeLabel)%></span>
            </div>
        </div>
        <div class="card-body">
            <form method="get" action="" class="row g-3 align-items-end">
                <div class="col-sm-6 col-lg-2">
                    <label for="StartDate" class="form-label fw-semibold">Start date</label>
                    <input type="date" class="form-control" id="StartDate" name="StartDate" value="<%=Html(startDate)%>" required>
                </div>
                <div class="col-sm-6 col-lg-2">
                    <label for="EndDate" class="form-label fw-semibold">End date</label>
                    <input type="date" class="form-control" id="EndDate" name="EndDate" value="<%=Html(endDate)%>" required>
                </div>
                <div class="col-sm-6 col-lg-2">
                    <label for="Source" class="form-label fw-semibold">Search source</label>
                    <select class="form-select" id="Source" name="Source">
                        <option value="human" <% If sourceFilter = "human" Then Response.Write "selected" %>>Non-URL searches</option>
                        <option value="all" <% If sourceFilter = "all" Then Response.Write "selected" %>>All sources</option>
                        <option value="button" <% If sourceFilter = "button" Then Response.Write "selected" %>>Search button</option>
                        <option value="incremental" <% If sourceFilter = "incremental" Then Response.Write "selected" %>>Incremental selection</option>
                        <option value="legacy" <% If sourceFilter = "legacy" Then Response.Write "selected" %>>Legacy</option>
                        <option value="url" <% If sourceFilter = "url" Then Response.Write "selected" %>>URL/query-string</option>
                    </select>
                </div>
                <div class="col-sm-6 col-lg-3">
                    <label for="Keyword" class="form-label fw-semibold">Search contains</label>
                    <input type="search" class="form-control" id="Keyword" name="Keyword" value="<%=Html(keyword)%>" maxlength="100" placeholder="Optional term">
                </div>
                <div class="col-sm-6 col-lg-1">
                    <label for="TopLimit" class="form-label fw-semibold">Top</label>
                    <select class="form-select" id="TopLimit" name="TopLimit">
                        <option value="10" <% If topLimit = 10 Then Response.Write "selected" %>>10</option>
                        <option value="25" <% If topLimit = 25 Then Response.Write "selected" %>>25</option>
                        <option value="50" <% If topLimit = 50 Then Response.Write "selected" %>>50</option>
                        <option value="100" <% If topLimit = 100 Then Response.Write "selected" %>>100</option>
                    </select>
                </div>
                <div class="col-sm-6 col-lg-2 d-grid">
                    <input type="hidden" name="RecentLimit" value="<%=recentLimit%>">
                    <button type="submit" class="btn btn-primary fw-semibold">Run report</button>
                </div>
            </form>
        </div>
    </div>

    <% If validationMessage <> "" Then %>
        <div class="alert alert-warning"><%=Html(validationMessage)%></div>
    <% Else %>

        <% If sourceFilter = "all" Or sourceFilter = "url" Then %>
            <div class="alert alert-warning shadow-sm">
                <strong>URL searches need separate interpretation.</strong>
                The sample data shows that many are crawler-generated or unrelated query-string requests, so they should not normally be treated as customer search demand.
            </div>
        <% End If %>

        <div class="alert alert-info shadow-sm">
            <strong>Data note:</strong> Search source and selected product tracking were added on 23 July 2026. Earlier records may therefore appear as <em>legacy</em>, and product selection rates are most meaningful from that date onward.
        </div>

        <div class="row g-3 mb-4">
            <div class="col-6 col-xl">
                <div class="card shadow-sm h-100"><div class="card-body">
                    <div class="metric-value"><%=Number0(totalSearches)%></div>
                    <div class="metric-label">Search events</div>
                </div></div>
            </div>
            <div class="col-6 col-xl">
                <div class="card shadow-sm h-100"><div class="card-body">
                    <div class="metric-value"><%=Number0(uniqueSessions)%></div>
                    <div class="metric-label">Sessions</div>
                </div></div>
            </div>
            <div class="col-6 col-xl">
                <div class="card shadow-sm h-100"><div class="card-body">
                    <div class="metric-value"><%=Number0(uniqueTerms)%></div>
                    <div class="metric-label">Distinct terms</div>
                </div></div>
            </div>
            <div class="col-6 col-xl">
                <div class="card shadow-sm h-100"><div class="card-body">
                    <div class="metric-value"><%=Number0(productSelections)%></div>
                    <div class="metric-label">Product selections</div>
                </div></div>
            </div>
            <div class="col-6 col-xl">
                <div class="card shadow-sm h-100"><div class="card-body">
                    <div class="metric-value"><%=Number0(distinctProducts)%></div>
                    <div class="metric-label">Products selected</div>
                </div></div>
            </div>
            <div class="col-6 col-xl">
                <div class="card shadow-sm h-100"><div class="card-body">
                    <div class="metric-value"><%=FormatNumber(selectionRate, 1)%>%</div>
                    <div class="metric-label">Incremental selection rate</div>
                </div></div>
            </div>
        </div>

        <div class="row g-4 mb-4">
            <div class="col-xl-6">
                <div class="card shadow-sm h-100">
                    <div class="card-header bg-dark text-white"><h2>Search source breakdown</h2></div>
                    <div class="table-responsive">
                        <table class="table table-hover align-middle mb-0">
                            <thead class="table-light">
                                <tr><th>Source</th><th class="text-end">Searches</th><th class="text-end">Sessions</th><th class="text-end">Selections</th><th class="source-progress">Share</th></tr>
                            </thead>
                            <tbody>
                            <% If rsSources.EOF Then %>
                                <tr><td colspan="5" class="text-center text-muted py-4">No searches found.</td></tr>
                            <% Else %>
                                <% Do While Not rsSources.EOF
                                    sourceName = rsSources("SearchSource") & ""
                                    sourceCount = CLng(rsSources("SearchCount"))
                                    sourceSessions = CLng(rsSources("SessionCount"))
                                    sourceSelections = 0
                                    If Not IsNull(rsSources("SelectedCount")) Then sourceSelections = CLng(rsSources("SelectedCount"))
                                    sourcePercent = 0
                                    If totalSearches > 0 Then sourcePercent = CInt((sourceCount / totalSearches) * 100)
                                %>
                                <tr>
                                    <td><span class="badge <%=SourceBadgeClass(sourceName)%>"><%=Html(SourceDescription(sourceName))%></span></td>
                                    <td class="text-end"><%=Number0(sourceCount)%></td>
                                    <td class="text-end"><%=Number0(sourceSessions)%></td>
                                    <td class="text-end"><%=Number0(sourceSelections)%></td>
                                    <td>
                                        <div class="progress" role="progressbar" aria-label="Source share" aria-valuenow="<%=sourcePercent%>" aria-valuemin="0" aria-valuemax="100">
                                            <div class="progress-bar" style="width: <%=sourcePercent%>%"><%=sourcePercent%>%</div>
                                        </div>
                                    </td>
                                </tr>
                                <% rsSources.MoveNext : Loop %>
                            <% End If %>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>

            <div class="col-xl-6">
                <div class="card shadow-sm h-100">
                    <div class="card-header bg-dark text-white"><h2>Daily activity</h2></div>
                    <div class="table-responsive" style="max-height: 360px;">
                        <table class="table table-hover mb-0 sticky-table-head">
                            <thead class="table-light"><tr><th>Date</th><th class="text-end">Searches</th><th class="text-end">Sessions</th><th class="text-end">Selections</th></tr></thead>
                            <tbody>
                            <% If rsDaily.EOF Then %>
                                <tr><td colspan="4" class="text-center text-muted py-4">No daily activity found.</td></tr>
                            <% Else %>
                                <% Do While Not rsDaily.EOF %>
                                <tr>
                                    <td><%=Html(rsDaily("SearchDate"))%></td>
                                    <td class="text-end"><%=Number0(rsDaily("SearchCount"))%></td>
                                    <td class="text-end"><%=Number0(rsDaily("SessionCount"))%></td>
                                    <td class="text-end"><%=Number0(rsDaily("SelectedCount"))%></td>
                                </tr>
                                <% rsDaily.MoveNext : Loop %>
                            <% End If %>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>

        <div class="row g-4 mb-4">
            <div class="col-xl-7">
                <div class="card shadow-sm h-100">
                    <div class="card-header bg-primary text-white"><h2>Top search terms</h2></div>
                    <div class="table-responsive">
                        <table class="table table-striped table-hover align-middle mb-0">
                            <thead class="table-light"><tr><th>#</th><th>Search term</th><th class="text-end">Searches</th><th class="text-end">Sessions</th><th class="text-end">Selections</th><th>Last used</th></tr></thead>
                            <tbody>
                            <% If rsTerms.EOF Then %>
                                <tr><td colspan="6" class="text-center text-muted py-4">No search terms found.</td></tr>
                            <% Else %>
                                <% Dim termPosition : termPosition = 0
                                   Do While Not rsTerms.EOF
                                    termPosition = termPosition + 1
                                %>
                                <tr>
                                    <td class="text-muted"><%=termPosition%></td>
                                    <td class="search-text fw-semibold"><%=Html(rsTerms("SearchTerm"))%></td>
                                    <td class="text-end"><%=Number0(rsTerms("SearchCount"))%></td>
                                    <td class="text-end"><%=Number0(rsTerms("SessionCount"))%></td>
                                    <td class="text-end"><%=Number0(rsTerms("SelectedCount"))%></td>
                                    <td class="text-nowrap"><%=Html(rsTerms("LastUsed"))%></td>
                                </tr>
                                <% rsTerms.MoveNext : Loop %>
                            <% End If %>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>

            <div class="col-xl-5">
                <div class="card shadow-sm h-100">
                    <div class="card-header bg-success text-white"><h2>Most selected products</h2></div>
                    <div class="table-responsive">
                        <table class="table table-striped table-hover align-middle mb-0">
                            <thead class="table-light"><tr><th>Product</th><th class="text-end">Selections</th><th class="text-end">Sessions</th><th>Last selected</th></tr></thead>
                            <tbody>
                            <% If rsProducts.EOF Then %>
                                <tr><td colspan="4" class="text-center text-muted py-4">No incremental product selections found.</td></tr>
                            <% Else %>
                                <% Do While Not rsProducts.EOF
                                    productCode = rsProducts("ProductCode") & ""
                                    productName = rsProducts("ProductName") & ""
                                %>
                                <tr>
                                    <td>
                                        <a href="/products.asp?code=<%=Server.URLEncode(productCode)%>" target="_blank" rel="noopener" class="fw-semibold"><%=Html(productCode)%></a>
                                        <% If productName <> "" Then %><div class="small text-muted product-name"><%=Html(productName)%></div><% End If %>
                                    </td>
                                    <td class="text-end"><%=Number0(rsProducts("SearchCount"))%></td>
                                    <td class="text-end"><%=Number0(rsProducts("SessionCount"))%></td>
                                    <td class="text-nowrap"><%=Html(rsProducts("LastUsed"))%></td>
                                </tr>
                                <% rsProducts.MoveNext : Loop %>
                            <% End If %>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>

        <div class="card shadow-sm mb-4">
            <div class="card-header bg-secondary text-white"><h2>Highest-volume visitor IPs</h2></div>
            <div class="table-responsive">
                <table class="table table-hover align-middle mb-0">
                    <thead class="table-light"><tr><th>Visitor IP</th><th class="text-end">Searches</th><th class="text-end">Sessions</th><th class="text-end">Distinct terms</th><th>Last used</th></tr></thead>
                    <tbody>
                    <% If rsVisitors.EOF Then %>
                        <tr><td colspan="5" class="text-center text-muted py-4">No visitor IP data found.</td></tr>
                    <% Else %>
                        <% Do While Not rsVisitors.EOF %>
                        <tr>
                            <td class="font-monospace"><%=Html(rsVisitors("VisitorIP"))%></td>
                            <td class="text-end"><%=Number0(rsVisitors("SearchCount"))%></td>
                            <td class="text-end"><%=Number0(rsVisitors("SessionCount"))%></td>
                            <td class="text-end"><%=Number0(rsVisitors("UniqueTerms"))%></td>
                            <td class="text-nowrap"><%=Html(rsVisitors("LastUsed"))%></td>
                        </tr>
                        <% rsVisitors.MoveNext : Loop %>
                    <% End If %>
                    </tbody>
                </table>
            </div>
        </div>

        <div class="card shadow-sm">
            <div class="card-header bg-dark text-white">
                <div class="d-flex flex-wrap justify-content-between align-items-center gap-2">
                    <h2>Recent search detail</h2>
                    <form method="get" action="" class="d-flex align-items-center gap-2">
                        <input type="hidden" name="StartDate" value="<%=Html(startDate)%>">
                        <input type="hidden" name="EndDate" value="<%=Html(endDate)%>">
                        <input type="hidden" name="Source" value="<%=Html(sourceFilter)%>">
                        <input type="hidden" name="Keyword" value="<%=Html(keyword)%>">
                        <input type="hidden" name="TopLimit" value="<%=topLimit%>">
                        <label for="RecentLimit" class="small text-nowrap">Rows:</label>
                        <select class="form-select form-select-sm" id="RecentLimit" name="RecentLimit" onchange="this.form.submit()">
                            <option value="50" <% If recentLimit = 50 Then Response.Write "selected" %>>50</option>
                            <option value="100" <% If recentLimit = 100 Then Response.Write "selected" %>>100</option>
                            <option value="250" <% If recentLimit = 250 Then Response.Write "selected" %>>250</option>
                            <option value="500" <% If recentLimit = 500 Then Response.Write "selected" %>>500</option>
                        </select>
                    </form>
                </div>
            </div>
            <div class="table-responsive" style="max-height: 720px;">
                <table class="table table-striped table-hover align-middle mb-0 sticky-table-head">
                    <thead class="table-light">
                        <tr><th>Date/time</th><th>Source</th><th>Search</th><th>Selected product</th><th>Session</th><th>Visitor IP</th></tr>
                    </thead>
                    <tbody>
                    <% If rsRecent.EOF Then %>
                        <tr><td colspan="6" class="text-center text-muted py-4">No searches found.</td></tr>
                    <% Else %>
                        <% Do While Not rsRecent.EOF
                            searchSource = rsRecent("SearchSource") & ""
                            productCode = rsRecent("ProductCode") & ""
                            productName = rsRecent("ProductName") & ""
                        %>
                        <tr>
                            <td class="text-nowrap"><%=Html(rsRecent("LastUpdated"))%></td>
                            <td><span class="badge <%=SourceBadgeClass(searchSource)%>"><%=Html(SourceDescription(searchSource))%></span></td>
                            <td class="search-text"><%=Html(rsRecent("Search"))%></td>
                            <td>
                                <% If productCode <> "" Then %>
                                    <a href="/products.asp?code=<%=Server.URLEncode(productCode)%>" target="_blank" rel="noopener" class="fw-semibold"><%=Html(productCode)%></a>
                                    <% If productName <> "" Then %><div class="small text-muted"><%=Html(productName)%></div><% End If %>
                                <% Else %>
                                    <span class="text-muted">—</span>
                                <% End If %>
                            </td>
                            <td class="font-monospace"><%=Html(rsRecent("SessionID"))%></td>
                            <td class="font-monospace"><%=Html(rsRecent("VisitorIP"))%></td>
                        </tr>
                        <% rsRecent.MoveNext : Loop %>
                    <% End If %>
                    </tbody>
                </table>
            </div>
        </div>

        <div class="small-note mt-3">
            Incremental selection rate is calculated as product selections divided by incremental search events. This report cannot currently identify searches returning no results because result count is not stored in <code>searchlog</code>.
        </div>

    <%
        rsSources.Close : Set rsSources = Nothing
        rsDaily.Close : Set rsDaily = Nothing
        rsTerms.Close : Set rsTerms = Nothing
        rsProducts.Close : Set rsProducts = Nothing
        rsVisitors.Close : Set rsVisitors = Nothing
        rsRecent.Close : Set rsRecent = Nothing
        conn.Close : Set conn = Nothing
    End If
    %>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>