#!/usr/bin/env python3
# $Id: ppnetlist 154 2026-10-06 06:41:51Z peter $
#
# ppnetlist --- the CLI entry point for netlist.py's own library
# functions. ADDED 2026-08-26, per Péter's own direct preference: no
# extension on executable files, and a project-specific "pp" prefix
# to avoid colliding with other tools' own common names (e.g. a
# generic "render" already existing on many systems).
#
# Split out from netlist.py itself (which keeps this CLI's own
# functions available to import, unchanged, for every other real
# module in this project that needs them: auto_layout.py,
# build_instructions.py, footprint.py, render.py, visualize.py, and
# both test scripts) rather than renaming netlist.py's own file
# directly: Python's own import statement needs a real ".py"
# extension to resolve `import netlist`, and netlist.py is
# genuinely BOTH a real CLI tool (this file) and a real, densely
# cross-imported library module -- splitting the two apart cleanly
# is a real, defensible improvement on its own terms (a library's
# own public API shouldn't depend on its own CLI-parsing code), not
# only a workaround for this naming preference.
#
# See netlist.py itself for the real, full account of what this
# project's own netlist support does and why.

import os
import sys
from netlist import load_netlist


def _version():
    """This project's own current Dewey-decimal version, read from
    VERSION -- CLI-specific (only ever used by --version), so it
    lives here, in the CLI entry point, not in netlist.py's own
    library code, which has no real need to know its own version at
    all. Duplicated across every one of this project's own pp*
    entry points rather than factored into a shared module -- see
    render.py's own identical helper for the fuller reasoning."""
    here = os.path.dirname(os.path.abspath(__file__))
    try:
        with open(os.path.join(here, "VERSION")) as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith("#"):
                    return line
    except OSError:
        pass
    return "unknown"


def main(argv=None):
    """CLI entry point, ADDED 2026-08-18 (replacing the previous
    positional-only argv[1] check) as this project's own first real
    application of DevelopmentStandard.org's own "Options and
    Arguments" rule (GNU getopt_long-equivalent parsing; version,
    help, debug, quiet as the minimal option set) to one of its own
    Python tools -- see ppnetlist.1 (this program's own manual page,
    renamed alongside this file itself) and FutureResearch.org for
    why netlist.py specifically was chosen to go first (this
    module's own real, narrow, single-purpose scope), and what's
    still open for the rest.

    MOVED 2026-08-26 from netlist.py's own file into this new,
    separate, extensionless CLI entry point -- unchanged otherwise."""
    import argparse

    parser = argparse.ArgumentParser(
        prog="ppnetlist",
        description="Load a KiCad netlist export (kicad-cli sch export "
                     "netlist --format kicadsexpr) and print its "
                     "components and nets in a plain, human-readable form.")
    parser.add_argument("netlist_file", metavar="NETLIST-FILE",
                         help="a .net file already exported by kicad-cli "
                              "('kicad-cli sch export netlist --format "
                              "kicadsexpr -o FILE.net SCHEMATIC.kicad_sch'; "
                              "this program does not invoke kicad-cli "
                              "itself -- ppkicad_layout(1), which writes a "
                              "new schematic from one, does)")
    parser.add_argument("--version", action="version",
                         version=f"%(prog)s {_version()}")
    parser.add_argument("--debug", action="store_true",
                         help="also print each net member's own real pin "
                              "name and KiCad electrical pin type, where "
                              "known (pin_names/pin_types -- see netlist.py's "
                              "own Netlist docstring)")
    parser.add_argument("--quiet", action="store_true",
                         help="suppress the leading component/net-count "
                              "summary line; print only the component and "
                              "net listings themselves")
    args = parser.parse_args(argv)

    try:
        with open(args.netlist_file) as f:
            nl = load_netlist(f.read())
    except OSError as e:
        print(f"ppnetlist: {args.netlist_file}: {e.strerror}", file=sys.stderr)
        raise SystemExit(1)
    except ValueError as e:
        print(f"ppnetlist: {args.netlist_file}: {e}", file=sys.stderr)
        raise SystemExit(1)

    if not args.quiet:
        print(f"{len(nl.components)} components, {len(nl.nets)} nets")
    for ref in nl.refs():
        c = nl.components[ref]
        print(f"  {ref}: {c.value}")
    for net in nl.nets:
        if args.debug:
            members = ", ".join(
                f"{r}.{p}"
                f"[{nl.pin_names.get((r, p), '?')}"
                f"/{nl.pin_types.get((r, p), '?')}]"
                for r, p in net.nodes)
        else:
            members = ", ".join(f"{r}.{p}" for r, p in net.nodes)
        print(f"  {net.name}: {members}")


if __name__ == "__main__":
    main()
