aboutsummaryrefslogtreecommitdiffstats
path: root/src/tmview/output.py
blob: 95dc471a31868aabdee341db299114a0af42806c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import json
import sys
from rich.console import Console
from rich.table import Table
from rich import box

console = Console()

STATUS_COLORS = {
    "registered": "green",
    "filed": "yellow",
    "pending": "yellow",
    "expired": "red",
    "refused": "red",
    "withdrawn": "dim",
}

TYPE_ABBREV = {
    "WORD": "Word",
    "FIGURATIVE": "Fig.",
    "COMBINED": "Combined",
    "3D": "3D",
    "COLOUR": "Colour",
    "SOUND": "Sound",
    "OTHER": "Other",
}


def _status_markup(status):
    key = (status or "").lower()
    color = STATUS_COLORS.get(key, "white")
    return f"[{color}]{status or '—'}[/{color}]"


def _truncate(text, width):
    text = text or "—"
    if len(text) > width:
        return text[: width - 1] + "…"
    return text


def _format_fetched(iso: str) -> str:
    if not iso:
        return "—"
    # Compact: "2026-02-24 10:30 UTC"
    try:
        ts = iso.replace("T", " ").replace("Z", "")
        return f"[dim]{ts} UTC[/dim]"
    except Exception:
        return f"[dim]{iso}[/dim]"


def print_table(result, query, verbose=False, image_path=None):
    trademarks = result["trademarks"]
    total = result["total"]
    page = result["page"]
    fetched_at = result.get("fetched_at", "")

    if image_path:
        from pathlib import Path
        header = f'Similar logos to "{Path(image_path).name}" — {total:,} result{"s" if total != 1 else ""} (page {page})'
    else:
        header = f'Trademark Search: "{query}" — {total:,} result{"s" if total != 1 else ""} (page {page})'
    console.print(f"\n[bold]{header}[/bold]\n")

    if not trademarks:
        console.print(f'[yellow]No trademarks found for "{query}"[/yellow]')
        return

    table = Table(box=box.ROUNDED, show_lines=False, highlight=False)
    table.add_column("Origin", width=12, no_wrap=True)
    table.add_column("Name", width=30)
    table.add_column("Status", width=14, no_wrap=True)
    table.add_column("Type", width=10, no_wrap=True)
    table.add_column("Owner", width=28)
    table.add_column("Classes", width=12, no_wrap=True)
    table.add_column("Applied", width=12, no_wrap=True)
    table.add_column("App #", width=14, no_wrap=True)
    if verbose:
        table.add_column("Fetched", width=20, no_wrap=True)

    fetched_cell = _format_fetched(fetched_at)

    for tm in trademarks:
        code = tm.get("office", "")
        name_label = tm.get("office_name", code) or code
        origin = f"[bold]{code}[/bold] {name_label}" if code else "—"

        tm_name = f"[cyan]{_truncate(tm.get('name'), 29)}[/cyan]"
        status = _status_markup(tm.get("status"))
        tm_type = TYPE_ABBREV.get((tm.get("type") or "").upper(), tm.get("type") or "—")
        owner = _truncate(tm.get("owner"), 27)
        classes_raw = tm.get("classes") or []
        classes = ", ".join(str(c) for c in classes_raw) if classes_raw else "—"
        applied = tm.get("application_date") or "—"
        app_num = tm.get("application_number") or "—"

        row = [origin, tm_name, status, tm_type, owner, classes, applied, app_num]
        if verbose:
            row.append(fetched_cell)
        table.add_row(*row)

    console.print(table)


def print_json(result):
    json.dump(result["trademarks"], sys.stdout, indent=2, default=str)
    sys.stdout.write("\n")